Set photometric light preset via maxscript?


#1

I want to be able to use maxscript to set a photometric light to one of it’s various preset values (i.e. D50, Halogen, HID Mercury, etc.) Is there any way to do this? I’ve started to learn a /little/ bit about dialog monitor/UI accessor stuff but this one is still a bit over my head.

I also think I read somewhere that because of the way dropdown lists are set up in Max, this can’t actually be done with them, but I don’t remember where it was so I can’t double check that. Can anyone confirm for me whether this is or is not possible, and if so how it can be done?


#2

I noticed that mousewheel can also change preset in this combobox. But it should be focused somehow…

(

global	WM_LBUTTONDOWN = 0x0201
global	WM_LBUTTONUP   = 0x0202
global  WM_KEYDOWN     = 0x0100
global  WM_KEYUP       = 0x0101

global _user32 = (

	source = ""
	source += "using System;
"
	source += "using System.Runtime.InteropServices;
"
	source += "class User32
"
	source += "{
"
	source += "	[DllImport(\"user32.dll\")]
"
	source += "	public static extern int PostMessage(Int32 hWnd, int wMsg, int wParam, int lParam);
"
	source += "}
"
  
	csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
	compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
					
	compilerParams.GenerateInMemory = on
	compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
	compilerResults.CompiledAssembly.CreateInstance "User32"
)



maxchilds = windows.getChildrenHWND #max
comboboxPtr = for i=1 to maxchilds.count where maxchilds[i][5] == "Intensity/Color/Attenuation" do exit with maxchilds[i+5][1]


_user32.postmessage comboboxPtr ::WM_LBUTTONDOWN 0 0
_user32.postmessage comboboxPtr ::WM_LBUTTONUP 0 0	


-- virtual keycodes
-- http://api.farmanager.com/ru/winapi/virtualkeycodes.html

for i=1 to 20 do (
	
	windows.processPostedMessages()
	format "%
" (windows.getHWNDData comboboxPtr)
	_user32.postmessage comboboxPtr ::WM_KEYDOWN 0x28 0
	_user32.postmessage comboboxPtr ::WM_KEYUP 0x28 0
	
)


)



#3

and here goes focusing that particular ui element

source = ""
source += "using System;
"
source += "using System.Runtime.InteropServices;
"
source += "using System.Text;
"
source += "class Win32
"
source += "{
"
source += "	[DllImport(\"user32.dll\")]
"
source += "	public static extern int SendMessage(Int32 hWnd, int wMsg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
"
source += "	[DllImport(\"user32\", CharSet = CharSet.Auto, SetLastError = true)]
"
source += "	public static extern Int32 SetFocus(Int32 hWnd);
"
source += "	[DllImport(\"user32\", CharSet = CharSet.Auto, SetLastError = true)]
"
source += "	internal static extern int GetWindowTextLength(Int32 hWnd);
"
source += "	[DllImport(\"user32\", CharSet = CharSet.Auto, SetLastError = true)]
"
source += "	internal static extern int GetWindowText(Int32 hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);
"
source += "	public static string GetWindowText(Int32 hWnd)
"
source += "	{
"
source += "		int length = GetWindowTextLength(hWnd);
"
source += "		StringBuilder sb = new StringBuilder(length + 1);
"
source += "		GetWindowText(hWnd, sb, sb.Capacity);
"
source += "		return sb.ToString();
"
source += "	}
"
source += "}
"

csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"

compilerParams.ReferencedAssemblies.Add "System.dll"
compilerParams.ReferencedAssemblies.Add "System.Drawing.dll"

compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)

Win32Assembly = compilerResults.CompiledAssembly
Win32Assembly.CreateInstance "Win32"


-- setting focus
Win32Assembly.setfocus comboboxPtr

all of the above based on samples from this forum. all the glory to it’s original authors


#4

The first sample works great, thanks so much for bringing it to my attention!

The second gives me the following error:

-- Error occurred in anonymous codeblock; filename: ; position: 1769; line: 38
-- Unknown property: "setFocus" in dotNetObject:System.Reflection.RuntimeAssembly

#5

I found out how to change that value :slight_smile:

_user32.postmessage comboboxPtr 0x014E index 0

#6

This stuff is beyond my comprehension at the moment, but I shall endeavor to understand it!


#7

:slight_smile: same boat


#8

Hm, actually, where did you find the first sample? It works but leaves the combobox in an open state when it’s done which is not preferable


#9

