End a program started with RunProgram?

Just starting out? Need help? Post your questions and find answers here.
BarryG
Addict
Addict
Posts: 4122
Joined: Thu Apr 18, 2019 8:17 am

End a program started with RunProgram?

Post by BarryG »

I have this old code from this forum, but it doesn't work anymore. How can I make it work? I don't want to use KillProgram() to end the program because it won't close down cleanly if you do that (such as Firefox, which gives a message about improper shutdown when you next restart it).

Code: Select all

Procedure EndProgram(processID)
  w=GetWindow_(GetDesktopWindow_(),#GW_CHILD)
  Repeat
    GetWindowThreadProcessId_(w,@pid)
    If pid=processID
      hWnd=w
      Break
    EndIf
    w=GetWindow_(w,#GW_HWNDNEXT)
  Until w=0
  Debug PostMessage_(hWnd,#WM_SYSCOMMAND,#SC_CLOSE,0) ; Returns 1 but Notepad is still open.
EndProcedure

app$="c:\windows\system32\notepad.exe"
handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
pid=ProgramID(handle)
Sleep_(2000) ; Give it time to open.
CloseProgram(handle)
EndProgram(pid) ; End started program.
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: End a program started with RunProgram?

Post by mk-soft »

It is better to close the window via the ClassName, as the title can change. I have extended my include.

Code: Select all

;-TOP

; Comment : Window Functions
; Author  : mk-soft
; Version : v1.03.0
; Create  : ?
; Update  : 20.11.2021

Structure udtListWindows
  Name.s
  Class.s
  Handle.i
  Process.i
  Childs.i
  Level.i
EndStructure

Threaded NewList ListWindows.udtListWindows()

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
    
    ;- Windows
    
    Procedure.s GetTitle(Handle)
      Protected Name.s
      Name.s = Space(1024)
      GetWindowText_(Handle, @Name, Len(Name))
      ProcedureReturn Left(Name, Len(Name))
    EndProcedure
    
    Procedure.s GetClassName(Handle.i)
      Protected Class.s
      Class.s = Space(1024)
      GetClassName_(Handle, @Class, Len(Class))
      ProcedureReturn Left(Class, Len(Class))
    EndProcedure

    Procedure EnumProc(Handle.i, lParam.i)
      Protected *tmp.udtListWindows
      AddElement(ListWindows())
     
      ListWindows()\Handle = Handle
      ListWindows()\Process = 0
      GetWindowThreadProcessId_(Handle, @ListWindows()\Process)
      ListWindows()\Name = GetTitle(Handle)
      ListWindows()\Class = GetClassName(Handle)
      
      If lParam
        *tmp = lParam
        *tmp\Childs + 1
        ListWindows()\Level = *tmp\Level + 1
      Else
        ListWindows()\Level = 0
      EndIf
      
      EnumChildWindows_(Handle, @EnumProc(), @ListWindows())
      
      ProcedureReturn #True
    EndProcedure
    
    Procedure GetAllWindows() ; Result = Count of Windows
      Protected r1, len
      
      ClearList(ListWindows())
      r1 = EnumWindows_(@EnumProc(), 0)
      ProcedureReturn ListSize(ListWindows())
    EndProcedure
    
    Procedure FindNamedWindow(Name.s) ; Result = Handle
      Protected cnt, len
      len = Len(Name)
      
      GetAllWindows()
      ForEach ListWindows()
        If FindString(ListWindows()\Class, "CabinetWClass")
          Continue
        EndIf
        If FindString(ListWindows()\Class, "ShellTabWindowClass")
          Continue
        EndIf
        If Left(ListWindows()\Name, len) = Name
          ProcedureReturn ListWindows()\Handle
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure FindClassWindow(Name.s) ; Result = Handle
      Protected cnt, len
      len = Len(Name)
      
      GetAllWindows()
      ForEach ListWindows()
        If FindString(ListWindows()\Class, "CabinetWClass")
          Continue
        EndIf
        If FindString(ListWindows()\Class, "ShellTabWindowClass")
          Continue
        EndIf
        If Left(ListWindows()\Class, len) = Name
          ProcedureReturn ListWindows()\Handle
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s) ; Result = Count of Windows
      Protected cnt, len
      len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If Left(ListWindows()\Name, len) = Name
          If FindString(ListWindows()\Class, "CabinetWClass")
            Continue
          EndIf
          If FindString(ListWindows()\Class, "ShellTabWindowClass")
            Continue
          EndIf
          SendMessage_(ListWindows()\Handle, #WM_CLOSE, 0, 0)
          cnt + 1
        EndIf
      Next
      ProcedureReturn cnt
    EndProcedure
    
    Procedure CloseClassWindow(Name.s) ; Result = Count of Windows
      Protected cnt, len
      len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If ListWindows()\Class = Name
          SendMessage_(ListWindows()\Handle, #WM_CLOSE, 0, 0)
          cnt + 1
        EndIf
      Next
      ProcedureReturn cnt
    EndProcedure
    

  CompilerCase #PB_OS_MacOS
    
    ;- MacOS
    Threaded __IsMainScope
    __IsMainScope = #True
    
    Procedure GetAllWindows() ; Result = Count of Windows
      Protected RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      ClearList(ListWindows())
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        AddElement(ListWindows())
        ListWindows()\Name = AppName
        ListWindows()\Handle = RunningApp
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn i
    EndProcedure
    
    Procedure FindNamedWindow(Name.s) ; Result = RunningApp
      Protected r1, RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, cnt, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        If Name = AppName
          r1 = RunningApp
          Break
        EndIf
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn r1
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s) ;  ; Result = Count of Windows
      Protected RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, cnt, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        If Name = AppName
          CocoaMessage(0, RunningApp, "terminate")
          cnt + 1
        EndIf
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn cnt
    EndProcedure
      
  CompilerCase #PB_OS_Linux
    
    ;- Linux
    
    ;- Install Paket 'sudo apt-get install wmctrl'
    
    Procedure GetAllWindows()
      Protected Compiler, Output.s, Temp.s, pos
      
        ClearList(ListWindows())
        Compiler = RunProgram("wmctrl", "-l -x", "", #PB_Program_Open | #PB_Program_Read)
        Output = ""
        If Compiler
          While ProgramRunning(Compiler)
            If AvailableProgramOutput(Compiler)
              Output = ReadProgramString(Compiler)
              AddElement(ListWindows())
              temp = "$" + Mid(Output, 3, 8)
              ListWindows()\Handle = Val(temp)
              temp = Mid(Output, 15)
              pos = FindString(temp, "  ")
              ListWindows()\Class = Left(temp, pos)
              temp = Trim(Mid(temp, pos))
              pos = FindString(temp, " ")
              ListWindows()\Name = Mid(temp, pos + 1)
            Else
              Delay(10)
            EndIf
          Wend
          CloseProgram(Compiler) ; Close the connection to the program
        Else
          Output = "Error - Programm konnte nicht gestartet werden!"
        EndIf
        
    EndProcedure
    
    Procedure FindNamedWindow(Name.s)
      Protected len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If Left(ListWindows()\Name, len) = Name
          If Not FindString(ListWindows()\Class, "nautilus", 1, #PB_String_NoCase)
            ProcedureReturn ListWindows()\Handle
          EndIf
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s)  ; Result = #True or #False
      RunProgram("wmctrl", "-a " + Name, "")
      Delay(100)
      RunProgram("wmctrl", "-c " + Name, "")
      Delay(100)
      ProcedureReturn #True
    EndProcedure
    
CompilerEndSelect

;- Example

CompilerIf #PB_Compiler_IsMainFile
  
  Enumeration Windows
    #Main
  EndEnumeration
  
  Enumeration Gadgets
    
  EndEnumeration
  
  Enumeration Status
    #MainStatusBar
  EndEnumeration
  
  Procedure Main()
    
    If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 400, 200, "Window" , #PB_Window_SystemMenu)
      
      GetAllWindows()
      
;       ForEach ListWindows()
;         If FindString(ListWindows()\Name, "Editor")
;           Debug ListWindows()\Name
;           Debug ListWindows()\Class
;         EndIf
;       Next
      
      r1 = FindClassWindow("Notepad")
      Debug "Notepad Handle = " + Hex(r1)
      Debug "Notepad Title  = " + GetTitle(r1)
      CloseClassWindow("Notepad")
      
      ;Debug GetTitle(r1)
      
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
      
    EndIf
    
  EndProcedure : Main()
  
CompilerEndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 6202
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: End a program started with RunProgram?

Post by mk-soft »

Another way ...

CloseWindowFromPID

Code: Select all

;-TOP by mk-soft

Threaded Handle_From_Process

Procedure EnumWindowsProcPID(hWnd, lParam)
  Protected lpdwProcessId
  GetWindowThreadProcessId_(hWnd, @lpdwProcessId)
  If lpdwProcessId = lParam
    Handle_From_Process = hWnd
    ProcedureReturn 0
  EndIf
  ProcedureReturn 1
EndProcedure

Procedure GetWindowFromPID(ProcessID)
  Protected r1
  Handle_From_Process = 0
  r1 = EnumWindows_(@EnumWindowsProcPID(), ProcessId);
  ProcedureReturn Handle_From_Process
EndProcedure

Procedure CloseWindowFromPID(ProcessID)
  Protected hWnd
  hWnd = GetWindowFromPID(ProcessID)
  If hWnd
    PostMessage_(hWnd, #WM_CLOSE, 0, 0)
  EndIf
EndProcedure

app$="c:\windows\system32\notepad.exe"
handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
pid=ProgramID(handle)
Delay(100) ; need some time to open notepad window
r1 = GetWindowFromPID(pid)
Debug r1
Sleep_(2000) ; Give it time to open.
CloseWindowFromPID(pid)

My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
BarryG
Addict
Addict
Posts: 4122
Joined: Thu Apr 18, 2019 8:17 am

Re: End a program started with RunProgram?

Post by BarryG »

Thanks mk-soft, I went for your second code because (a) it's much smaller, and (b) it uses RunProgram like I asked - I wasn't trying to close an existing window. Thanks for your help.
User avatar
a_carignan
User
User
Posts: 98
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: End a program started with RunProgram?

Post by a_carignan »

Hello, Here is a working example for applications other than Notepad.

Code: Select all

Procedure EndProgram(processID)
  w=GetWindow_(GetDesktopWindow_(),#GW_CHILD)
  Repeat
    GetWindowThreadProcessId_(w,@pid)
    If pid=processID
      hWnd=w
      ;PostMessage_(hWnd,#WM_SYSCOMMAND,#SC_CLOSE,0) ; Returns 1 but Notepad is still open.
      PostMessage_(hWnd, #WM_CLOSE, 0, 0)
      Debug "ICI"
      ;Break
    EndIf
    w=GetWindow_(w,#GW_HWNDNEXT)
  Until w=0
  ;SendMessage_(GetForegroundWindow_(), #WM_SYSCOMMAND, #SC_HOTKEY, hwnd)
  ;SetForegroundWindow_(hwnd)     
  ;BringWindowToTop_(hwnd)
  ;SendMessage_(hwnd,#WM_ACTIVATE,0,0)
  ;SendMessage_(hwnd, #WM_SYSCOMMAND, #SC_CLOSE, 0)
EndProcedure
;app$="c:\windows\system32\notepad.exe"
;app$="C:\Key_USB\OneDrive\LiberKey\MyApps\MiniMacro\editeur.exe"
;app$="C:\Key_USB\OneDrive\LiberKey\MyApps\Druide\druide3.exe"
handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
Sleep_(5000) ; Give it time to open.
EndProgram(ProgramID(handle)) ; End started program.
Debug "Fini"
:D
User avatar
a_carignan
User
User
Posts: 98
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: End a program started with RunProgram?

Post by a_carignan »

Hello, Here is an example to close Notepad, The example is a little clearer than one already described.

Code: Select all

;-TOP

; Comment : Window Functions
; Author  : mk-soft
; Version : v1.03.0
; Create  : ?
; Update  : 20.11.2021

Structure udtListWindows
  Name.s
  Class.s
  Handle.i
  Process.i
  Childs.i
  Level.i
EndStructure

Threaded NewList ListWindows.udtListWindows()

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
    
    ;- Windows
    
    Procedure.s GetTitle(Handle)
      Protected Name.s
      Name.s = Space(1024)
      GetWindowText_(Handle, @Name, Len(Name))
      ProcedureReturn Left(Name, Len(Name))
    EndProcedure
    
    Procedure.s GetClassName(Handle.i)
      Protected Class.s
      Class.s = Space(1024)
      GetClassName_(Handle, @Class, Len(Class))
      ProcedureReturn Left(Class, Len(Class))
    EndProcedure

    Procedure EnumProc(Handle.i, lParam.i)
      Protected *tmp.udtListWindows
      AddElement(ListWindows())
     
      ListWindows()\Handle = Handle
      ListWindows()\Process = 0
      GetWindowThreadProcessId_(Handle, @ListWindows()\Process)
      ListWindows()\Name = GetTitle(Handle)
      ListWindows()\Class = GetClassName(Handle)
      
      If lParam
        *tmp = lParam
        *tmp\Childs + 1
        ListWindows()\Level = *tmp\Level + 1
      Else
        ListWindows()\Level = 0
      EndIf
      
      EnumChildWindows_(Handle, @EnumProc(), @ListWindows())
      
      ProcedureReturn #True
    EndProcedure
    
    Procedure GetAllWindows() ; Result = Count of Windows
      Protected r1, len
      
      ClearList(ListWindows())
      r1 = EnumWindows_(@EnumProc(), 0)
      ProcedureReturn ListSize(ListWindows())
    EndProcedure
    
    Procedure FindNamedWindow(Name.s) ; Result = Handle
      Protected cnt, len
      len = Len(Name)
      
      GetAllWindows()
      ForEach ListWindows()
        If FindString(ListWindows()\Class, "CabinetWClass")
          Continue
        EndIf
        If FindString(ListWindows()\Class, "ShellTabWindowClass")
          Continue
        EndIf
        If Left(ListWindows()\Name, len) = Name
          ProcedureReturn ListWindows()\Handle
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure FindClassWindow(Name.s) ; Result = Handle
      Protected cnt, len
      len = Len(Name)
      
      GetAllWindows()
      ForEach ListWindows()
        If FindString(ListWindows()\Class, "CabinetWClass")
          Continue
        EndIf
        If FindString(ListWindows()\Class, "ShellTabWindowClass")
          Continue
        EndIf
        If Left(ListWindows()\Class, len) = Name
          ProcedureReturn ListWindows()\Handle
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s) ; Result = Count of Windows
      Protected cnt, len
      len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If Left(ListWindows()\Name, len) = Name
          If FindString(ListWindows()\Class, "CabinetWClass")
            Continue
          EndIf
          If FindString(ListWindows()\Class, "ShellTabWindowClass")
            Continue
          EndIf
          SendMessage_(ListWindows()\Handle, #WM_CLOSE, 0, 0)
          cnt + 1
        EndIf
      Next
      ProcedureReturn cnt
    EndProcedure
    
    Procedure CloseClassWindow(Name.s) ; Result = Count of Windows
      Protected cnt, len
      len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If ListWindows()\Class = Name
          SendMessage_(ListWindows()\Handle, #WM_CLOSE, 0, 0)
          cnt + 1
        EndIf
      Next
      ProcedureReturn cnt
    EndProcedure
    

  CompilerCase #PB_OS_MacOS
    
    ;- MacOS
    Threaded __IsMainScope
    __IsMainScope = #True
    
    Procedure GetAllWindows() ; Result = Count of Windows
      Protected RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      ClearList(ListWindows())
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        AddElement(ListWindows())
        ListWindows()\Name = AppName
        ListWindows()\Handle = RunningApp
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn i
    EndProcedure
    
    Procedure FindNamedWindow(Name.s) ; Result = RunningApp
      Protected r1, RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, cnt, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        If Name = AppName
          r1 = RunningApp
          Break
        EndIf
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn r1
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s) ;  ; Result = Count of Windows
      Protected RunningApps.i, RunningAppsCount.i, RunningApp.i, AppName.s, i, cnt, Pool
      
      If Not __IsMainScope
        Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      EndIf
      
      RunningApps = CocoaMessage(0, CocoaMessage(0, 0, "NSWorkspace sharedWorkspace"), "runningApplications")
      RunningAppsCount = CocoaMessage(0, RunningApps, "count")
      i = 0
      While i < RunningAppsCount
        RunningApp = CocoaMessage(0, RunningApps, "objectAtIndex:", i)
        AppName.s = PeekS(CocoaMessage(0, CocoaMessage(0, RunningApp, "localizedName"), "UTF8String"), -1, #PB_UTF8)
        If Name = AppName
          CocoaMessage(0, RunningApp, "terminate")
          cnt + 1
        EndIf
        i + 1
      Wend
      
      If Pool
        CocoaMessage(0, Pool, "release")
      EndIf
      
      ProcedureReturn cnt
    EndProcedure
      
  CompilerCase #PB_OS_Linux
    
    ;- Linux
    
    ;- Install Paket 'sudo apt-get install wmctrl'
    
    Procedure GetAllWindows()
      Protected Compiler, Output.s, Temp.s, pos
      
        ClearList(ListWindows())
        Compiler = RunProgram("wmctrl", "-l -x", "", #PB_Program_Open | #PB_Program_Read)
        Output = ""
        If Compiler
          While ProgramRunning(Compiler)
            If AvailableProgramOutput(Compiler)
              Output = ReadProgramString(Compiler)
              AddElement(ListWindows())
              temp = "$" + Mid(Output, 3, 8)
              ListWindows()\Handle = Val(temp)
              temp = Mid(Output, 15)
              pos = FindString(temp, "  ")
              ListWindows()\Class = Left(temp, pos)
              temp = Trim(Mid(temp, pos))
              pos = FindString(temp, " ")
              ListWindows()\Name = Mid(temp, pos + 1)
            Else
              Delay(10)
            EndIf
          Wend
          CloseProgram(Compiler) ; Close the connection to the program
        Else
          Output = "Error - Programm konnte nicht gestartet werden!"
        EndIf
        
    EndProcedure
    
    Procedure FindNamedWindow(Name.s)
      Protected len = Len(Name)
      GetAllWindows()
      ForEach ListWindows()
        If Left(ListWindows()\Name, len) = Name
          If Not FindString(ListWindows()\Class, "nautilus", 1, #PB_String_NoCase)
            ProcedureReturn ListWindows()\Handle
          EndIf
        EndIf
      Next
      ProcedureReturn 0
    EndProcedure
    
    Procedure CloseNamedWindow(Name.s)  ; Result = #True or #False
      RunProgram("wmctrl", "-a " + Name, "")
      Delay(100)
      RunProgram("wmctrl", "-c " + Name, "")
      Delay(100)
      ProcedureReturn #True
    EndProcedure
    
CompilerEndSelect

;- Example

CompilerIf #PB_Compiler_IsMainFile
  
  Enumeration Windows
    #Main
  EndEnumeration
  
  Enumeration Gadgets
    
  EndEnumeration
  
  Enumeration Status
    #MainStatusBar
  EndEnumeration
  
  Procedure Main()
    
    If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 400, 200, "Window" , #PB_Window_SystemMenu)
      
      GetAllWindows()
      
;       ForEach ListWindows()
;         If FindString(ListWindows()\Name, "Editor")
;           Debug ListWindows()\Name
;           Debug ListWindows()\Class
;         EndIf
;       Next
      
      r1 = FindClassWindow("Notepad")
      Debug "Notepad Handle = " + Hex(r1)
      Debug "Notepad Title  = " + GetTitle(r1)
      CloseClassWindow("Notepad")
      
      ;Debug GetTitle(r1)
      
      Repeat
        Select WaitWindowEvent()
          Case #PB_Event_CloseWindow
            Break
        EndSelect
      ForEver
    EndIf
    
  EndProcedure ;: Main()
  app$="c:\windows\system32\notepad.exe"
  handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
  Sleep_(5000) ; Give it time to open.
  CloseClassWindow("Notepad")
  
CompilerEndIf
:D
infratec
Always Here
Always Here
Posts: 7576
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: End a program started with RunProgram?

Post by infratec »

User avatar
a_carignan
User
User
Posts: 98
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: End a program started with RunProgram?

Post by a_carignan »

because killprogram kills the program, it does not close it.
Quin
Addict
Addict
Posts: 1122
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: End a program started with RunProgram?

Post by Quin »

What about CloseProgram()?
CloseProgram()
Syntax
CloseProgram(Program)
Description
Closes the connection with the given program (which was started with RunProgram()) and frees all related data.
User avatar
a_carignan
User
User
Posts: 98
Joined: Sat Feb 21, 2009 2:01 am
Location: Canada

Re: End a program started with RunProgram?

Post by a_carignan »

closeprogram cuts off communication with the software opened by runprogram, but does not close it.
Axolotl
Enthusiast
Enthusiast
Posts: 798
Joined: Wed Dec 31, 2008 3:36 pm

Re: End a program started with RunProgram?

Post by Axolotl »

Hi BarryG,
on my computer I never find the PID retrurned by ProgramID(). I don't know why.
So here is my solution:

Code: Select all

EnableExplicit 

Procedure.s GetWindowText(hWnd) 
  Protected wndTitle$ 

  wndTitle$ = Space(#MAX_PATH) 
  If GetWindowText_(hWnd, @wndTitle$, #MAX_PATH) = 0 
  ; Debug #PB_Compiler_Procedure+"() - Error " + GetLastError_() 
  EndIf 
  ProcedureReturn wndTitle$ 
EndProcedure 

Procedure EndProgram(ProcessID)
  Protected wnd, hwndFound, pid 

  wnd = GetWindow_(GetDesktopWindow_(), #GW_CHILD) 
  Repeat
    GetWindowThreadProcessId_(wnd, @pid)  
;     If pid = processID 
;       hwndFound = wnd           : Debug "Found " + hwndFound  
;       Break ; found it, escape the loop  
    If GetWindowText(wnd) = "Notepad" 
Debug "  Notepad window found  == 0x" + Hex(wnd) + ", (" + Str(wnd) + ")  -- PID == " + pid 
      hwndFound = wnd 
      Break     
    EndIf
    wnd = GetWindow_(wnd, #GW_HWNDNEXT) 
  Until wnd = 0 

  Debug PostMessage_(hwndFound, #WM_SYSCOMMAND, #SC_CLOSE, 0)  ; returns 1 but Notepad is still open. 
EndProcedure

Global App$, PN, pid  

App$ = "c:\windows\system32\notepad.exe" 

PN = RunProgram(App$, "", GetPathPart(App$), #PB_Program_Open) 
pid = ProgramID(PN)
Debug "NotePad .... pid == " + pid 

Delay(1000)  ; Give it time to open.

CloseProgram(PN) 
EndProgram(pid) ; End started program.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
BarryG
Addict
Addict
Posts: 4122
Joined: Thu Apr 18, 2019 8:17 am

Re: End a program started with RunProgram?

Post by BarryG »

@Axolotl: My post was from 3 years ago. The new posts here are others asking about it. ;) I'm all good.
User avatar
Piero
Addict
Addict
Posts: 863
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: End a program started with RunProgram?

Post by Piero »

PB Bug?

Code: Select all

app$="c:\windows\system32\notepad.exe"
handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
Sleep_(2000) ; Give it time to open.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; works only if there is a single notepad instance!?! (try to run after opening notepad with windows)
pid=ProgramID(handle)
RunProgram("taskkill","/F /PID "+ Str(pid) +" /T","",#PB_Program_Wait|#PB_Program_Hide)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CloseProgram(handle)
 
This works, but kills all instances:

Code: Select all

RunProgram("taskkill","/F /IM notepad.exe /T","",#PB_Program_Wait|#PB_Program_Hide)

; /F kill (no prompt for unsaved documents etc.)
; /T also terminate subprocesses
Quit frontmost:

Code: Select all

app$="c:\windows\system32\notepad.exe"
handle=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
handle2=RunProgram(app$,"",GetPathPart(app$),#PB_Program_Open)
Sleep_(3000) ; try click the background notepad window…

; works, but only for FRONTMOST instance
RunProgram("taskkill","/IM notepad.exe /T","",#PB_Program_Wait|#PB_Program_Hide)
; RunProgram("taskkill","/IM notepad.exe /T","",#PB_Program_Wait|#PB_Program_Hide)

CloseProgram(handle)
CloseProgram(handle2)
 
Edit/PS: Dear Wise Admins, this noob hopes to be wrong, but from my tests it seems to be a "dangerous bug"; wrong/inexistent PID………
Post Reply