Attribute VB_Name = "ModGetMod"
Option Explicit
'*************************************************************************
'**模 块 名：ModGetMod
'**说    明：查询某进程所包含的模块
'**创 建 人：嗷嗷叫的老马
'**日    期：2006年06月11日
'**描    述：摘于网络.需要与ModFindProcess.bas配合.
'**版    本：V1.0
'*************************************************************************

Private Type MODULEINFO
    lpBaseOfDLL As Long
    SizeOfImage As Long
    EntryPoint As Long
End Type

Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const MAX_PATH = 260

Private Declare Function EnumProcessModules Lib "psapi.dll" (ByVal hProcess As Long, hModule As Long, ByVal cb As Long, cbNeeded As Long) As Long
Private Declare Function GetModuleBaseName Lib "psapi.dll" Alias "GetModuleBaseNameA" (ByVal hProcess As Long, ByVal hModule As Long, ByVal lpBaseName As String, ByVal nSize As Long) As Long
Private Declare Function GetModuleFileNameEx Lib "psapi.dll" Alias "GetModuleFileNameExA" (ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Public Function EnumModule(ByVal ProcName As String, ByRef sModule() As String, ByRef hModule() As Long) As Long
    '功    能：读出一个进程中所有的模块名和模块路径（第一个就是程序本身的路径）- 使用进程名称版本
    '返 回 值：暂无（大家也可以写入错误处理）
    '参    数：EnumModule(进程文件名，读出的模块数组)
    Dim lRet As Long '返回值
    Dim I As Long '循环计数器
    Dim hProcess As Long '进程标识
    Dim ModName As String '模块名
    Dim ModFilePath As String '模块路径
    Dim cbNeed As Long '偶也不知是做什么的，好像是计录进程中的模块数量cbNeed / 4
    Dim hProc As Long
    
    Call FindProcess(ProcName, hProc)
    If hProc = 0 Then Exit Function
    
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0&, hProc)
    ReDim hModule(1) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), 1, cbNeed)
    ReDim hModule(1 To cbNeed / 4) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), cbNeed, cbNeed)
    
    For I = 1 To cbNeed / 4
        If hModule(I) Then
            ModName = String(MAX_PATH, 0)
            GetModuleBaseName hProcess, hModule(I), ModName, Len(ModName)
            ModName = Left(ModName, InStr(1, ModName, Chr(0)) - 1)
            
            ModFilePath = String(MAX_PATH, 0)
            GetModuleFileNameEx hProcess, hModule(I), ModFilePath, Len(ModFilePath)
            ModFilePath = Left(ModFilePath, InStr(1, ModFilePath, Chr(0)) - 1)
            ReDim Preserve sModule(I - 1) As String
            sModule(I - 1) = ModName & "=" & ModFilePath
        End If
    Next
    CloseHandle hProcess
End Function

Public Function EnumModuleByPid(ByVal hPid As Long, ByRef sModule() As String, ByRef hModule() As Long) As Long
    '功    能：读出一个进程中所有的模块名和模块路径（第一个就是程序本身的路径）- 使用PID的版本
    '返 回 值：暂无（大家也可以写入错误处理）
    '参    数：EnumModule(进程文件名，读出的模块数组)
    Dim lRet As Long '返回值
    Dim I As Long '循环计数器
    Dim hProcess As Long '进程标识
    Dim ModName As String '模块名
    Dim ModFilePath As String '模块路径
    Dim cbNeed As Long '偶也不知是做什么的，好像是计录进程中的模块数量cbNeed / 4
    
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0&, hPid)
    ReDim hModule(1) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), 1, cbNeed)
    ReDim hModule(1 To cbNeed / 4) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), cbNeed, cbNeed)
    
    For I = 1 To cbNeed / 4
        If hModule(I) Then
            ModName = String(MAX_PATH, 0)
            GetModuleBaseName hProcess, hModule(I), ModName, Len(ModName)
            ModName = Left(ModName, InStr(1, ModName, Chr(0)) - 1)
            
            ModFilePath = String(MAX_PATH, 0)
            GetModuleFileNameEx hProcess, hModule(I), ModFilePath, Len(ModFilePath)
            ModFilePath = Left(ModFilePath, InStr(1, ModFilePath, Chr(0)) - 1)
            ReDim Preserve sModule(I - 1) As String
            sModule(I - 1) = ModName & "=" & ModFilePath
        End If
    Next
    CloseHandle hProcess
End Function

Public Function EnumModuleByhProcess(ByVal hProcess As Long, ByRef sModule() As String, ByRef hModule() As Long) As Long
    '功    能：读出一个进程中所有的模块名和模块路径（第一个就是程序本身的路径）- 使用已成功打开的hProcess版本
    '返 回 值：暂无（大家也可以写入错误处理）
    '参    数：EnumModule(进程文件名，读出的模块数组)
    Dim lRet As Long '返回值
    Dim I As Long '循环计数器
    Dim ModName As String '模块名
    Dim ModFilePath As String '模块路径
    Dim cbNeed As Long '偶也不知是做什么的，好像是计录进程中的模块数量cbNeed / 4
    
    ReDim hModule(1) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), 1, cbNeed)
    ReDim hModule(1 To cbNeed / 4) As Long
    lRet = EnumProcessModules(hProcess, hModule(1), cbNeed, cbNeed)
    
    For I = 1 To cbNeed / 4
        If hModule(I) Then
            ModName = String(MAX_PATH, 0)
            GetModuleBaseName hProcess, hModule(I), ModName, Len(ModName)
            ModName = Left(ModName, InStr(1, ModName, Chr(0)) - 1)
            
            ModFilePath = String(MAX_PATH, 0)
            GetModuleFileNameEx hProcess, hModule(I), ModFilePath, Len(ModFilePath)
            ModFilePath = Left(ModFilePath, InStr(1, ModFilePath, Chr(0)) - 1)
            ReDim Preserve sModule(I - 1) As String
            sModule(I - 1) = ModName & "=" & ModFilePath
        End If
    Next
    CloseHandle hProcess
End Function

Public Function TestFun()
    '测试过程.在立即窗口里执行本过程即可看到效果.
    Dim I() As String, J As Long, K() As Long
    
    Call EnumModule("notepad.exe", I, K())
    For J = 0 To UBound(I)
        Debug.Print I(J)
    Next
End Function
