Page 1 of 1

Automatic closing of application

Posted: Fri Jul 21, 2017 7:30 am
by Klonk
Hi everyone,

I wrote an application starter (starts other programs using RunProgram).

I wanted to include a feature that all opened applications will ber closed when closing the launcher.

The only way I found is the following (using the windowhandle)

The procedure starting a program:

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
      Delay(100)
      WaitForInputIdle_(ProcessInfo\hProcess, 30000) ;wait for application to accept input, wait maximum 30 seconds
      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
            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
      Until WinHandle Or (count=100) ;wait up to 10 seconds for window to occur
    EndIf
  Else
    RunProgram(filename$,parameter$,directory$)
    WinHandle = 0 ;just for security
  EndIf
  ProcedureReturn WinHandle
EndProcedure
Winhandle is defined as long

For closing the started application I do:

Code: Select all

               PostMessage_(WinHandle,#WM_CLOSE,0,0); close Window
The problem is: Sometimes it work, most of the time it does not.

Is anyone aware of some other possibility? Any ideas.

Thanks a million.

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 8:12 am
by Dude
Try this instead -- it's what I use for apps that don't obey #WM_CLOSE:

Code: Select all

PostMessage_(hWnd,#WM_SYSCOMMAND,#SC_CLOSE,0)

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 8:13 am
by Bisonte
Winhandle is defined as long
Use Integer for OS handles ! Ever. Also in x86 programs.

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 9:12 am
by Klonk
@Dude:

The result of Postmessage can be checked, right?

So the following should work?

Code: Select all

               result=PostMessage_(LaunchApp()\hWnd,#WM_CLOSE,0,0); close Window
               If result = false then
                 PostMessage_(LaunchApp()\hWnd,#WM_SYSCOMMAND,#SC_CLOSE,0); close window, 2nd try
               End If

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 9:33 am
by RSBasic
Please use SendMessage_().

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 10:14 am
by Klonk
Sorry for the maybe dumb question, but why sendmessage?

Sendmessage waits for the result, Postmessage not. Is this the reason?

If it does not wait I cannot look at the result?

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 10:16 am
by RSBasic
Klonk wrote:Sendmessage waits for the result, Postmessage not. Is this the reason?
Yes

Re: Automatic closing of application

Posted: Fri Jul 21, 2017 3:53 pm
by Lunasole
Well can also close with built-in function, but it is wrapper over TerminateProcess API. Closing this way works always (except very rare cases if process protected), but it also causes loss of unsaved data in launched programs.

Code: Select all

EnableExplicit

; run & kill process after 10s
Define hProgram = RunProgram("calc.exe", "", "", #PB_Program_Open)

Repeat
	Delay(10 * 1000)
	KillProgram(hProgram)
	CloseProgram(hProgram)
	Break
ForEver

Re: Automatic closing of application

Posted: Sat Jul 22, 2017 4:03 am
by Dude
Hi Klonk! I meant that I personally just use the #WM_SYSCOMMAND and #SC_CLOSE version instead of the other #WM_CLOSE version, as it seems to work every time compared to #WM_CLOSE not working with all windows. I haven't used #WM_CLOSE to close a window in 10 years, and never had a problem with #SC_CLOSE doing it. It's still an official way to send a close message.

From https://stackoverflow.com/questions/101 ... d-sc-close :

"WM_CLOSE is sent as a window message whenever the window is requested to be closed, by any means. SC_CLOSE is sent as a parameter of a WM_SYSCOMMAND message, when the user presses the Close button (or selects Close from the control menu of the window). Which one you listen for is determined by which action(s) you attempting to intercept/deal with."

So I've been using #SC_CLOSE without issue. For example, sending it to an unsaved Notepad window will still make Notepad prompt the user to save the file first, etc.

Here's some actual code from one of my apps, with my commentary on why I started using it:

Code: Select all

;PostMessage_(hWnd,#WM_CLOSE,0,0) ; Fails TOTALLY on admin windows. Avoid!
If PostMessage_(hWnd,#WM_SYSCOMMAND,#SC_CLOSE,0) ; Works on MOST admin windows.
  ; ...
EndIf

Re: Automatic closing of application

Posted: Sat Jul 22, 2017 1:24 pm
by Klonk
Ah, ok, many thanks...

Re: Automatic closing of application

Posted: Mon Jul 31, 2017 9:58 am
by Michael Vogel
Lunasole wrote:Well can also close with built-in function, but it is wrapper over TerminateProcess API. Closing this way works always (except very rare cases if process protected), but it also causes loss of unsaved data in launched programs.
I have some cases where I can't close a running program window, here's an example...

Code: Select all

Procedure RunCommand(command.s)

	Protected handle
	Protected timeout

	timeout=ElapsedMilliseconds()+1000

	handle=RunProgram("cmd.exe","/c "+command,GetTemporaryDirectory(),#PB_Program_Open)
	;handle=RunProgram("cmd.exe","/c "+command,GetTemporaryDirectory(),#PB_Program_Open|#PB_Program_Read)

	If handle
		While ProgramRunning(handle) And timeout>ElapsedMilliseconds()
			Debug "*"
			Delay(100)
		Wend
		Debug "TRY TO KILL"
		Debug IsProgram(handle)
		Debug KillProgram(handle)
		Debug IsProgram(handle)
		Debug CloseProgram(handle)
		Debug IsProgram(handle)

	EndIf

	Debug "done"

EndProcedure

;RunCommand("net start bthserv")
RunCommand("net stop bthserv")
Debug "..."
Delay(3000)
Debug "QUIT"