NetRenderAutomation for 2019?

Hi,
I use NetRenderAutomation script for 3DSmax 2015 by Gravey https://forums.cgsociety.org/t/how-to-net-render-with-dependencies/1558453. The script works well, but since the 2018/2019 version, I have a problem.

What has changed since the 2015 version?
Would anyone have a solution?
Can this come from the 64bits version?

Thx :)

struct NetRenderAutomation
(
	fn CheckGlobal glob string_pattern =
	(
		glob == undefined OR
		NOT isKindOf glob dotnetobject OR
		NOT matchpattern ( glob.ToString() ) pattern:string_pattern
	),
 
	fn CreatePInvokeAssembly forceRecompile:false =
	(
		if forceRecompile OR
			CheckGlobal ::PInvokeAssembly "*Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" OR
			CheckGlobal ::User32 "PInvoke.User32" do
		(
			source = ""
			append source "using System;\n"
			append source "using System.Runtime.InteropServices;\n"
			append source "namespace PInvoke\n"
			append source "{\n" -- open namespace PInvoke
 
			append source "public class User32\n"
			append source "{\n" -- open class
			append source "		[DllImport(\"user32.dll\")]\n"
			append source "		public static extern bool SetDlgItemText(IntPtr hDlg, int nIDDlgItem, string lpString);\n"
			append source "		[DllImport(\"user32.dll\", CharSet = CharSet.Auto)]\n"
			append source "		public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);\n"
			append source "}\n" -- end class
 
			append source "[StructLayout(LayoutKind.Sequential)]\n"
			append source "public struct LVITEM\n"
			append source "{\n" -- open class
			append source "		public UInt32 mask;\n"
			append source "		public Int32 iItem;\n"
			append source "		public Int32 iSubItem;\n"
			append source "		public UInt32 state;\n"
			append source "		public UInt32 stateMask;\n"
			append source "		public IntPtr pszText;\n"
			append source "		public Int32 cchTextMax;\n"
			append source "		public Int32 iImage;\n"
			append source "		public Int32 lParam;\n"
			append source "}\n" -- end class
 
			append source "public class Memory\n"
			append source "{\n" -- open class
			append source "		public static unsafe IntPtr Alloc(int cb)\n"
			append source "		{\n" -- open method Alloc
			append source "			IntPtr data = Marshal.AllocHGlobal(cb);\n"
			append source "			byte* p = (byte*)data.ToPointer();\n"
			append source "			for (int i = 0; i < cb; ++i)\n"
			append source "			{\n" -- open for loop
			append source "				*p = 0; ++p;\n"
			append source "			}\n" -- close for loop
			append source "			return data;\n"
			append source "		}\n" -- close method Alloc
			append source "		public static void Free(IntPtr pointer)"
			append source "		{\n" -- open method Free
			append source "			Marshal.FreeHGlobal(pointer);\n"
			append source "		}\n" -- close method Free
			append source "		public static byte[] GetByteArray(IntPtr pointer, int count)"
			append source "		{\n" -- open method GetByteArray
			append source "			byte[] bytes = new byte[count];\n"
			append source "			Marshal.Copy(pointer, bytes, 0, count);\n"
			append source "			return bytes;\n"
			append source "		}\n" -- close method GetByteArray
			append source "}\n" -- end class
 
			append source "}\n" -- end namespace PInvoke
			csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
			compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
			compilerParams.ReferencedAssemblies.Add "System.dll"
			compilerParams.ReferencedAssemblies.Add "mscorlib.dll"
			compilerParams.CompilerOptions = "/unsafe"
			compilerParams.GenerateInMemory = on
			compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
 
			for i = 1 to compilerResults.Errors.count do
			(
				showall compilerResults.Errors.Item[i-1]
			)
 
			::PInvokeAssembly = compilerResults.CompiledAssembly
			::User32 = ::PInvokeAssembly.CreateInstance "PInvoke.User32"
		)
 
		::PInvokeAssembly
	),
	------------------------------------------------------------------------------------------------
	Memory, -- "PInvoke.Memory"
	IntPtr = dotnetclass "System.IntPtr",
	UInt32 = dotnetclass "System.UInt32",
	Activator = dotnetclass "System.Activator",
	GCHandle = dotnetclass "System.Runtime.InteropServices.GCHandle",
	GCHandleType = dotnetclass "System.Runtime.InteropServices.GCHandleType",
	Encoding = dotnetclass "System.Text.Encoding",
	StringClass = dotnetclass "System.String",
	------------------------------------------------------------------------------------------------
	LVM_FIRST			= 0x1000,
	LVM_GETITEMCOUNT	= LVM_FIRST + 4,
	LVM_GETITEMA		= LVM_FIRST + 5,
	LVM_GETITEMW		= LVM_FIRST + 75,
	LVM_GETITEM			= LVM_GETITEMW,
	LVM_SETITEMA		= LVM_FIRST + 6,
	LVM_SETITEMW		= LVM_FIRST + 76,
	LVM_SETITEM			= LVM_SETITEMW,
	------------------------------------------------------------------------------------------------
	LVIF_TEXT			= 0x0001,
	LVIF_STATE			= 0x0008,
	LVIF_MASK			= bit.OR LVIF_TEXT LVIF_STATE,
	------------------------------------------------------------------------------------------------
	LVIS_SELECTED		= 0x0002,
	------------------------------------------------------------------------------------------------
	LISTBOX_BASE		= 383,
	LB_SETSEL			= LISTBOX_BASE +  6,
	LB_GETTEXT			= LISTBOX_BASE + 10,
	LB_GETCOUNT			= LISTBOX_BASE + 12,
	LB_ERR				= -1,
	------------------------------------------------------------------------------------------------
 
	manager_name = undefined,
	include_maps = false,
	suspended = false,
	specific_servers = #(),
	dependencies = #(),
	job_name = "job_name",
	job_priority = 50,
	critical = false,
 
	------------------------------------------------------------------------------------------------
 
	fn Alloc num_bytes =
	(
		ptr = Memory.Alloc num_bytes
		dotnetobject IntPtr ptr
	),
 
	------------------------------------------------------------------------------------------------
 
	fn ListView_SendMessage handle _message &item _wparam:0 =
	(
		pinned_item = GCHandle.Alloc item GCHandleType.Pinned
		item_ptr = dotnetobject IntPtr ( pinned_item.AddrOfPinnedObject() )
 
		h = dotnetobject IntPtr handle
		message = dotnetobject "System.UInt32" _message
		wparam = dotnetobject IntPtr _wparam
 
		result = 0
		try
		(
			result = ::User32.SendMessage h message wparam item_ptr
		)
		catch
		(
			format "-- h: %\n" h
			format "-- message: %\n" message
			format "-- wparam: %\n" wparam
			format "-- item_ptr: %\n" item_ptr
			format "-- item: %\n" item
			format "%\n" ( GetCurrentException() )
		)
 
		pinned_item.Free()
 
		result
	),
 
	fn ListView_GetNewItem item_index sub_item_index =
	(
		item			= ::PInvokeAssembly.CreateInstance "PInvoke.LVITEM"
		item.mask		= LVIF_MASK
		item.stateMask	= LVIS_SELECTED
		item.iItem		= item_index
		item.iSubItem	= sub_item_index
		item.cchTextMax = 256
 
		item
	),
 
	-- HWND handle, int item_index, int sub_item_index, out LVITEM &item
	fn ListView_GetItemText handle &item =
	(
		item.pszText = Alloc item.cchTextMax
 
		ListView_SendMessage handle LVM_GETITEM &item
	),
 
	fn ListView_SetItemSelected handle &item =
	(
		item.mask		= LVIF_STATE
		item.state		= LVIS_SELECTED
		item.stateMask	= LVIS_SELECTED
 
		ListView_SendMessage handle LVM_SETITEM &item
	),
 
	fn ListView_GetItemCount handle =
	(
		windows.SendMessage handle LVM_GETITEMCOUNT 0 0
	),
 
	------------------------------------------------------------------------------------------------
 
	fn ListBox_GetCount handle =
	(
		windows.SendMessage handle LB_GETCOUNT 0P 0P
	),
 
	fn ListBox_GetText handle item_index buffer_ptr =
	(
		try
		(
			h = dotnetobject IntPtr handle
			wparam = dotnetobject IntPtr item_index
			::User32.SendMessage h LB_GETTEXT wparam buffer_ptr
		)
		catch
		(
			format "-- i: % -- %\n" i ( GetCurrentException() )
			format "-- handle: %\n" handle
			format "-- h: %\n" h
			format "-- wparam: %\n" wparam
			format "-- buffer_ptr: %\n" buffer_ptr
			LB_ERR
		)
	),
 
	fn ListBox_GetAllItems handle =
	(
		buffer_size = 256
		buffer_ptr = Alloc buffer_size
 
		items = #()
		count = ListBox_GetCount handle
		for i = 0 to count-1 do
		(
			result = ListBox_GetText handle i buffer_ptr
			if result != LB_ERR do
			(
				bytes = Memory.GetByteArray buffer_ptr buffer_size
				item = Encoding.Unicode.GetString bytes
				append items item
			)
		)
		Memory.Free buffer_ptr
 
		items
	),
 
	fn ListBox_SelectItem handle item_index =
	(
		windows.SendMessage handle LB_SETSEL 1 item_index
	),
 
	------------------------------------------------------------------------------------------------
 
	mapped fn PrintElement handle numTabs:0 =
	(
		class_name = UIAccessor.GetWindowClassName handle
		class_name = dotnetobject StringClass ( class_name as string )
		window_text = UIAccessor.GetWindowText handle
		for i = 1 to numTabs do format "\t"
		format "%\"%\"\n" ( class_name.PadRight 75 ) window_text
	),
 
	fn PrintChildrenRecursive WindowHandle depth:0 =
	(
		children = windows.getChildrenHWND WindowHandle
		if children != undefined then
		(
			children = for h in children where h[1] != 0 collect h[1]
			for handle in children while NOT keyboard.escPressed do
			(
				PrintElement handle numTabs:depth
 
				PrintChildrenRecursive handle depth:(depth+1)
			)
		)
		OK
	),
 
	fn GetChildren handle =
	(
		children = windows.getChildrenHWND handle
		if children != undefined then for h in children where h[1] != 0 collect h[1] else #()
	),
 
	fn GetElementsByClass handle_arr class_string =
	(
		results = #()
		for handle in handle_arr do
		(
			className = UIAccessor.GetWindowClassName handle
			if matchpattern className pattern:class_string do appendIfUnique results handle
		)
		results
	),
 
	fn PressButtonByHandle handle =
	(
		BM_CLICK = 0xF5
		windows.SendMessage handle BM_CLICK 0 0
	),
 
	-- state: 0 unchecked, 1 checked, 2 indeterminate
	fn Checkbox_SetState handle state =
	(
		BM_SETCHECK = 0xF1
		windows.SendMessage handle BM_SETCHECK state 0
	),
 
	------------------------------------------------------------------------------------------------
 
	fn FindByName controls window_text_pattern =
	(
		notFound = true
		ret_handle = 0
		for handle in controls while notFound where matchpattern (UIAccessor.GetWindowText handle) pattern:window_text_pattern do
		(
			ret_handle = handle
			notFound = false
		)
		ret_handle
	),
 
	fn FindPressButton buttons window_text_pattern press_func:UIAccessor.PressButton =
	(
		handle = FindByName buttons window_text_pattern
		if handle != 0 then press_func handle
		else format "failed to find button control with text pattern: %\n" window_text_pattern
		handle
	),
 
	fn FindSetCheckboxState buttons window_text_pattern state =
	(
		handle = FindByName buttons window_text_pattern
		if handle != 0 then Checkbox_SetState handle state
		else format "failed to find checkbox control with text pattern: %\n" window_text_pattern
		handle
	),
 
	fn FindChangeText text_controls window_text_pattern new_text =
	(
		handle = FindByName text_controls window_text_pattern debug:true
		if handle != 0 then UIAccessor.SetWindowText handle new_text
		else format "failed to find text control with text pattern: %\n" window_text_pattern
		handle
	),
 
	------------------------------------------------------------------------------------------------
 
	fn DialogAutomation =
	(
		WindowHandle = DialogMonitorOPS.GetWindowHandle()
		WindowText = UIAccessor.GetWindowText WindowHandle
-- 		format "WindowText: %\n" WindowText
		if classof WindowText != string then true
		else
		(
			if matchpattern WindowText pattern:"*Network Job Assignment*" then
			(
-- 				format "--- Net Render Dialog : % ---\n" WindowHandle
 
				children = GetChildren WindowHandle
				buttons = GetElementsByClass children "Button"
				listViews = GetElementsByClass children "SysListView32"
				edits = GetElementsByClass children "Edit"
 
				if isKindOf manager_name string AND manager_name.count != 0 then
				(
					FindSetCheckboxState buttons "*Automatic*" 0
					UIAccessor.SetWindowText edits[5] manager_name
				)
				else FindSetCheckboxState buttons "*Automatic*" 1
 
				FindPressButton buttons "&Connect"
 
				FindSetCheckboxState buttons "*Notifications*" 0
				FindSetCheckboxState buttons "*Split Scan*" 0
				FindSetCheckboxState buttons "*Ignore Scene*" 0
				FindSetCheckboxState buttons "*Maps*" (if include_maps == true then 1 else 0)
				FindSetCheckboxState buttons "*Frame Window*" 1
				FindSetCheckboxState buttons "*Suspended*" (if suspended == true then 1 else 0)
 
				serverView = listViews[1]
 
				count = ListView_GetItemCount serverView
-- 				format "server count : %\n" count
 
				servers = #()
				for i = 0 to count-1 do
				(
					item = ListView_GetNewItem i 0
					result = ListView_GetItemText serverView &item
-- 					format "result : %\n" result
 
					serverName = ""
					text_ptr = dotnetobject IntPtr item.pszText
					try
					(
						bytes = Memory.GetByteArray text_ptr item.cchTextMax
-- 						with printAllElements on format "bytes: %\n" bytes
						serverName = Encoding.Unicode.GetString bytes
-- 						format "serverName: '%'\n" serverName
					)
					catch
					(
						format "i: % -- %\n" i ( GetCurrentException() )
					)
					Memory.Free text_ptr
 
					notFound = true
					for s in specific_servers while notFound where matchpattern serverName pattern:s do
					(
						ListView_SetItemSelected listviews[1] &item
						notFound = false
					)
				)
 
				for handle in buttons do
				(
					window_text = UIAccessor.GetWindowText handle
					if specific_servers.count > 0 AND matchpattern window_text pattern:"Use Sele&cted" then
					(
-- 						format "%\n" window_text
						UIAccessor.PressButton handle
					)
					else if specific_servers.count == 0 AND matchpattern window_text pattern:"&Use All Servers" then
					(
-- 						format "%\n" window_text
						UIAccessor.PressButton handle
					)
				)
 
				textControls = GetElementsByClass children "Edit"
				UIAccessor.SetWindowText textControls[1] job_name
 
				if critical == true then
					FindSetCheckboxState buttons "Cri&tical" 1
				else
				(
					FindSetCheckboxState buttons "Cri&tical" 0
					FindChangeText textControls "50" (job_priority as string)
				)
 
				if dependencies.count != 0 do FindPressButton buttons "&Dependencies"
 
				::SUBMIT_HANDLE = FindPressButton buttons "&Submit"
 
-- 				FindPressButton buttons "*Cancel*"
			)
			else if matchpattern WindowText pattern:"*Job Dependencies*" then
			(
				children = GetChildren WindowHandle
				listboxes = GetElementsByClass children "ListBox"
 
				items = ListBox_GetAllItems listboxes[1]
				for i = 1 to items.count do
				(
					for d in dependencies where matchpattern items[i] pattern:d do
						ListBox_SelectItem listboxes[1] (i-1)
				)
 
				buttons = GetElementsByClass children "Button"
				FindPressButton buttons "&Add"
				FindPressButton buttons "OK"
			)
			else if matchpattern WindowText pattern:"3ds max" then
			(
				children = GetChildren WindowHandle
				buttons = GetElementsByClass children "Button"
 
				FindPressButton buttons "&Yes"
			)
			else if matchpattern WindowText pattern:"*Output Overwrite Alert*" then
			(
				children = GetChildren WindowHandle
				buttons = GetElementsByClass children "Button"
 
				FindPressButton buttons "*Yes*"
			)
			else if matchpattern WindowText pattern:"Render Region" then
			(
				children = GetChildren WindowHandle
				buttons = GetElementsByClass children "Button"
 
				FindPressButton buttons "*OK*"
			)
		)
 
		true
	),
 
	------------------------------------------------------------------------------------------------
 
	fn SubmitNetRender =
	(
		RenderSceneDialog.Close()
 
		---------------------------------
 
		DialogMonitorOPS.Enabled = false
		DialogMonitorOPS.unRegisterNotification id:#NET_RENDER_DIALOG_AUTOMATION
 
		DialogMonitorOPS.RegisterNotification DialogAutomation id:#NET_RENDER_DIALOG_AUTOMATION
		DialogMonitorOPS.Enabled = true
 
		---------------------------------
 
		oldRendUseNet = rendUseNet
		rendUseNet = true
		max quick render
 
		---------------------------------
 
		DialogMonitorOPS.Enabled = false
		DialogMonitorOPS.unRegisterNotification id:#NET_RENDER_DIALOG_AUTOMATION
 
		---------------------------------
 
		rendUseNet = oldRendUseNet
 
		OK
	),
 
	on create do
	(
		CreatePInvokeAssembly forceRecompile:false
		Memory = ::PInvokeAssembly.CreateInstance "PInvoke.Memory"
 
		OK
	)
)
OK
 
-- clearListener()
nra = NetRenderAutomation()
-- nra.manager_name = "superbeast"
-- nra.include_maps = true
-- nra.suspended = true
-- nra.specific_servers = #( "render-07", "render-09" )
-- nra.dependencies = #( "Existing Job Name A", "Existing_Job_Name_B" )
nra.job_name = "NameObjCurrent"
--nra.job_priority = 53
-- nra.critical = true
nra.SubmitNetRender()
 
<code>