Notifications
Clear all

[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!

6 Replies

Damn You !
it doesn’t even look like a hack , just brilliant

Edit

reset max while pFlow sets in a viewport

what does Edit do? which Edit is?

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

1 Reply
(@denist)
Joined: 2 years ago

Posts: 0

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