Archive: Find process associated with window


Find process associated with window
  Is there any way in NSIS to find out the ProcessID (and/or ProcessName) associated with a particular window returned by FindWindow?


If you use the system plugin to call FindWindowEx you will get a handle to your window and then you can use GetWindowThreadProcessId to get the thread and/or process ID that created the window or GetWindowModuleFilename to get the filename of the process that created the window.
Hope this helps
CF


Thanks CancerFace,

I've tried to do that with some success, however, I'm getting stuck with something weird.

The following section loops through all the windows, and lists the window title, window handle, class name, filename, thread id and process id.
Title, handle and thread id are working perfectly.
For some reason I fail to understand though, I get no process id (it returns 0 every time) and the filename is rather random (most of the time it returns the filename of the installer itself).

Section "ListWindowsInfo"


FileOpen $8 "c:\temp\windowslist.txt" "w"
SetPluginUnload alwaysoff
System
::Get "(i.r1, i) iss"
Pop $R0
System::Call "user32::EnumWindows(k R0, i) i.s"

loop:
Pop $0
StrCmp$0 "callback1" 0 done
System::Call "user32::GetWindowText(ir1,t.r2,i${NSIS_MAX_STRLEN})"
System::Call "user32::GetClassName(ir1,t.r3,i${NSIS_MAX_STRLEN})"
System::Call "user32::GetWindowModuleFileName(ir1,t.r6,i${NSIS_MAX_STRLEN})"
System::Call "user32::GetWindowThreadProcessId(ir1,i.r7) i .r9"

IntFmt $4 "0x%X" $1
FileWrite$8 "$1 / $4 - ***91;$3***93; $2$\r$\n"
FileWrite $8 " $1 -->> FileName: $6$\r$\n"
FileWrite $8 " $1 -->> Thread: $9$\r$\n"
FileWrite $8 " $1 -->> Process: $7$\r$\n"

Push 1 # callback's return value
System::Call "$R0"
Goto loop

done:
SetPluginUnload manual

System::Free $R0
FileClose$8

SectionEnd
>
I'm a bit lost...

Strange, although the threads are picked it seems that the process is always 0. However the filename is not always the name of the NSIS script, there are some instances of comctl32.dll. I have no clue why!
The only thing I managed to dig out is this:

GetWindowModuleFileName returns the name of a EXE or DLL that created a window. Be forewarned though; this API only works on HWNDs created by the process that called the API. This means it’s only of use for windows that your program created or within a systemwide hook procedure.
and I wonder if this is the reason for the above behavior

You may want to try CreateToolhelp32Snapshot to get a snapshot of all the processes then use Module32First/Module32Next to get the filename and path of the module associated with a certain window, based on its process ID ...

I know, it is too complicated :)

CF

Originally posted by CancerFace
Strange, although the threads are picked it seems that the process is always 0.
I found that one, I should have used a pointer:

System::Call "user32::GetWindowThreadProcessId(ir1,*i.r7) i .r9" 

However the filename is not always the name of the NSIS script, there are some instances of comctl32.dll. I have no clue why!
The only thing I managed to dig out is this:
and I wonder if this is the reason for the above behavior
I read the same thing and will have to agree with you on that one.

You can use GetModuleFileNameEx to get the executable name for a process other than yours. This could explain why you keep getting the installer's executable name. This function is only supported on Windows NT or later and you need the PSAPI library (see below).

The ToolHelper functions are only viable under Windows 98/95. They were removed in NT and later, replaced with PSAPI functions/libraries. NT does not have the PSAPI library included by default, you can copy the PSAPI.DLL from Windows XP into a directory on the path and use it if you want, otherwise grab the installer from Microsoft.

I am not very familiar with the thread-to-window association stuff, sorry I can't help with that yet.

Duncan


That's a good idea Mr Inches :)
I think this should work:


Section "ListWindowsInfo"

FileOpen $8 "c:\tempwindowslist.txt" "w"
SetPluginUnload alwaysoff
System::Get "(i.r1, i) iss"
Pop $R0
System::Call "user32::EnumWindows(k R0, i) i.s"

loop:
Pop $0
StrCmp $0 "callback1" 0 done
System::Call 'user32::GetWindowText(ir1,t.r2,i${NSIS_MAX_STRLEN})i.R6'
System::Call 'user32::GetClassName(ir1,t.r3,i${NSIS_MAX_STRLEN})i.R6'
System::Call 'user32::GetWindowThreadProcessId(ir1,*i.r7)i.r9'
System::Call 'kernel32::OpenProcess(i 0x1F0FFF,i0,ir7)i.R9'
System::Call 'Psapi::GetModuleFileNameExA(iR9,in,t.R8,i${NSIS_MAX_STRLEN})i.R6'
System::Call 'kernel32::CloseHandle(iR9)i.R6'
IntFmt $4 "0x%X" $1
FileWrite $8 "$1 / $4 - [$3] $2$\r$\n"
FileWrite $8 " $1 -->> Thread: $9$\r$\n"
FileWrite $8 " $1 -->> Process: $7$\r$\n"
FileWrite $8 " $1 -->> FileName: $R8$\r$\n"


Push 1 # callback's return value
System::Call "$R0"
Goto loop

done:
SetPluginUnload manual

System::Free $R0
FileClose $8

You get the window name that you're after, the Process ID of the process that created it and the filename of the executable responsible for that process ...
CF