Page 1 of 2
Window handle from process handle?
Posted: Sun Dec 09, 2007 10:03 am
by Mistrel
I wrote this function to try and get a window handle from the process handle but it can't find any matching processes. Is there some subtle error in my code or is it my logic?
Code: Select all
Procedure EnumWindowsProc(hWnd,lParam)
GetWindowThreadProcessId_(hWnd,@lpProc)
If lpProc=PeekL(lParam) ; process passed to EnumWindows is process found at this hwnd
PokeL(lParam,hWnd) ; set ptr to hwnd
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
Procedure GetProcHwnd(lpProc)
ptr=lpProc
Repeat : Until EnumWindows_(@EnumWindowsProc(),@ptr)
If ptr=lpProc ; if no handle is returned no matching process was found
ProcedureReturn 0
EndIf
; some form of GetWindow_() here for top-level window..
ProcedureReturn ptr
EndProcedure
program=RunProgram("Notepad.exe","","",#PB_Program_Open)
id=ProgramID(program)
hproc=OpenProcess_(#PROCESS_ALL_ACCESS,0,id)
Debug hproc
If Not GetProcHwnd(hproc)
Debug "GetProcHwnd failed."
Else
Debug "Success!"
EndIf
Re: Window handle from process handle?
Posted: Sun Dec 09, 2007 10:19 am
by PB
Here's my code that I've been using for years:
Code: Select all
; RunProgramEx by PB: Retrieves handle of an app's opened window.
Procedure RunProgramEx(file$,param$,dir$,showflag)
If Left(param$,1)<>" " : param$=" "+param$ : EndIf
Info.STARTUPINFO : Info\cb=SizeOf(STARTUPINFO) : Info\dwFlags=1
Info\wShowWindow=showflag : ProcessInfo.PROCESS_INFORMATION
If CreateProcess_(@file$,@param$,0,0,0,#NORMAL_PRIORITY_CLASS,0,@dir$,@Info,@ProcessInfo)
ProcessID=ProcessInfo\dwProcessId
Repeat
win=FindWindow_(0,0)
While win<>0
GetWindowThreadProcessId_(win,@pid)
If pid=ProcessID : WinHandle=win : Break : EndIf
win=GetWindow_(win,#GW_HWNDNEXT)
Wend
Until WinHandle
EndIf
ProcedureReturn WinHandle
EndProcedure
app$="c:\windows\notepad.exe" ; Full path needed!
hWnd=RunProgramEx(app$,"",GetPathPart(app$),#SW_SHOW)
Sleep_(2000) ; Give it a couple of seconds to open.
PostMessage_(hWnd,#WM_CLOSE,0,0) ; Now close it.
Posted: Sun Dec 09, 2007 10:34 am
by Mistrel
The notepad window does not close and I'm receiving an error when trying to use your code, PB. This is my debug output:
After adding these lines to the end:
Code: Select all
Procedure.s ShowAPIError(CheckReturnValue) ; forum code, unsure of original author
Buffer.s=Space (4096)
NumberOfChars=FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM,0,CheckReturnValue,0,Buffer.s,Len(Buffer.s),0)
ProcedureReturn Left(Buffer.s,NumberOfChars-2)
EndProcedure
Debug hWnd
Debug IsWindow_(hWnd)
Debug ShowAPIError(GetLastError_())
Getting the window to close has been very sporadic. Sometimes it will close and sometimes it won't. Sometimes it closes but IsWindow returns false. Other times IsWindow returns true but the window doesn't close.
This is all from the same source.
Re: Window handle from process handle?
Posted: Sun Dec 09, 2007 10:49 am
by PB
Hmm, this code has been 100% reliable for me for many years. Don't know
why it's failing for you. I've used it with Win98SE, Win2K and WinXP with no
problems. Even running it now, with your code added, always returns this:
Code: Select all
10683168
0
The operation completed successfully.
All I can suggest is try putting Delay(500) after the CreateProcess line, in
case a faster CPU than mine is doing something too fast. Or maybe it's due
to dual-processors or something. Don't know. Just guessing. Try the delay.
And ensure the correct full path for Notepad.exe is being used (looks like it
is though, as you said sometimes it starts but other times it doesn't).
Posted: Sun Dec 09, 2007 10:51 am
by Mistrel
This time the window did not close, IsWindow returned false, and ShowAPIError returned successful.
I tried to use this code to force it to close but I never get more than one output to the debug window and it's still hit or miss.
Code: Select all
Repeat
Debug SendMessage_(hWnd,#WM_CLOSE,0,0)
Until Not IsWindow(hWnd)
End
I tried uninstalling and reinstalling PB too.
I'm also concerned with this line of my code:
Code: Select all
OpenProcess_(#PROCESS_ALL_ACCESS,0,id)
Even though I pass a unique PID every time the function only returns either 1952 or 1956 as the process handle. This still occurs even if I pass a completely different file. How can this be accurate?
***
Upon further testing I found that adding this to your code will make the application close every time.
Code: Select all
Repeat
hWnd=FindWindow_("Notepad","Untitled - Notepad")
Until hWnd
So this is an issue with the speed of my computer.
Posted: Sun Dec 09, 2007 3:06 pm
by netmaestro
Repeat
hWnd=FindWindow_("Notepad","Untitled - Notepad")
Until hWnd
That's going to close it without any other code hehe. After you send the message, of course. Try this modification:
Code: Select all
Procedure EnumProc(hwnd, param)
*handle.LONG = param
*handle\l = hwnd
ProcedureReturn 0
EndProcedure
Procedure RunProgramEx(file$,param$,dir$,showflag)
If Left(param$,1)<>" " : param$=" "+param$ : EndIf
Info.STARTUPINFO : Info\cb=SizeOf(STARTUPINFO) : Info\dwFlags=1
Info\wShowWindow=showflag : ProcessInfo.PROCESS_INFORMATION
If CreateProcess_(@file$,@param$,0,0,0,#NORMAL_PRIORITY_CLASS,0,@dir$,@Info,@ProcessInfo)
ThreadID=ProcessInfo\dwThreadID
EndIf
ProcedureReturn ThreadID
EndProcedure
app$="c:\windows\notepad.exe" ; Full path needed!
ThreadID=RunProgramEx(app$,"",GetPathPart(app$),#SW_SHOW)
Sleep_(2000)
EnumThreadWindows_(ThreadId, @EnumProc(), @hWnd.l)
PostMessage_(hWnd,#WM_CLOSE,0,0) ; Now close it.
Posted: Mon Dec 10, 2007 9:10 am
by Mistrel
Here is an improvement to your method that does not rely upon a delay.
Code: Select all
Procedure EnumProc(hwnd, param)
*handle.LONG = param
*handle\l = hwnd
ProcedureReturn 0
EndProcedure
Procedure RunProgramEx(file$,param$,dir$,showflag)
If Left(param$,1)<>" " : param$=" "+param$ : EndIf
Info.STARTUPINFO : Info\cb=SizeOf(STARTUPINFO) : Info\dwFlags=1
Info\wShowWindow=showflag : ProcessInfo.PROCESS_INFORMATION
If CreateProcess_(@file$,@param$,0,0,0,#NORMAL_PRIORITY_CLASS,0,@dir$,@Info,@ProcessInfo)
ThreadID=ProcessInfo\dwThreadID
EndIf
ProcedureReturn ThreadID
EndProcedure
app$="c:\windows\notepad.exe" ; Full path needed!
ThreadID=RunProgramEx(app$,"",GetPathPart(app$),#SW_HIDE)
Repeat
EnumThreadWindows_(ThreadId, @EnumProc(), @hWnd.l)
Until ShowWindow_(hWnd,#SW_SHOW)
Debug hWnd
Debug SendMessage_(hWnd,#WM_CLOSE,0,0) ; Now close it.
Re: Window handle from process handle?
Posted: Mon Dec 10, 2007 10:01 am
by PB
Can somebody else confirm if my code works for them? Because I'd like to
know if it's indeed reliable or just a problem at Mistrel's end.
Posted: Mon Dec 10, 2007 10:17 am
by omit59
@PB,
works here ok, Windows XP, SP2
Timo
Posted: Mon Dec 10, 2007 12:20 pm
by PurePWNRER
I'd say Karma kicked in when he saw the wrapper this guy is writing

Posted: Mon Dec 10, 2007 9:11 pm
by Mistrel
Here is another slight variation.
Code: Select all
Procedure EnumProc(hwnd, param)
*handle.LONG = param
*handle\l = hwnd
ProcedureReturn 0
EndProcedure
Procedure RunProgramEx(file$,param$,dir$,showflag,*lpProcessInformation.PROCESS_INFORMATION)
If Left(param$,1)<>" " : param$=" "+param$ : EndIf
Info.STARTUPINFO : Info\cb=SizeOf(STARTUPINFO) : Info\dwFlags=1
Info\wShowWindow=showflag
If Not CreateProcess_(@file$,@param$,0,0,0,#NORMAL_PRIORITY_CLASS,0,@dir$,@Info,*lpProcessInformation)
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
app$="c:\windows\notepad.exe" ; Full path needed!
If Not RunProgramEx(app$,"",GetPathPart(app$),#SW_HIDE,@ProcessInfo.PROCESS_INFORMATION)
MessageRequester("Error","Failed to load process.")
End
EndIf
Repeat
EnumThreadWindows_(ProcessInfo\dwThreadID, @EnumProc(), @hWnd.l)
Until ShowWindow_(hWnd,#SW_SHOW)
Debug SendMessage_(hWnd,#WM_CLOSE,0,0) ; Now close it.
Re: Window handle from process handle?
Posted: Tue Dec 11, 2007 8:14 am
by kryptonn
PB wrote:Can somebody else confirm if my code works for them?
Very good works on my Win Xp.
Posted: Tue Dec 11, 2007 4:02 pm
by blueb
PB wrote:
Can somebody else confirm if my code works for them?
It works... but
not every time. It appears as if the PostMessage command loses the hWnd handle and does nothing. I tried to increase the time to 4 seconds and that made no difference.
Latest XP Pro on a Dual Core 6600
--blueb
Posted: Tue Dec 11, 2007 6:44 pm
by Alquerian
Can somebody else confirm if my code works for them?
It worked fine here as well.
I am running XP SP2
AMD Athlon 64 3000+
I think Mistrel is running a Core2 Duo 4350 (or something like that), I am not sure if the dual core has any impact on it.
Posted: Wed Dec 12, 2007 1:08 am
by SFSxOI
Something like this maybe? A few older things I collected from the forum a while back,
don't remember who did what but the credit goes to them. Might need to be updated a little for PB 4.10. Uses some API but you dont need the path or anything and have always been reliable for me.
Code: Select all
; will return the correct hWnd for a PID if the PiD only runs a single thread.
; for apps that run more then one thread will return the handle from the first thread belonging to the PiD
; which may not be the handle you want.
Procedure InstanceToWnd(target_pid.l)
;Find the first window
test_hwnd = FindWindow_(0,0)
While test_hwnd <> 0
;Check If the window isn't a child
If GetParent_(test_hwnd) = 0 ;Then
;Get the window's thread
test_thread_id = GetWindowThreadProcessId_(test_hwnd, @test_pid)
If test_pid = target_pid ;Then
InstanceToWnd = test_hwnd
Break ;Exit Do
EndIf
EndIf
;retrieve the Next window
test_hwnd = GetWindow_(test_hwnd, #GW_HWNDNEXT)
Wend
ProcedureReturn test_hwnd
EndProcedure
or if you got a name, or even a partial name, of the file you can simply find the window handle by name?
Code: Select all
Procedure FindPartWin(part$)
r=GetWindow_(GetDesktopWindow_(),#GW_CHILD)
Repeat
t$=Space(999) : GetWindowText_(r,t$,999)
If FindString(t$,part$,1)<>0 And IsWindowVisible_(r)=#True
w=r
Else
r=GetWindow_(r,#GW_HWNDNEXT)
EndIf
Until r=0 Or w<>0
ProcedureReturn w
EndProcedure
hWnd = FindPartWin("note") ; notepad used as example here, name is case sensitive i.e. "notepad" and not "Notepad"
Or...am i on the wrong track and the train already left the station?