[Closed] Register Particle View as an extended viewport
this task was interested me just theoretically only. this is not a big deal to do it in max SDK.
but is it possible to do in MXS?
there is the result:
global User32Assembly
fn CreateUser32Assembly forceRecompile:on =
(
if forceRecompile or not iskindof ::User32Assembly dotnetobject or (::User32Assembly.GetType()).name != "Assembly" do
(
source = "using System;
"
source += "using System.Runtime.InteropServices;
"
source += "class User32
"
source += "{
"
source += " [DllImport(\"User32.DLL\", EntryPoint=\"GetWindowLong\")]
"
source += " public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 index);
"
source += " [DllImport(\"User32.DLL\", EntryPoint=\"SetWindowLong\")]
"
source += " public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 index, Int32 newVal);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"SetWindowPos\")]
"
source += " public static extern bool SetWindowPos(IntPtr hWnd, int hWndArg, int Left, int Top, int Width, int Height, int hWndFlags);
"
source += " [DllImport(\"user32.dll\", CharSet=CharSet.Auto)]
"
source += " public static extern IntPtr GetParent(IntPtr hWnd);
"
source += " [DllImport(\"user32.dll\")]
"
source += " public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"GetWindowRect\")]
"
source += " static extern bool GetWindowRect(IntPtr hWnd, out POS rect);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"GetClientRect\")]
"
source += " static extern bool GetClientRect(IntPtr hWnd, out POS rect);
"
source += " public struct POS
"
source += " {
"
source += " public int Left;
"
source += " public int Top;
"
source += " public int Right;
"
source += " public int Bottom;
"
source += " }
"
source += " public int[] GetWindowPosAndSize(IntPtr hWnd)
"
source += " {
"
source += " POS rect;
"
source += " if ( GetWindowRect(hWnd, out rect) )
"
source += " {
"
source += " return new int[] { rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top };
"
source += " }
"
source += " return null;
"
source += " }
"
source += " public int[] GetClientPosAndSize(IntPtr hWnd)
"
source += " {
"
source += " POS rect;
"
source += " if ( GetClientRect(hWnd, out rect) )
"
source += " {
"
source += " return new int[] { rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top };
"
source += " }
"
source += " return null;
"
source += " }
"
source += " [DllImport(\"user32.dll\")]
"
source += " static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
"
source += " public bool RedrawAllWindow(IntPtr hWnd, uint flags) { return RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, flags); }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
::User32Assembly = compilerResults.CompiledAssembly
)
::User32Assembly.CreateInstance "User32"
)
--if User32 == undefined do
global User32 = CreateUser32Assembly()
if (windows.getchildhwnd 0 "Particle View") == undefined do
(
HWND_BOTTOM = 0x1
HWND_TOP = 0x0
HWND_NOTOPMOST = -2
GWL_STYLE = -16
WS_BORDER = 0x00800000
WS_DLGFRAME = 0x00400000
WS_THICKFRAME = 0x00040000
SWP_NOSIZE = 0x0001
SWP_NOMOVE = 0x0002
SWP_NOZORDER = 0x0004
rollout owner_dialog "Extended Particle View"
(
local child, owner
fn resizeChildWindow flag:SWP_NOZORDER = if owner != undefined and child != undefined do
(
local vsh = 2
local cs = ::User32.GetClientPosAndSize owner
::User32.SetWindowPos child 0 0 2 cs[3] (cs[4]-vsh) flag
::User32.RedrawAllWindow child 0x185
::User32.RedrawAllWindow child 0x185
)
on owner_dialog resized p do resizeChildWindow flag:(SWP_NOZORDER+SWP_NOMOVE)
)
vv = ParticleFlow.openParticleView()
hwnd = (windows.getchildhwnd 0 "Particle View")[1]
hwnd = dotnetobject "IntPtr" hwnd
pv = ::User32.GetWindowPosAndSize hwnd
createdialog owner_dialog 0 0 pv[1] pv[2] \
style:#(#style_sysmenu, #style_maximizebox, #style_minimizebox, #style_border, #style_titlebar, #style_resizing)
main = (windows.getchildhwnd 0 "Extended Particle View")[1]
main = dotnetobject "IntPtr" main
::User32.SetWindowPos main 0 pv[1] pv[2] pv[3] pv[4] 0
f = ::User32.GetWindowLong hwnd GWL_STYLE
f = bit.xor f (WS_BORDER+WS_DLGFRAME+WS_THICKFRAME)
::User32.SetWindowLong hwnd GWL_STYLE f
::User32.SetParent hwnd main
owner_dialog.child = hwnd
owner_dialog.owner = main
owner_dialog.resizeChildWindow()
registerViewWindow owner_dialog
)
Warning!!! Use it at YOUR OWN RISK. I didn’t deeply test Particle View functionality, and I don’t suppose to!
Damn You !
it doesn’t even look like a hack , just brilliant
Edit
reset max while pFlow sets in a viewport
the edit means … it looks like a hack if you reset max while pflow sets in a viewport
there is no editing for that code description , it is still brilliant
honestly … i didn’t think it is possible to do that
i know about it. there are some workarounds… use callbacks (reset, new, … , etc.) for example. but i’m looking for more elegant solution.
Thanks a lot for the posts guys. And Denis Thanks a lot for sharing the code :bowdown: it works perfectly, amazing job!.. (i though i will post this before i started digesting the code )
I spend a weekend doing research on this, i wrote an app in vb 2008 .net to do this, I not only wanted to embed particle flow view but also any other window (like in maya you can embed internet explorer) that will be a very cool feature especially while i am reading tutorials from the internet explorer, although the app embeds any window in any viewport the window embed looses focus for ever infact the window is killed as i am using the setparent api to make the target hwnd a child of the viewport and i have no idea how to access it. and the only way to kill the target windows process is by going into the task manager > process tab and doing end process. heres the messy code:
a few disclaimers in place : first of this code is not final its only a test code i wrote for myself… if you are going to run this code make sure notepad is on and its title bar says “untitled – notepad” bleh i could have used shell in the code but as i said its not final code and its full of bugs at the moment, I was thinking of putting this code in a maxscript function and then making it a callback function for the registerRedrawViewsCallback till denis said
this is not a big deal to do it in max SDK.
Public Class Pflow_Viewport
Private Sub Pflow_Viewport_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim my_style As Long
Dim th_style As Long
Target_hwnd = FindWindow(vbNullString, "Untitled - Notepad")
my_style = WS_BORDER Or WS_CHILD Or WS_DISABLED Or WS_DLGFRAME Or WS_POPUP Or WS_THICKFRAME
th_style = GetWindowLong(Target_hwnd, GWL_STYLE)
my_style = th_style Xor my_style
SetWindowLong(Target_hwnd, GWL_STYLE, my_style)
Dim my_proc As Process = New Process
Dim all_procs() As Process
Dim hwnd_title As String
Dim hwnd_handle As Long
Dim i As Integer
all_procs = my_proc.GetProcesses()
For i = 1 To UBound(all_procs)
If StrComp(all_procs(i).ProcessName, "3dsmax") = 0 Then
hwnd_title = all_procs(i).MainWindowTitle()
hwnd_handle = all_procs(i).MainWindowHandle()
child_count = 0
EnumChildWindows(hwnd_handle, AddressOf enumerate_childern, 0)
MsgBox(child_count.ToString)
End If
Next
End Sub
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
End Sub
End Class
heres the module for the api:
Imports System.Runtime.InteropServices
Imports System.Text
Module Win32_Api
Public child_count As Integer
Public Const GWL_STYLE = (-16)
Public Target_hwnd As Long
Public WS_BORDER = &H800000
Public WS_DLGFRAME = &H400000
Public WS_THICKFRAME = &H40000
Public WS_POPUP = &H80000000
Public WS_CHILD = &H40000000
Public GWL_HWNDPARENT = (-8)
Public Const SWP_NOMOVE = 2
Public Const SWP_NOSIZE = 1
Public Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
Public Const HWND_TOPMOST = -1
Public Const HWND_NOTOPMOST = -2
Public WS_DISABLED = &H8000000
Public Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
Public Delegate Function EnumWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function FindWindow( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Public Function EnumChildWindows(ByVal hWndParent As System.IntPtr, ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As Integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Public Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
End Function
<DllImport("user32.dll")> _
Public Function SetWindowLong( _
ByVal hWnd As IntPtr, _
ByVal nIndex As Integer, _
ByVal dwNewLong As IntPtr) As Integer
End Function
<DllImport("user32.dll")> _
Public Function MoveWindow(ByVal hWnd As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal bRepaint As Boolean) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Function GetWindowLong( _
ByVal hWnd As IntPtr, _
ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As UInt32) As Boolean
End Function
Public Function enumerate_childern(ByVal hwnd As Long, ByVal lparam As Long)
Dim child_title_length As Integer
Dim child_rectangle As RECT
child_title_length = GetWindowTextLength(hwnd)
If child_title_length > 0 Then
Dim child_title_string As New System.Text.StringBuilder("", child_title_length + 1)
GetWindowText(hwnd, child_title_string, child_title_string.Capacity)
Pflow_Viewport.ListBox1.Items.Add(child_title_string.ToString)
If StrComp(child_title_string.ToString, "Front") = 0 Then
GetWindowRect(hwnd, child_rectangle)
'MoveWindow(Target_hwnd, child_rectangle.Left, child_rectangle.Top, (child_rectangle.Right - child_rectangle.Left), (child_rectangle.Bottom - child_rectangle.Top), True)
MoveWindow(Target_hwnd, 0, 0, (child_rectangle.Right - child_rectangle.Left), (child_rectangle.Bottom - child_rectangle.Top), True)
SetParent(Target_hwnd, hwnd)
'SetWindowPos(Target_hwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS)
'SetWindowLong(Target_hwnd, GWL_HWNDPARENT, hwnd)
End If
End If
child_count = child_count + 1
enumerate_childern = True
End Function
End Module
However i read the sdk and found this
class TestViewWindow : public ViewWindow
{MCHAR *GetName() { return _M("TestViewWindow"); } HWND CreateViewWindow([b]HWND hParent[/b], int x, int y, int w, int h); void DestroyViewWindow(HWND hWnd); }; HWND TestViewWindow::CreateViewWindow(HWND hParent, int x, int y, int w, int h) { return CreateWindow("button", "Test Button", WS_VISIBLE | WS_CHILD, x, y, w, h, hParent, NULL, (HINSTANCE)GetWindowLong(hParent, GWL_HINSTANCE), NULL); } void TestViewWindow::DestroyViewWindow(HWND hWnd) { DestroyWindow(hWnd); } static TestViewWindow tvw;
do we have to implement the view window class to create and extended view and if so can hwnd parent be handle to any windows, But what if its an existing window then i dont want to call a createwindow. [b]In short how do i this with the sdk[/b]
forgive me for the noobiness i am new to sdk although i have done a little bit of api in the old days (visual basic 6)
once again thanks for sharing the code
any help is appreciated thanks :)
{BURP!} (excuse me!) that was some heavy code to digest
anyways i made a few modifications to the code and i can now embed any window of my liking as an extended view port cheers infact i am posting this from inside of 3d max
here’s the code :
global User32Assembly
fn CreateUser32Assembly forceRecompile:on =
(
if forceRecompile or not iskindof ::User32Assembly dotnetobject or (::User32Assembly.GetType()).name != "Assembly" do
(
source = "using System;
"
source += "using System.Runtime.InteropServices;
"
source += "class User32
"
source += "{
"
source += " [DllImport(\"User32.DLL\", EntryPoint=\"GetWindowLong\")]
"
source += " public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 index);
"
source += "[DllImport(\"user32.dll\", EntryPoint=\"FindWindow\", SetLastError = true)]
"
source += " public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
"
source += " [DllImport(\"User32.DLL\", EntryPoint=\"SetWindowLong\")]
"
source += " public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 index, Int32 newVal);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"SetWindowPos\")]
"
source += " public static extern bool SetWindowPos(IntPtr hWnd, int hWndArg, int Left, int Top, int Width, int Height, int hWndFlags);
"
source += " [DllImport(\"user32.dll\", CharSet=CharSet.Auto)]
"
source += " public static extern IntPtr GetParent(IntPtr hWnd);
"
source += " [DllImport(\"user32.dll\")]
"
source += " public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"GetWindowRect\")]
"
source += " static extern bool GetWindowRect(IntPtr hWnd, out POS rect);
"
source += " [DllImport(\"user32.dll\", EntryPoint=\"GetClientRect\")]
"
source += " static extern bool GetClientRect(IntPtr hWnd, out POS rect);
"
source += " public struct POS
"
source += " {
"
source += " public int Left;
"
source += " public int Top;
"
source += " public int Right;
"
source += " public int Bottom;
"
source += " }
"
source += " public int[] GetWindowPosAndSize(IntPtr hWnd)
"
source += " {
"
source += " POS rect;
"
source += " if ( GetWindowRect(hWnd, out rect) )
"
source += " {
"
source += " return new int[] { rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top };
"
source += " }
"
source += " return null;
"
source += " }
"
source += " public int[] GetClientPosAndSize(IntPtr hWnd)
"
source += " {
"
source += " POS rect;
"
source += " if ( GetClientRect(hWnd, out rect) )
"
source += " {
"
source += " return new int[] { rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top };
"
source += " }
"
source += " return null;
"
source += " }
"
source += " [DllImport(\"user32.dll\")]
"
source += " static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
"
source += " public bool RedrawAllWindow(IntPtr hWnd, uint flags) { return RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, flags); }
"
source += "}
"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
::User32Assembly = compilerResults.CompiledAssembly
)
::User32Assembly.CreateInstance "User32"
)
--if User32 == undefined do
global User32 = CreateUser32Assembly()
if (windows.getchildhwnd 0 "Particle View") == undefined do
(
HWND_BOTTOM = 0x1
HWND_TOP = 0x0
HWND_NOTOPMOST = -2
GWL_STYLE = -16
WS_BORDER = 0x00800000
WS_DLGFRAME = 0x00400000
WS_THICKFRAME = 0x00040000
SWP_NOSIZE = 0x0001
SWP_NOMOVE = 0x0002
SWP_NOZORDER = 0x0004
rollout owner_dialog "Extended Particle View"
(
local child, owner
fn resizeChildWindow flag:SWP_NOZORDER = if owner != undefined and child != undefined do
(
local vsh = 2
local cs = ::User32.GetClientPosAndSize owner
::User32.SetWindowPos child 0 0 2 cs[3] (cs[4]-vsh) flag
::User32.RedrawAllWindow child 0x185
::User32.RedrawAllWindow child 0x185
)
on owner_dialog resized p do resizeChildWindow flag:(SWP_NOZORDER+SWP_NOMOVE)
)
vv = ParticleFlow.openParticleView()
nullptr = dotnetobject "IntPtr" 0
hwnd = ::User32.FindWindowByCaption nullptr "CGTalk - 3dsMax SDK and MaxScript - Mozilla Firefox"
hwnd = dotnetobject "IntPtr" hwnd
pv = ::User32.GetWindowPosAndSize hwnd
createdialog owner_dialog 0 0 pv[1] pv[2] \
style:#(#style_sysmenu, #style_maximizebox, #style_minimizebox, #style_border, #style_titlebar, #style_resizing)
main = (windows.getchildhwnd 0 "Extended Particle View")[1]
main = dotnetobject "IntPtr" main
::User32.SetWindowPos main 0 pv[1] pv[2] pv[3] pv[4] 0
f = ::User32.GetWindowLong hwnd GWL_STYLE
f = bit.xor f (WS_BORDER+WS_DLGFRAME+WS_THICKFRAME)
::User32.SetWindowLong hwnd GWL_STYLE f
::User32.SetParent hwnd main
owner_dialog.child = hwnd
owner_dialog.owner = main
owner_dialog.resizeChildWindow()
registerViewWindow owner_dialog
)
here’s a snap shot :
and once again Thanks for the code Denis
ps: i think the redrawing function should be called more often, as i minimize maximize windows over the extended viewport which contains the rollout its left with a grey color showing the rollout background infact it would be best to place the redraw call in theregisterRedrawViewsCallback