• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 145
  • Last Modified:

Executable Name from Window Handle in NT

Can any tell me how to get the executable name from a window handle running on NT.  The GetWindowHandle and GetModuleFileName API calls do not work with NT as instance handles are not global.  Any ideas antone?
1 Solution

  Dim iHwnd As Long
  Dim sCaptionName As String
  Dim sExecName As String
  ' Scan thru windows looking for a specific Exe...
  ' The desktop is the highest window
  iHwnd = GetDesktopWindow()

  ' It's first child is the 1st top level window
  iHwnd = GetWindow(iHwnd, GW_CHILD)

  ' Now examine all top level windows
    Get_Window_Details iHwnd, sExecName, sCaptionName
    If UCase$(sExecName) = UCase$(sProgramExe) Then
      '--If no need to look at the caption...
      If Len(sFindInCaption) = 0 Then
        Get_Handle = iHwnd
        Exit Function
      '--else, check out the caption...
        If InStr(sCaptionName, sFindInCaption) > 0 Then
          Get_Handle = iHwnd
          Exit Function
        End If
      End If
    End If

    iHwnd = GetWindow(iHwnd, GW_HWNDNEXT)
  Loop While iHwnd <> 0

  Get_Handle = 0

End Function

Sub Get_Window_Details(iHwnd As Long, sExecName As String, sCaptionName As String)
  Dim iInstance As Long
  Dim iDummy As Long
  Dim sProgramExe As String

  sExecName = String$(256, 0) ' Predefine string length
  'iInstance = GetWindowLong(iHwnd, GWL_HINSTANCE)
  iDummy = GetModuleFileName(iInstance, sExecName, 255)
  sExecName = Get_Base_Name(sExecName)

  '-- get rid of trailing null 0
  'If InStr(sExecName, Chr$(0)) Then sExecName = Left$(sExecName, InStr(sExecName, Chr$(0)) - 1)

  'DKM - added this for window caption
  sCaptionName = String$(256, 0)  'init string space
  iDummy = GetWindowText(iHwnd, sCaptionName, 255)
  If InStr(sCaptionName, Chr$(0)) Then sCaptionName = Left$(sCaptionName, InStr(sCaptionName, Chr$(0)) - 1)

end sub

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

JeffClarkeAuthor Commented:
This solution works for win 95,98 but trajically not for NT as
requested  In NT the instance handles iare not global but are unique to the address space where the application is running.

A way around this that as been suggested but sadly Ii have been unable to achieve is going via the registry using the process thread ID to retrieve performance data (which fortunately contains the process name)
There is a function called GetModuleFileNameExA in psapi.dll. However, it needs a process handle also. If you
have it also, the fuction can help you to get
the executable Name