I would try windows.processPostedMessages or Uiaccessor.perssdefaultbutton then.
I’m not that much into winapi and all that stuff too


#10

everything is much more simple…

to set/get current selection to a combobox control you have to use messages CB_SETCURSEL/CB_GETCURSEL (google for more details).

the problem is that technically you can make your own presets with own names and you have to know all available preset names.

to solve it we need a help from c#

global ComboBoxOpsAssembly
fn CreateComboBoxOpsAssembly =
(
		
source = ""
source += "using System;
"
source += "using System.Text;
"
source += "using System.Runtime.InteropServices;
"
source += "public class ComboBoxOps
"
source += "{
"
source += "    [DllImport(\"user32.dll\")]
"
source += "    public static extern int SendMessage(IntPtr window, int message, int wParam, IntPtr lParam);
"
source += "    [DllImport(\"user32.dll\")]
"
source += "    public static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
"
source += "    public const int CB_GETCOUNT          = 0x0146;
"
source += "    public const int CB_GETCURSEL         = 0x0147;
"
source += "    public const int CB_GETLBTEXT         = 0x0148;
"
source += "    public const int CB_GETLBTEXTLEN      = 0x0149;
"
source += "    public const int CB_FINDSTRING        = 0x014C;
"
source += "    public const int CB_SELECTSTRING      = 0x014D;
"
source += "    public const int CB_SETCURSEL         = 0x014E;
"
source += " [DllImport(\"user32.dll\", CharSet = CharSet.Auto)]
"
source += " static extern int SendMessage(Int32 hWnd, int msg, int wParam, [Out] StringBuilder param);
"
source += " public static string GetText(Int32 hWnd, int msg, int wParam, int length)
"
source += " {
"
source += "    StringBuilder sb = new StringBuilder(length + 1);
"
source += "    SendMessage(hWnd, msg, wParam, sb);
"
source += "    return sb.ToString();
"
source += " }
"
source += "}
"

		csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"

		compilerParams.ReferencedAssemblies.Add("System.dll");

		compilerParams.GenerateInMemory = true
		compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
		
		ComboBoxOpsAssembly = compilerResults.CompiledAssembly
		ComboBoxOpsAssembly.CreateInstance "ComboBoxOps"
)
global ComboBoxOps = CreateComboBoxOpsAssembly()

so…

hwnd = <combobox hwnd>

-- num items 
num = ComboBoxOps.SendMessage hwnd ComboBoxOps.CB_GETCOUNT 0 0
-- length of n-th (0 based) item's text
textlen = ComboBoxOps.SendMessage hwnd ComboBoxOps.CB_GETLBTEXTLEN n 0
-- text of  n-th (0 based) item
ComboBoxOps.GetText hwnd ComboBoxOps.CB_GETLBTEXT 0 textlen

-- set n-th as current seelction
ComboBoxOps.SendMessage hwnd ComboBoxOps.CB_SETCURSEL n 0
-- get current seelction
n = ComboBoxOps.SendMessage hwnd ComboBoxOps.CB_GETCURSEL 0 0

#11


source += " public const int CB_GETCOUNT = 0x0146;
"
source += " public const int CB_GETCURSEL = 0x0147;
"
source += " public const int CB_GETLBTEXT = 0x0148;
"

I always wonder where do you get all that const definitions from?


#12

you should be able to extend the Ops easily and do another ‘interesting’ things :wink: enjoy!


#13

i remember them all … all windows messages … :slight_smile:

joke.

i do a googling as anyone else. for this particular codes for example -> “cb_ constants”


#14

Could you unpack

hwnd = <combobox hwnd>

for me?


#15

it’s a hwnd of the preset combobox control. there are several way to get it … for example:

if the modifier opened and a photometric light selected…

h = windows.getchildhwnd #max "Command Panel"
c = windows.getchildhwnd h[1] "Color"
c = uiaccessor.getnextwindow c[1]
c = uiaccessor.getnextwindow c
combobox_hwnd = uiaccessor.getnextwindow c   

#16

another way is to use its resource ID , which probably the same for all recent versions


#17

I adapted part of Serejah’s code to find the correct handle for me. Seems to be working for now!

Thanks to you both!


#18

Out of curiosity, are there any other ways to change a photometric light’s preset? (i.e. which do not require the light to be selected?)


#19

Actually, now that I have tried it in a practical test, it looks to me like the code is setting the dropdown list to the correct value, but the actual light color is not being updated…


#20

you probably have to send “ENTER” key to the combobox control to confirm changing. or send a message to dialog that the combobox was changed