Results 1 to 6 of 6

Thread: Normal Termination of an external program using VB6

  1. #1

    Thread Starter
    Lively Member Mahdi Jazini's Avatar
    Join Date
    Feb 2014
    Location
    Iran / Tehran
    Posts
    89

    Question Normal Termination of an external program using VB6

    I know how to close external programs using TerminateProcess API Function and ExitProcess API Function and Tskkill DOS Command but i need to find a way to close opened programs normally...

    Something like clicking on close button of programs...

    Can anyone help me?

    tnx
    Last edited by Mahdi Jazini; Feb 17th, 2014 at 03:35 AM. Reason: add space

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Normal Termination of an external program using VB6

    PostMessage the WM_CLOSE message to that window. BTW, it's a good thing you've decided to gracefully close other processes because terminating them abruptly may lead to memory leaks. The MS KB article How To Terminate an Application "Cleanly" in Win32 outlines the steps you need to take.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3

    Thread Starter
    Lively Member Mahdi Jazini's Avatar
    Join Date
    Feb 2014
    Location
    Iran / Tehran
    Posts
    89

    Re: Normal Termination of an external program using VB6

    Quote Originally Posted by Bonnie West View Post
    PostMessage the WM_CLOSE message to that window. BTW, it's a good thing you've decided to gracefully close other processes because terminating them abruptly may lead to memory leaks. The MS KB article How To Terminate an Application "Cleanly" in Win32 outlines the steps you need to take.
    the PostMessage function is g8. tnx a lot

    but the PostMessage is unable to close applications by (file name example: test.exe) it can close (visible) applications by their (title name=caption)

  4. #4
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Normal Termination of an external program using VB6

    Code:
    Option Explicit     'In a standard module
    Option Compare Text 'Enable case-insensitive string comparisons for the Like operator
    
    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    Private Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
    Private Declare Function GetProcessImageFileNameW Lib "psapi.dll" (ByVal hProcess As Long, ByVal lpImageFileName As Long, ByVal nSize As Long) As Long
    Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As Long, Optional ByRef lpdwProcessId As Long) As Long
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function SendMessageTimeoutW Lib "user32.dll" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal fuFlags As Long, ByVal uTimeout As Long, Optional ByRef lpdwResult As Long) As Long
    Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
    Private Declare Function TerminateProcess Lib "kernel32.dll" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
    
    'This subroutine attempts to terminate a process gracefully.
    'There are, however, some limitations: it can only close
    'processes which have a top-level window and it can't kill
    'certain processes like anti-virus and 64-bit processes.
    
    'The ImageName argument accepts either a specific filename
    'or a filename that includes wildcard characters like * or ?
    
    Public Sub EndProcess(ByRef ImageName As String)
        EnumWindows AddressOf EnumWindowsProc, VarPtr(ImageName)
    End Sub
    
    Private Function EnumWindowsProc(ByVal hWnd As Long, ByRef lParam As String) As Long
        Const PROCESS_QUERY_INFORMATION = &H400&, PROCESS_TERMINATE = &H1&
        Const BUFFER_SIZE = 300&, SMTO_ABORTIFHUNG = &H2&, WM_CLOSE = &H10&, TIMEOUT = 5000& '<-- 5 Secs.
        Dim PID As Long, hProcess As Long, StartPos As Long, EndPos As Long, sBuffer As String
    
        If GetWindowThreadProcessId(hWnd, PID) Then
            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE, 0&, PID)
            If hProcess Then
                SysReAllocStringLen VarPtr(sBuffer), , BUFFER_SIZE
                EndPos = GetProcessImageFileNameW(hProcess, StrPtr(sBuffer), BUFFER_SIZE + 1&)
                If EndPos Then
                    StartPos = InStrRev(sBuffer, "\", EndPos)
                    If Mid$(sBuffer, StartPos + 1&, EndPos - StartPos) Like lParam Then
                        If SendMessageTimeoutW(hWnd, WM_CLOSE, 0&, 0&, SMTO_ABORTIFHUNG, TIMEOUT) = 0& Then
                            PID = TerminateProcess(hProcess, 0&):  Debug.Assert PID
                        End If
                    End If
                End If
                hProcess = CloseHandle(hProcess):  Debug.Assert hProcess
            End If
        End If
    
        EnumWindowsProc = 1&
    End Function
    Code:
    EndProcess "calc.exe"
    EndProcess "notepad.???"
    EndProcess "Project*"
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  5. #5

    Thread Starter
    Lively Member Mahdi Jazini's Avatar
    Join Date
    Feb 2014
    Location
    Iran / Tehran
    Posts
    89

    Re: Normal Termination of an external program using VB6

    Quote Originally Posted by Bonnie West View Post
    Code:
    Option Explicit     'In a standard module
    Option Compare Text 'Enable case-insensitive string comparisons for the Like operator
    
    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    Private Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
    Private Declare Function GetProcessImageFileNameW Lib "psapi.dll" (ByVal hProcess As Long, ByVal lpImageFileName As Long, ByVal nSize As Long) As Long
    Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hWnd As Long, Optional ByRef lpdwProcessId As Long) As Long
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function SendMessageTimeoutW Lib "user32.dll" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal fuFlags As Long, ByVal uTimeout As Long, Optional ByRef lpdwResult As Long) As Long
    Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
    Private Declare Function TerminateProcess Lib "kernel32.dll" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
    
    'This subroutine attempts to terminate a process gracefully.
    'There are, however, some limitations: it can only close
    'processes which have a top-level window and it can't kill
    'certain processes like anti-virus and 64-bit processes.
    
    'The ImageName argument accepts either a specific filename
    'or a filename that includes wildcard characters like * or ?
    
    Public Sub EndProcess(ByRef ImageName As String)
        EnumWindows AddressOf EnumWindowsProc, VarPtr(ImageName)
    End Sub
    
    Private Function EnumWindowsProc(ByVal hWnd As Long, ByRef lParam As String) As Long
        Const PROCESS_QUERY_INFORMATION = &H400&, PROCESS_TERMINATE = &H1&
        Const BUFFER_SIZE = 300&, SMTO_ABORTIFHUNG = &H2&, WM_CLOSE = &H10&, TIMEOUT = 5000& '<-- 5 Secs.
        Dim PID As Long, hProcess As Long, StartPos As Long, EndPos As Long, sBuffer As String
    
        If GetWindowThreadProcessId(hWnd, PID) Then
            hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE, 0&, PID)
            If hProcess Then
                SysReAllocStringLen VarPtr(sBuffer), , BUFFER_SIZE
                EndPos = GetProcessImageFileNameW(hProcess, StrPtr(sBuffer), BUFFER_SIZE + 1&)
                If EndPos Then
                    StartPos = InStrRev(sBuffer, "\", EndPos)
                    If Mid$(sBuffer, StartPos + 1&, EndPos - StartPos) Like lParam Then
                        If SendMessageTimeoutW(hWnd, WM_CLOSE, 0&, 0&, SMTO_ABORTIFHUNG, TIMEOUT) = 0& Then
                            PID = TerminateProcess(hProcess, 0&):  Debug.Assert PID
                        End If
                    End If
                End If
                hProcess = CloseHandle(hProcess):  Debug.Assert hProcess
            End If
        End If
    
        EnumWindowsProc = 1&
    End Function
    Code:
    EndProcess "calc.exe"
    EndProcess "notepad.???"
    EndProcess "Project*"
    Your code worked g8... tnx a lot
    but there is problem...
    do you know WAMPSERVER?
    i have 32 bit version of it.
    when i do right click on the (system try icon) of it and click (Exit)... the WAMP SERVER program will try to close (itself) + (all hidden opened programs related to the wamp... like: httpd.exe and etc...)
    but your code will try to close wampmanager.exe only
    yes tried to close wampmanager.exe in safe mode, but it couldn't execute (Exit) command in WAMP SERVER program.
    i have a suggestion... if we do convert hProcess to hwnd, we can use PostMessage function for this. but i don't know how to convert it hProcess is an argument of TerminateProcess function:

    Code:
    Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Declare Function TerminateProcess Lib "kernel32" Alias "TerminateProcess" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long

  6. #6
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Normal Termination of an external program using VB6

    Quote Originally Posted by Mehdi Jazini View Post
    do you know WAMPSERVER?
    No.

    Quote Originally Posted by Mehdi Jazini View Post
    i have 32 bit version of it.
    when i do right click on the (system try icon) of it and click (Exit)... the WAMP SERVER program will try to close (itself) + (all hidden opened programs related to the wamp... like: httpd.exe and etc...)
    but your code will try to close wampmanager.exe only
    yes tried to close wampmanager.exe in safe mode, but it couldn't execute (Exit) command in WAMP SERVER program.
    In your OP, you failed to mention that you wanted to terminate the child processes too. I had no way of knowing what you really required, hence the code in post #4 didn't take that into account. In order to prevent further confusion, can you please describe your requirements in utmost detail? Thank you. (When composing an OP, you should always divulge as much information as possible about the problem.)

    Quote Originally Posted by Mehdi Jazini View Post
    i have a suggestion... if we do convert hProcess to hwnd, we can use PostMessage function for this. but i don't know how to convert it hProcess is an argument of TerminateProcess function:
    In the code above, I've replaced the PostMessage function with the SendMessageTimeout function so that the code will wait a certain amount of time for the WM_CLOSE message to be processed by the target window. This synchronous approach simplifies the code a bit by eliminating the WaitForSingleObject function.

    Here's what the code above does:

    1. All the top-level windows (those that are neither a child control nor owned window) are enumerated.
    2. Each window's Process ID is obtained so that its process can be opened.
    3. The fully-qualified pathname of the process is retrieved and the filename component is extracted.
    4. The process' filename is compared (using the Like operator) against the specified ImageName.
    5. If the names match, the current window is requested to close via the WM_CLOSE message.
    6. If the window failed to close within the designated time limit, the code then attempts to forcibly terminate the window's process.
    7. Steps 2-6 are repeated for the other windows whose processes matches the specified ImageName, if any.


    Are you saying you want to do the reverse? That is, enumerate the windows of a given process? Well, it can be done through the CreateToolhelp32Snapshot, Thread32First, Thread32Next and EnumThreadWindows functions.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width