[Closed] Maximizing another process from MXS
I’m trying to find a way to determine if a specific program is running and if so to maximize it / make it the active window. I imagine it might be possible via the DOSCommand or HiddenDOSCommand , I just don’t know how.
You can find examples of how to determin if 3dsmax is running. find the proper thread(it was a thread of how to kill 3dsmax.exe in taskmanager).
There are examples of how to minimize/maximize the Edit UVWs editor window.
Thanks!
DOScommand ended up being a dead end, mostly because it apparently can't return anything useful...
Seems I can minimize or maximize an app via "windows.SendMessage" (no idea about setting active / highest in windows z-order) so long as I have the windows handle (hWnd). Problem is the only way I know how to get that is via "windows.getchildhwnd", and that gets the hWnd using the title bar name instead of the process file name, which isn't very useful with programs that list their (constantly changing) version number on the title bar.
So, anyone knows of a way to get the hWnd of a running process via the process name (ie. notepad.exe , photoshop.exe , etc.) ?
system.diagnostics.process.getprocesses()
Find the process you need (by name, wildcard, whatever)
Process.MainWindowHandle
Thanks Denis, but I’m not really getting anything out of that method?
dotnetclass “System.Diagnostics.Process.GetProcesses()” always returns undefined.
If I use:
(dotnetclass “System.Diagnostics.Process”).GetProcessesByName “notepad”
the number of array items returned will be correct, but the actual contents are all the same string, that is:
#(dotNetObject:System.Diagnostics.Process)
So if I have several instances of the app running the returned array looks like this:
#(dotNetObject:System.Diagnostics.Process, dotNetObject:System.Diagnostics.Process, dotNetObject:System.Diagnostics.Process, dotNetObject:System.Diagnostics.Process)
This is actually my first time using .NET , so I’m probably just missing something basic.
You are very close but I’m unfortunately far from max right now.
dotnetclass “system.diagnostics.process” has to return you the class
After that ask getprocesses() . It returns list (array) of process objects. Print their names. Somehow you can find the one you need. And ask its main window hwnd if it has it
Could anyone help following this scenario please?
I really don’t know anything about DotNet, but tryind a little with:
With two ‘notepad’ open processes I get:
bb =(dotnetclass “System.Diagnostics.Process”).GetProcessesByName “notepad”
I get:
#(dotNetObject:System.Diagnostics.Process, dotNetObject:System.Diagnostics.Process)
Then, I don’t know if it’s usefull:
bb[1].id —-> I get 10304
bb[2].id —-> I get 8432
bb[1].mainwindowhandle —-> I get 723556P
bb[2].mainwindowhandle —-> I get 2493362P
bb[1].mainwindowtitle —-> I get “Untitled: Notepad”
bb[2].mainwindowtitle —-> I get “Untitled: Notepad”
bb[1].tostring() —-> I get “System.Diagnostics.Process (notepad)”
bb[2].tostring() —-> I get “System.Diagnostics.Process (notepad)”
Sorry but my knowledge of DotNet is zero.zero.
thanks. you’ve showed that the thing works
pp = (dotnetclass "System.Diagnostics.Process").GetProcesses()
showproperties pp[1] -- if there is any
pp[1].mainwindowhandle ---->?
using getprocessesbyname you have give exact name. my idea is to collect all processes and try to find one you need by matching a pattern.
Here is a simple function. You can customize it to fit your needs.
(
fn BringWindowToFront pName =
(
/* Get all running Processes */
processes = (dotnetclass "System.Diagnostics.Process").GetProcesses()
/*
Find the one that matches the given name.
In this example it needs to be the EXACT same name,
but you can change it to work with wildcards.
*/
handles = for j in processes where j.ProcessName == pName collect j.MainWindowHandle
/*
More than one Process with the same name.
You'll need another property to bring the correct one to the foreground
*/
if handles.count > 1 do return messagebox "More than one Process with the same name found."
/* No Process found. Display an Alert */
if handles.count == 0 do return messagebox ("Process not found.
\"" + pName +"\"")
/*
We got a matching Process. Bring it to the front.
There are several ways of doing this. This is the simplest I know.
*/
local WM_SYSCOMMAND = 0x0112
local SC_RESTORE = 0xF120
windows.sendmessage handles[1] WM_SYSCOMMAND SC_RESTORE 0
)
BringWindowToFront "notepad"
)
Thanks guys, problem solved
One small note in case anyone else wants to use this method to switch apps in the future: SC_RESTORE wont make the other app active unless it’s coming from a minimized state, so you need to run SC_MINIMIZE first just to be sure. ie.
windows.sendmessage handles[1] WM_SYSCOMMAND SC_MINIMIZE 0
windows.sendmessage handles[1] WM_SYSCOMMAND SC_RESTORE 0
it would be better to activate the window and probably send it on top.
(there is no max around to provide a working code. sorry)
Definitely yes. But you need to do some compiling and test it across all OS as some methods had been reported to not work well in all scenarios.
yes. you need compiling. i would try SetForegroundWindow, SetActiveWindow, and SetWindowPos with HWND_TOP flag.
I suppose SetForegroundWindow() should work alone, but in any case it will need to be a little more elaborated to do the work properly. The function should handle all the possible window states, like if it is normal, normal-minimized and maximized-minimized, among other things.
@Greg:
Here is a sample code if you are interested in some C# methods, but as you will see, it does not work if the windows is minimized.
(
fn CreateAssembly =
(
src = "using System;
"
src += "using System.Runtime.InteropServices;
"
src += "class User32
"
src += "{
"
src += "[DllImport(\"User32.dll\")]
"
src += "public static extern bool SetForegroundWindow(IntPtr hWnd);
"
src += "[DllImport(\"User32.dll\", SetLastError=true)]
"
src += "public static extern IntPtr SetActiveWindow(IntPtr hWnd);
"
src += "}
"
provider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
params = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
params.GenerateInMemory = true
result = provider.CompileAssemblyFromSource params #(src)
result.CompiledAssembly.CreateInstance "User32"
)
local assembly
fn BringWindowToFront pName =
(
processes = (dotnetclass "System.Diagnostics.Process").GetProcesses()
handles = for j in processes where j.ProcessName == pName collect j.MainWindowHandle
intptr = dotnetobject "System.IntPtr" handles[1]
if assembly == undefined do assembly = CreateAssembly()
assembly.SetForegroundWindow intptr
--assembly.SetActiveWindow intptr
)
BringWindowToFront "notepad"
)