Public Declare Function GetModuleFileNameExA Lib "psapi.dll" (ByVal hProcess As String, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long

also see http://msdn.microsoft.com/library/sdkdoc/winbase/psapi_8x88.htm
Public Declare Function Process32First Lib "kernel32" ( _
   ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Public Declare Function Process32Next Lib "kernel32" ( _
   ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Public Declare Function CloseHandle Lib "Kernel32.dll" _
   (ByVal Handle As Long) As Long

Public Declare Function OpenProcess Lib "Kernel32.dll" _
  (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, _
      ByVal dwProcId As Long) As Long

Public Declare Function EnumProcesses Lib "psapi.dll" _
   (ByRef lpidProcess As Long, ByVal cb As Long, _
      ByRef cbNeeded As Long) As Long

Public Declare Function GetModuleFileNameExA Lib "psapi.dll" _
   (ByVal hProcess As Long, ByVal hModule As Long, _
      ByVal ModuleName As String, ByVal nSize As Long) As Long

Public Declare Function EnumProcessModules Lib "psapi.dll" _
   (ByVal hProcess As Long, ByRef lphModule As Long, _
      ByVal cb As Long, ByRef cbNeeded As Long) As Long

Public Declare Function CreateToolhelp32Snapshot Lib "kernel32" ( _
   ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long

Public Declare Function GetVersionExA Lib "kernel32" _
   (lpVersionInformation As OSVERSIONINFO) As Integer
Public Declare Function TerminateProcess Lib "kernel32" _
    (ByVal hProcess As Long, ByVal uExitCode As Long) As Long

   dwSize As Long
   cntUsage As Long
   th32ProcessID As Long           ' This process
   th32DefaultHeapID As Long
   th32ModuleID As Long            ' Associated exe
   cntThreads As Long
   th32ParentProcessID As Long     ' This process's parent process
   pcPriClassBase As Long          ' Base priority of process threads
   dwFlags As Long
   szExeFile As String * 260       ' MAX_PATH
End Type

   dwOSVersionInfoSize As Long
   dwMajorVersion As Long
   dwMinorVersion As Long
   dwBuildNumber As Long
   dwPlatformId As Long           '1 = Windows 95.
                                  '2 = Windows NT

   szCSDVersion As String * 128
End Type

Public Const PROCESS_VM_READ = 16
Public Const MAX_PATH = 260
Public Const SYNCHRONIZE = &H100000
Public Const TH32CS_SNAPPROCESS = &H2&
Public Const hNull = 0

Main code...

Sub MAIN()
        APP_NAME$ = UCase(Trim(Command$))
    Select Case getVersion()
        Case 1 'Windows 95/98
            Dim f As Long, sname As String
            Dim hSnap As Long, proc As PROCESSENTRY32
            Dim lretprocesshandle As Long
            Dim ProcessName95 As String
            Dim InstrRes As Integer
            Dim lret2 As Long
            hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
            If hSnap = hNull Then Exit Sub
            proc.dwSize = Len(proc)
            ' Iterate through the processes
            f = Process32First(hSnap, proc)
            Do While f
                sname = StrZToStr(proc.szExeFile)

                ProcessName95 = APP_NAME$
                sname = Trim$(sname)
                InstrRes = InStr(1, sname, ProcessName95, vbTextCompare)
                If InstrRes > 2 Then
                    lretprocesshandle = OpenProcess(PROCESS_ALL_ACCESS, True, proc.th32ProcessID)
                lret2 = TerminateProcess(lretprocesshandle, 0&)
                End If
                f = Process32Next(hSnap, proc)
        Case 2 'Windows NT
            Dim cb As Long
            Dim cbNeeded As Long
            Dim NumElements As Long
            Dim ProcessIDs() As Long
            Dim cbNeeded2 As Long
            Dim NumElements2 As Long
            Dim Modules(1 To 200) As Long
            Dim lret As Long
            Dim ModuleName As String
            Dim ProcessName As String
            Dim CompString As String
            Dim nSize As Long
            Dim hProcess As Long
            Dim i As Long
            Dim InstrResNT As Integer
            'Get the array containing the process id's for each process object
            cb = 8
            cbNeeded = 96
            Do While cb <= cbNeeded
                cb = cb * 2
                ReDim ProcessIDs(cb / 4) As Long
                lret = EnumProcesses(ProcessIDs(1), cb, cbNeeded)
            NumElements = cbNeeded / 4
            For i = 1 To NumElements
                'Get a handle to the Process
                hProcess = OpenProcess(PROCESS_QUERY_INFORMATION _
                    Or PROCESS_VM_READ Or PROCESS_TERMINATE, 0, ProcessIDs(i))
                'Got a Process handle
                If hProcess <> 0 Then
                    'Get an array of the module handles for the specified
                    lret = EnumProcessModules(hProcess, Modules(1), 200, _
                    'If the Module Array is retrieved, Get the ModuleFileName
                    If lret <> 0 Then
                        ModuleName = Space(MAX_PATH)
                        nSize = 500
                        lret = GetModuleFileNameExA(hProcess, Modules(1), _
                            ModuleName, nSize)
                        ProcessName = APP_NAME$
                        ModuleName = Trim$(ModuleName)
                        InstrResNT = InStr(1, ModuleName, ProcessName, vbTextCompare)
                        If InstrResNT > 2 Then
                            lret = TerminateProcess(hProcess, 0&)
                        End If
                        'List1.AddItem Left(ModuleName, lRet)
                    End If
                End If
                'Close the handle to the process
            lret = CloseHandle(hProcess)
    End Select
End Sub

Support functions called by main routine...

Public Function getVersion() As Long
   Dim osinfo As OSVERSIONINFO
   Dim retvalue As Integer
   osinfo.dwOSVersionInfoSize = 148
   osinfo.szCSDVersion = Space$(128)
   retvalue = GetVersionExA(osinfo)
   getVersion = osinfo.dwPlatformId
End Function

Function StrZToStr(s As String) As String
   StrZToStr = Left$(s, Len(s) - 1)
End Function

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now