Announcement

Collapse
No announcement yet.

Enumerating DLLs

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Enumerating DLLs

    I was interested to enumerate all running Exe and following code does it.
    Code:
       ' Based on HOWTO: List Running Processes ID: Q187913
       #Compile Exe
       #Dim All
       #Register None
       #Include "Win32Api.Inc"
    
       Global hDlg As Long
    
       %TH32CS_SNAPPROCESS = &H2&
    
       Type PROCESSENTRY32
          dwSize As Dword
          cntUsage As Dword
          th32ProcessID As Dword          ' This process
          th32DefaultHeapID As Long Ptr
          th32ModuleID As Dword           ' Associated exe
          cntThreads As Dword
          th32ParentProcessID As Dword    ' This process's parent process
          pcPriClassBase As Long          ' Base priority of process threads
          dwFlags As Dword
          szExeFile As Asciiz * %MAX_PATH
       End Type
       ' For 9x
       Declare Function Process32First _
          (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
       Declare Function Process32Next _
          (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
       Declare Function CreateToolhelp32Snapshot _
          (ByVal dwFlags As Dword, ByVal th32ProcessID As Dword) As Long
       ' For Nt/2000
       Declare Function EnumProcesses _
          (lpidProcess As Dword, ByVal cb As Dword, cbNeeded As Dword) As Long
       Declare Function GetModuleFileNameEx _
          (ByVal hProcess As Dword, ByVal hModule As Dword, ModuleName As Asciiz, ByVal nSize As Dword) As Dword
       Declare Function EnumProcessModules _
          (ByVal hProcess As Dword, ByRef lphModule As Dword, ByVal cb As Dword, cbNeeded As Dword) As Long
    
       Sub EnumModules
          Dim os As OSVERSIONINFO, Proc As PROCESSENTRY32
          Dim cb As Dword, cbNeeded As Dword
          Dim i As Long, j As Long, nModules As Long, nProcesses As Long, hProcess As Dword, lResult As Long
          Dim hKernel32 As Dword, hCreateToolhelp32Snapshot As Dword, hProcess32Next As Dword, hProcess32First As Dword
          Dim hPsApiDll As Dword, hEnumProcesses As Dword, hGetModuleFileNameEx As Dword, hEnumProcessModules As Dword
    
          os.dwOSVersionInfoSize = SizeOf(os)
          GetVersionEx ByVal VarPtr(os)
    
          ListBox Reset hDlg, 101
    
          If IsFalse(os.dwPlatformId = %VER_PLATFORM_WIN32_NT) Then ' Windows 95/98
             hKernel32 =  GetModuleHandle("kernel32.dll")
             hCreateToolhelp32Snapshot = GetProcAddress(hKernel32, "CreateToolhelp32Snapshot")
             hProcess32Next = GetProcAddress(hKernel32, "Process32Next")
             hProcess32First = GetProcAddress(hKernel32, "Process32First")
    
             Call Dword hCreateToolhelp32Snapshot Using _
                CreateToolhelp32Snapshot (%TH32CS_SNAPPROCESS, 0&) To i
             If i = 0 Then Exit Sub
             Proc.dwSize = SizeOf(Proc)
             Call Dword hProcess32First Using Process32First (i, Proc) To j
             While j
                ListBox Add hDlg, 101, Proc.szExeFile
                Call Dword hProcess32Next Using Process32Next (i, Proc) To j
             Wend
    
          Else ' Windows NT
             hPsApiDll = GetModuleHandle("psApi.dll")
             If hPsApiDll = 0 Then hPsApiDll = LoadLibrary("psApi.dll")
             hEnumProcesses = GetProcAddress(hPsApiDll, "EnumProcesses")
             hGetModuleFileNameEx = GetProcAddress(hPsApiDll, "GetModuleFileNameExA")
             hEnumProcessModules = GetProcAddress(hPsApiDll, "EnumProcessModules")
    
             cb = 100
             Do
                ReDim ProcessIDs(1 To cb / 4) As Dword
                Call Dword hEnumProcesses Using EnumProcesses (ProcessIDs(1), cb, cbNeeded) To lResult
                If cb > cbNeeded Then Exit Do
                cb = cb * 2
             Loop
             nProcesses = cbNeeded / 4
    
             For i = 1 To nProcesses
                hProcess = OpenProcess(%PROCESS_QUERY_INFORMATION Or %PROCESS_VM_READ, %False, ProcessIDs(i))
                If hProcess <> 0 Then
                   cb = 100
                   Do
                      ReDim Modules(1 To cb / 4) As Dword
                      Call Dword hEnumProcessModules Using _
                         EnumProcessModules (hProcess, Modules(1), cb, cbNeeded) To lResult
                      If lResult = 0 Then cbNeeded = 0: Exit Do
                      If cb > cbNeeded Then Exit Do Else cb = cb * 2
                   Loop
                   nModules = cbNeeded / 4
                   For j = 1 To nModules
                      Call Dword hGetModuleFileNameEx Using GetModuleFileNameEx _
                         (hProcess, Modules(j), Proc.szExeFile, SizeOf(Proc.szExeFile)) To lResult
                      If lResult Then If j = 1 Then ListBox Add hDlg, 101, Proc.szExeFile Else _
                                                     ListBox Add hDlg, 101, "    " + Proc.szExeFile
                   Next
                   CloseHandle hProcess
                End If
             Next
          End If
       End Sub
    
       CallBack Function DlgProc
          Select Case CbMsg
             Case %WM_INITDIALOG
                EnumModules
             Case %WM_SIZE
                Dim rc As RECT
                GetClientRect CbHndl, rc
                SetWindowPos GetDlgItem(CbHndl, 101), 0, _
                   0.03 * rc.nRight, 0.02 * rc.nBottom, 0.94 * rc.nRight, _
                   0.96 * rc.nBottom, %SWP_NOACTIVATE Or %SWP_NOZORDER
          End Select
       End Function
    
       Function PbMain
          Dialog New 0, "Processes and modules", , , 400, 200, _
             %WS_SYSMENU Or %WS_CAPTION Or %WS_THICKFRAME, To hDlg
          Control Add ListBox, hDlg, 101, , 0, 0, 0, 0, %WS_CHILD Or %WS_VSCROLL, %WS_EX_CLIENTEDGE
          Dialog Show Modal hDlg Call DlgProc
       End Function
    But I found, that under NT/2000 it's possible to retrieve also DLL's list.
    I thought that this knowledge can be useful, for example, to detect "gifts" in own process.
    Somebody knows how to retrieve the DLL's list under 9x ?
    (it's not very important and I already solved initial task, but interesting ...)

    ------------------


    [This message has been edited by Semen Matusovski (edited August 01, 2000).]

    #2
    Semen,

    very nice code. But to run it under NT you should make the fct
    calls to Process32First and Process32Next indirect. Both are
    not part of WinNt kernel32.dll.

    Ralph

    ------------------

    Comment


      #3
      Ralph --
      >> very nice code.
      Agree, in MSDN there are enough interesting pieces.
      I wanted to correct a fragment, which searches duplicate instance of Exe.
      Instead of unusful message - "this is a duplicate instance", much better to transfer control to top-level window of first instance.
      To do this, it's necessary to add EnumWindows + GetWindowThreadProcessId.

      >> But to run it under NT you should make the fct calls to Process32First and Process32Next indirect. Both are
      not part of WinNt kernel32.dll.

      It's not a problem. My main OS is Win2000 and fragment, posted above, was tested, first of all, under Y2K.
      If do not call a function - under NT program doesn't call Process32First/Process32Next - no problems (because DLL is exist).

      Functions in PSAPI.DLL is another question. 9x doesn't have this DLL and program doesn't start, if to use
      Code:
      Declare ... Lib ... Alias
      By the way, a suggesstion for further releases - to do like in VB, which resolves a reference, when you call a function only.
      Or PB can simply set error code.

      It's possible to avoid wrong situation (LoadLibrary ...), but very not comfortable.

      ------------------

      Comment


        #4
        Semen,

        it seems W2K and WinNt ( i use NT 4 SP 6 ) are loading DLL's
        in a different way. Tried your code and got the err msg:
        procedure entry point "process32first" could not be found
        in "kernel32.dll"

        Ralph



        ------------------

        Comment


          #5
          Semen,

          with the minor changes below your code runs on NT4 and W98 to.

          Code:
          '/* proto */
          ' same DECLARE for Process32First and Process32Next
          DECLARE FUNCTION Process32(BYVAL hSnapshot AS LONG, lppe AS PROCESSENTRY32) AS LONG
          DECLARE FUNCTION EnumProcesses(lpidProcess AS DWORD, BYVAL cb AS DWORD, cbNeeded AS DWORD) AS LONG
          DECLARE FUNCTION GetModuleFileNameEx(BYVAL hProcess AS DWORD, BYVAL hModule AS DWORD, ModuleName AS ASCIIZ, BYVAL nSize AS DWORD) AS DWORD
          DECLARE FUNCTION EnumProcessModules(BYVAL hProcess AS DWORD, BYREF lphModule AS DWORD, BYVAL cb AS DWORD, cbNeeded AS DWORD) AS LONG
          DECLARE FUNCTION CreateToolhelp32Snapshot(BYVAL dwFlags AS DWORD, BYVAL th32ProcessID AS DWORD) AS LONG
          changes in false branch of EnumModules

          Code:
                  DIM f AS LONG, sname AS STRING
                   DIM hSnap AS LONG, proc AS PROCESSENTRY32
          
                   LOCAL hProcess32First AS DWORD, hProcess32Next AS DWORD, CrToolhlp32Snp AS DWORD, hKernelDll AS DWORD
                   '' no err check for hKernelDll it's always loaded
                   hKernelDll      = GetModuleHandle("kernel32.dll")
                   CrToolhlp32Snp  = GetProcAddress(hKernelDll, "CreateToolhelp32Snapshot")
                   CALL DWORD CrToolhlp32Snp USING CreateToolhelp32Snapshot(%TH32CS_SNAPPROCESS, 0) TO hSnap
                   IF ISFALSE hSnap THEN EXIT SUB
                   hProcess32First = GetProcAddress(hKernelDll, "Process32First")
                   hProcess32Next  = GetProcAddress(hKernelDll, "Process32Next")
                   proc.dwSize     = LEN(proc)
                   CALL DWORD hProcess32First USING Process32 (hSnap, proc) TO f
                   DO WHILE f
                      LISTBOX ADD hDlg, 101, proc.szExeFile
                      CALL DWORD hProcess32Next USING Process32 (hSnap, proc) TO f
                   LOOP
          Ralph


          ------------------

          Comment


            #6
            Ralph --
            Thanks, that you pointed this fact. A code is re-posted.

            I understood "difference" between NT4 and Win2000.
            In Win2000' kernel32.dll there are functions Process32... and CreateSnap...
            What they are doing here ?
            Hmm .. Interesting, it's necessary to investigate.

            [This message has been edited by Semen Matusovski (edited August 01, 2000).]

            Comment


              #7
              1) There are reasons to think, that Process32... works under Win2000.
              2) I constructed a function, which activates first instance.

              Code:
                 ' Based on HOWTO: List Running Processes ID: Q187913
                 #Compile Exe
                 #Dim All
                 #Register None
                 #Include "Win32Api.Inc"
              
                 '=============================== INC ==============================
                 %TH32CS_SNAPPROCESS = &H2&
                 Type PROCESSENTRY32
                    dwSize As Dword
                    cntUsage As Dword
                    th32ProcessID As Dword          ' This process
                    th32DefaultHeapID As Long Ptr
                    th32ModuleID As Dword           ' Associated exe
                    cntThreads As Dword
                    th32ParentProcessID As Dword    ' This process's parent process
                    pcPriClassBase As Long          ' Base priority of process threads
                    dwFlags As Dword
                    szExeFile As Asciiz * %MAX_PATH
                 End Type
                 ' For 9x
                 Declare Function Process32First _
                    (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
                 Declare Function Process32Next _
                    (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
                 Declare Function CreateToolhelp32Snapshot _
                    (ByVal dwFlags As Dword, ByVal th32ProcessID As Dword) As Long
                 ' For Nt/2000
                 Declare Function EnumProcesses _
                    (lpidProcess As Dword, ByVal cb As Dword, cbNeeded As Dword) As Long
                 Declare Function GetModuleFileNameEx _
                    (ByVal hProcess As Dword, ByVal hModule As Dword, ModuleName As Asciiz, ByVal nSize As Dword) As Dword
                 Declare Function EnumProcessModules _
                    (ByVal hProcess As Dword, ByRef lphModule As Dword, ByVal cb As Dword, cbNeeded As Dword) As Long
              
                 Global hWndOfDuplicateInstance As Long
              
                 Function EnumWindowsProc (ByVal hwnd As Long, ByVal lParam As Dword) As Long
                    Dim cProcessId As Long
                    GetWindowThreadProcessId hwnd, cProcessId
                    If lParam = cProcessId Then Function = %False: hWndOfDuplicateInstance = hWnd Else _
                       Function = %True
                 End Function
              
                 Declare Function SwitchToThisWindow(hWnd As Long, chState As Long) As Long
              
                 Sub pSetForegroundWindow(hwnd As Long)
                    Dim hSwitchToThisWindow As Dword, lResult As Long
                    Dim lForeThreadID As Long, lThisThreadID As Long, hWndF As Long
                    hSwitchToThisWindow = GetProcAddress(GetModuleHandle("user32.dll"), "SwitchToThisWindow")
                    Do
                       If IsIconic(hwnd) Then ShowWindow hwnd, %SW_RESTORE Else ShowWindow hwnd, %SW_SHOW
                       SetForegroundWindow hwnd: Sleep 1
                       hWndF = GetForegroundWindow: If hwnd = hWndF Then Exit Sub
                       lForeThreadID = GetWindowThreadProcessId(hWndF, ByVal 0&)
                       lThisThreadID = GetWindowThreadProcessId(hwnd, ByVal 0&)
                       If lForeThreadID <> lThisThreadID Then _
                          AttachThreadInput lForeThreadID, lThisThreadID, %True
                       SetForegroundWindow hwnd: Sleep 1
                       If lForeThreadID <> lThisThreadID Then _
                          AttachThreadInput lForeThreadID, lThisThreadID, %False
                       hWndF = GetForegroundWindow: If hwnd = hWndF Then Exit Sub
                       Call Dword hSwitchToThisWindow Using SwitchToThisWindow(hwnd, %True) To lResult: Sleep 1
                       hWndF = GetForegroundWindow: If hwnd = hWndF Then Exit Sub
                       ShowWindow hWnd, %SW_MINIMIZE
                    Loop
                 End Sub
              
                 Function DuplicateInstance As Long
                    Dim os As OSVERSIONINFO, Proc As PROCESSENTRY32
                    Dim ExeName As Asciiz * %MAX_PATH, ProcessId As Dword, _
                        dExeName As Asciiz * %MAX_PATH, dProcessId As Dword
                    Dim cb As Dword, cbNeeded As Dword
                    Dim i As Long, j As Long, nModules As Long, nProcesses As Long, hProcess As Dword, lResult As Long
                    Dim hKernel32 As Dword, hCreateToolhelp32Snapshot As Dword, hProcess32Next As Dword, hProcess32First As Dword
                    Dim hPsApiDll As Dword, hEnumProcesses As Dword, hGetModuleFileNameEx As Dword, hEnumProcessModules As Dword
              
                    If IsFalse(GetModuleFileName (GetModuleHandle(ByVal 0&), Proc.szExeFile, SizeOf(Proc.szExeFile))) Then Exit Function
                    If IsFalse(GetShortPathName (Proc.szExeFile, ExeName, SizeOf(ExeName))) Then Exit Function
                    CharUpperBuff ExeName, Len(ExeName)
                    ProcessId = GetCurrentProcessId
              
                    os.dwOSVersionInfoSize = SizeOf(os)
                    GetVersionEx ByVal VarPtr(os)
              
                    If IsFalse(os.dwPlatformId = %VER_PLATFORM_WIN32_NT) Then ' Windows 95/98
                       hKernel32 =  GetModuleHandle("kernel32.dll")
                       hCreateToolhelp32Snapshot = GetProcAddress(hKernel32, "CreateToolhelp32Snapshot")
                       hProcess32Next = GetProcAddress(hKernel32, "Process32Next")
                       hProcess32First = GetProcAddress(hKernel32, "Process32First")
                       Call Dword hCreateToolhelp32Snapshot Using _
                          CreateToolhelp32Snapshot (%TH32CS_SNAPPROCESS, 0&) To i
                       If i = 0 Then Exit Function
                       Proc.dwSize = SizeOf(Proc)
                       Call Dword hProcess32First Using Process32First (i, Proc) To j
                       While j
                          If Proc.th32ProcessID = ProcessId Then
                          ElseIf IsFalse(GetShortPathName (Proc.szExeFile, dExeName, SizeOf(dExeName))) Then
                          ElseIf IsFalse CharUpperBuff(dExeName, Len(dExeName)) Then
                          ElseIf ExeName = dExeName Then
                             dProcessId = Proc.th32ProcessID
                          End If
                          If dProcessId Then Exit Do
                          Call Dword hProcess32Next Using Process32Next (i, Proc) To j
                       Wend
                    Else ' Windows NT
                       hPsApiDll = GetModuleHandle("psApi.dll")
                       If hPsApiDll = 0 Then hPsApiDll = LoadLibrary("psApi.dll")
                       hEnumProcesses = GetProcAddress(hPsApiDll, "EnumProcesses")
                       hGetModuleFileNameEx = GetProcAddress(hPsApiDll, "GetModuleFileNameExA")
                       hEnumProcessModules = GetProcAddress(hPsApiDll, "EnumProcessModules")
                       cb = 100
                       Do
                          ReDim ProcessIDs(1 To cb / 4) As Dword
                          Call Dword hEnumProcesses Using EnumProcesses (ProcessIDs(1), cb, cbNeeded) To lResult
                          If cb > cbNeeded Then Exit Do
                          cb = cb * 2
                       Loop
                       nProcesses = cbNeeded / 4
                       For i = 1 To nProcesses
                          hProcess = OpenProcess(%PROCESS_QUERY_INFORMATION Or %PROCESS_VM_READ, %False, ProcessIDs(i))
                          If hProcess <> 0 Then
                             cb = 100
                             Do
                                ReDim Modules(1 To cb / 4) As Dword
                                Call Dword hEnumProcessModules Using _
                                   EnumProcessModules (hProcess, Modules(1), cb, cbNeeded) To lResult
                                If lResult = 0 Then cbNeeded = 0: Exit Do
                                If cb > cbNeeded Then Exit Do Else cb = cb * 2
                             Loop
                             nModules = cbNeeded / 4
                             ' Exe is first
                             Call Dword hGetModuleFileNameEx Using GetModuleFileNameEx _
                                (hProcess, Modules(1), Proc.szExeFile, SizeOf(Proc.szExeFile)) To lResult
                             If IsFalse(lResult) Then
                             ElseIf ProcessIDs(i) = ProcessId Then
                             ElseIf IsFalse(GetShortPathName (Proc.szExeFile, dExeName, SizeOf(dExeName))) Then
                             ElseIf IsFalse CharUpperBuff(dExeName, Len(dExeName)) Then
                             ElseIf ExeName = dExeName Then
                                dProcessId = ProcessIDs(i)
                             End If
                          End If
                          CloseHandle hProcess
                          If dProcessId Then Exit For
                       Next
                    End If
                    If IsFalse(dProcessId) Then Exit Function
                    EnumWindows CodePtr(EnumWindowsProc), dProcessId
                    If IsFalse(hWndOfDuplicateInstance) Then Exit Function
                    pSetForegroundWindow hWndOfDuplicateInstance
                    Function = %True
                 End Function
              
                 '=======================================================================
                 Function PbMain
                    If DuplicateInstance Then Exit Function
              
                    Local hDlg As Long
                    Dialog New 0, "Processes and modules", , , 400, 200, _
                       %WS_SYSMENU Or %WS_CAPTION Or %WS_MINIMIZEBOX, To hDlg
                    Control Add TextBox, hDlg, 101, "", 10, 10, 380, 180, _
                       %ES_MULTILINE Or %ES_WANTRETURN, %WS_EX_CLIENTEDGE
                    Dialog Show Modal hDlg
                 End Function
              Warning: it's not final code.

              You can test this code by starting one instance in IDE and another in Explorer.

              What I don't like ... Sometimes a text within textbox is selected.

              Somebody saw non-classic methods to activate ceirtain window ?
              For example, by imitation mouse click on caption/task bar and so on ...


              ------------------


              [This message has been edited by Semen Matusovski (edited August 02, 2000).]

              Comment


                #8
                Semen,

                Very impressive, but why didn't you use BringWindowToTop hWnd ?
                I thought it would be a bit easier to use.

                Peter.


                ------------------
                [email protected]

                Comment


                  #9
                  Peter --
                  BringWindowToTop is subset of SetWindowPos and does nothing in this situation under 98/2000.

                  For whome is interesting.
                  A list of rectrictions for SetForegroundWindow under Windows 98, Windows 2000: (MSDN)

                  The system restricts which processes can set the foreground window.
                  A process can set the foreground window only if one of the following conditions is true:

                  The process is the foreground process.
                  The process was started by the foreground process.
                  The process received the last input event.
                  There is no foreground process.
                  The foreground process is being debugged.
                  The foreground is not locked (see LockSetForegroundWindow).
                  The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
                  Windows 2000: No menus are active.
                  With this change, an application cannot force a window to the foreground while the user is working with another window.
                  Instead, SetForegroundWindow will activate the window (see SetActiveWindow) and call the FlashWindowEx function to notify the user.


                  About 95 - probably, does something, but here SetForegroundWindow exactly works.


                  ------------------


                  [This message has been edited by Semen Matusovski (edited August 02, 2000).]

                  Comment

                  Working...
                  X
                  😀
                  🥰
                  🤢
                  😎
                  😡
                  👍
                  👎