Visual Basic System Services
CreateToolhelp32Snapshot: Enumerate to Determine an App's Parent Process
     
Posted:   Monday November 04, 2002
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   All OS versions except Windows NT4
Author:   Jason Bouzane, VBnet - Randy Birch
     
 Prerequisites
CreateToolhelp32Process is not available on Windows NT4 systems.

When an application creates a system process snapshot via CreateToolhelp32Process, the process ID of the current application's process as well as that of the application that launched the current application is available. By enumerating the snapshot to locate the current process, then re-enumerate with the parent process ID, the exe used to launch the current application can be returned.

This method shows how to perform the enumeration to retrieve the launching application name. This code is based on a posting to by Jason Bouzane to the comp.lang.basic.visual newsgroup.

 

 BAS Module Code
None:

 Form Code
Add a command button (Command1) and a text box (Text1) to a form, along with the following:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const TH32CS_SNAPPROCESS = &H2
Private Const INVALID_HANDLE = &HFFFFFFFF
Private Const MAX_PATH As Long = 260

Private Type PROCESSENTRY32
  dwSize As Long
  cntUsage As Long
  th32ProcessID As Long
  th32DefaultHeapID As Long
  th32ModuleID As Long
  cntThreads As Long
  th32ParentProcessID As Long
  pcPriClassBase As Long
  dwFlags As Long
  szExeFile As String * MAX_PATH
End Type

Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" _
   (ByVal lFlags As Long, ByVal lProcessID As Long) As Long
   
Private Declare Function Process32First Lib "kernel32" _
  (ByVal hSnapshot As Long, _
   uProcess As PROCESSENTRY32) As Long

Private Declare Function Process32Next Lib "kernel32" _
  (ByVal hSnapshot As Long, _
   uProcess As PROCESSENTRY32) As Long

Private Declare Sub CloseHandle Lib "kernel32" _
  (ByVal hPass As Long)

Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long

Private Declare Function lstrlenW Lib "kernel32" _
  (ByVal lpString As Long) As Long
         


Private Sub Form_Load()

   Command1.Caption = "Get Parent Process"

End Sub


Private Sub Command1_Click()

   Text1.Text = GetParentProcess2()
   
End Sub


Private Function GetParentProcess2() As String
    
    Dim hSnapshot As Long
    Dim pe As PROCESSENTRY32

   'create a snapshot of the system
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0&)
    
    If hSnapshot <> INVALID_HANDLE Then
    
     'call FindProcess passing the
     'snapshot handle and the result
     'of a GetCurrentProcessID API call
     'to obtain the process entry data
     'for the current app.
      pe = FindProcess(hSnapshot, GetCurrentProcessId())
      
      
     'if a match is found, the value of
     'interest is the parent process ID.
     'This gets passed to a second call to
     'FindProcess.
      If pe.th32ParentProcessID <> 0 Then
      
         pe = FindProcess(hSnapshot, pe.th32ParentProcessID)
         
        'if a parent proccess match was found,
        'the szExeFile parmeter of the returned
        'data holds the parent application name
         If pe.th32ProcessID <> 0 Then
         
            GetParentProcess2 = TrimNull(pe.szExeFile)
         
         Else
            GetParentProcess2 = "[no match; parent must have closed]"
         End If
      End If
      
      CloseHandle hSnapshot
   
   End If
    
End Function


Private Function FindProcess(ByVal hSnapshot As Long, _
                             ByVal dwProcID As Long) As PROCESSENTRY32

   Dim pe As PROCESSENTRY32
   
  'initialize the type
   pe.dwSize = Len(pe)
   
  'double check the snapshot handle
   If hSnapshot <> INVALID_HANDLE Then
   
      Call Process32First(hSnapshot, pe)
      
     'loop until a process matching
     'dwProcID is found, or until
     'nothing more to enumerate
      Do
      
         If pe.th32ProcessID = dwProcID Then
           'match found; return the
           'data as a PROCESSENTRY32 type
            FindProcess = pe
            Exit Do
         End If
      
      Loop Until Process32Next(hSnapshot, pe) = 0
       
   End If
   
End Function


Private Function TrimNull(startstr As String) As String

   TrimNull = Left$(startstr, lstrlenW(StrPtr(startstr)))
   
End Function
 Comments
When the project above is run in the IDE, the parent process returned is explorer.exe. 

To test this for the demo I complied the code above as project1.exe. I then created a second project with one line of code: Call Shell("d:\project1.exe", vbNormalFocus). 

When this calling application was run in the IDE to launch project1.exe, the parent app returned was VB6.exe. When the calling program was compiled into go.exe and run, the parent program was correctly returned as go.exe.  If project1.exe is opened via explorer, the parent is explorer.exe. Apps with explorer.exe as parent can be assumed to have been started via explorer or an explorer shortcut.


 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter