Extend RunProgram : retrieve handle of opened window

Share your advanced PureBasic knowledge/code with the community.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Extend RunProgram : retrieve handle of opened window

Post by eddy »

Code updated for 5.20+

Example :

Code: Select all

; /////////////////////////////
; System Directory
; /////////////////////////////

Procedure.s GetSystemDir()
   systemdir$=Space(255)
   lg = GetSystemDirectory_(systemdir$, 255)
   systemdir$=Left(systemdir$,lg)
   ProcedureReturn systemdir$
EndProcedure 

command$=GetSystemDir()+"\calc.exe"
app=RunProgramEx(command$,"",GetPathPart(command$), #SW_NORMAL)
ShowWindow_(app, #SW_MINIMIZE)
Program :

Code: Select all

; ///////////////////////
; Run Program Ex
; ///////////////////////

Procedure RunProgramEx(Filename.s, Parameter.s, Directory.s, ShowFlag)

   Info.STARTUPINFO
   Info\cb          =SizeOf(STARTUPINFO)   
   Info\dwFlags     =1                    ;#STARTF_USESHOWWINDOW
   Info\wShowWindow =ShowFlag
   
   ProcessInfo.PROCESS_INFORMATION   
   ProcessPriority=$20                    ;NORMAL_PRIORITY
     
  ;Create a window and retrieve its process
  If CreateProcess_(@Filename, @Parameter, 0, 0, 0, ProcessPriority, 0, @Directory, @Info, @ProcessInfo)

      ;Process Values     
      ProcessID =ProcessInfo\dwProcessId

      ;Find Window Handle of Process
      Repeat
         win=FindWindow_(0,0)
         While win<>0 And quit=0
            GetWindowThreadProcessId_(win, @pid)
            If pid=ProcessID
               WinHandle=win
               quit=1
            EndIf
            win=GetWindow_(win, #GW_HWNDNEXT)         
         Wend
      Until WinHandle
   EndIf
   
   ;Retrieve Window Handle
   ProcedureReturn WinHandle
EndProcedure 
 
Tip BrainStorming : viewtopic.php?p=29189#29189

Special Thanks to Freak & PB :) :D
Last edited by eddy on Mon Jun 30, 2003 1:30 pm, edited 1 time in total.
User avatar
eddy
Addict
Addict
Posts: 1479
Joined: Mon May 26, 2003 3:07 pm
Location: Nantes

Post by eddy »

Example : create a Calculator Tool Window

Code: Select all

   app=RunProgramEx(GetSystemDir()+"\calc.exe","",GetSystemDir()+"\",#SW_SHOWNORMAL) 
   ExStyle.l  =GetWindowLong_(app,#GWL_EXSTYLE)
   ExStyle = ExStyle | #WS_EX_TOOLWINDOW
   SetWindowLong_(app,#GWL_EXSTYLE, ExStyle) ;Tool Style
   SetWindowPos_(app,#HWND_TOPMOST,0,0,0,0,16|2|1)     ;Always on top  

PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: RunProgramEx : retrieve handle of opened window

Post by PB »

> command$=GetSystemDir()+"\calc.exe"

Note that Calc.exe is NOT located in the System folder on Win 9x or ME,
so the above code fails. Better to just use command$="calc.exe" so
that it runs on all versions of Windows.
Klonk
Enthusiast
Enthusiast
Posts: 173
Joined: Tue Jul 13, 2004 2:17 pm

Post by Klonk »

Just one issue when used this piece of code:
Add

Code: Select all

Delay(100)
directly after Repeat to give the application some time to start, alternatively

Code: Select all

WaitForInputIdle_(ProcessInfo\hProcess, 5000)
should also work to wait for the application.

So the code might look like (at least this works OK for me) and can be used with all files:

Code: Select all

Procedure RunProgramEx(filename$,parameter$,directory$)
  If Left(parameter$,1)<>" "
    parameter$=" "+parameter$
  EndIf
  Info.STARTUPINFO
  Info\cb=SizeOf(STARTUPINFO)
  Info\dwFlags=1
  Info\wShowWindow=#SW_SHOWNORMAL
  ProcessInfo.PROCESS_INFORMATION
  If UCase(GetExtensionPart(filename$))="EXE"
    If CreateProcess_(@filename$,@parameter$,0,0,0,#NORMAL_PRIORITY_CLASS ,0,@directory$,@Info,@ProcessInfo)
      ProcessID=ProcessInfo\dwProcessId
      WaitForInputIdle_(ProcessInfo\hProcess, 5000) ;wait for application to accept input
      count=0
      Repeat
        Delay(100) ;avoid hanging of windows during start of application while searching for the window
        count=count + 1 ;security counter to avoid hanging
        win=FindWindow_(0,0)
        While win<>0
          GetWindowThreadProcessId_(win,@pid.l)
          If pid=ProcessID
            WinHandle=win
            Break
          EndIf
          win=GetWindow_(win,#GW_HWNDNEXT)
        Wend
      Until WinHandle Or (count=50) ;wait up to 5 seconds for window to occur
    EndIf
  Else
    RunProgram(filename$,parameter$,directory$)
    WinHandle = 0 ;just for security
  EndIf
  ProcedureReturn WinHandle
EndProcedure
Bye Karl
Klonk
Enthusiast
Enthusiast
Posts: 173
Joined: Tue Jul 13, 2004 2:17 pm

Post by Klonk »

I have simply one problem with the above code:

I use

Code: Select all

PostMessage_(Winhandle,#WM_CLOSE,0,0)
to exit and close the application.

This works fine with Win2k, But does not work on some applications at WinXP.
Does anyone have an explanation for that?

I tried also #WM_QUIT but that didn't also work. Any Ideas/hints?
Bye Karl
Klonk
Enthusiast
Enthusiast
Posts: 173
Joined: Tue Jul 13, 2004 2:17 pm

Post by Klonk »

Sorry, found it myself:
The above sequence for saving the window handle should be changed the following way:

Code: Select all

        While win<>0
          GetWindowThreadProcessId_(win,@pid.l)
          If pid=ProcessID
            If GetParent_(win)=0 ;save handle only if not a child window
              WinHandle=win
              Break
            EndIf
          EndIf
          win=GetWindow_(win,#GW_HWNDNEXT) ;check next window
        Wend
Because with that only the handles of parent windows are returned. Which has to be done with WinXP (Don'r know why, but with that it works as it is intended.
Bye Karl
Post Reply