so

so动态库是否加载如何判断

在Windows系统中,判断动态库(DLL)是否已加载到当前进程,可以通过以下几种方法实现:


方法1:使用 GetModuleHandle 函数

这是最直接高效的方法。该函数检查指定模块(DLL)是否已加载,若已加载则返回模块句柄,否则返回 NULL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <Windows.h>

bool IsDllLoaded(LPCWSTR lpDllName) {
// 检查DLL是否已加载(不触发加载)
HMODULE hModule = GetModuleHandleW(lpDllName);
return (hModule != NULL);
}

// 示例用法
int main() {
if (IsDllLoaded(L"user32.dll")) {
// DLL已加载
} else {
// DLL未加载
}
return 0;
}

特点:

  • 不改变模块引用计数:仅查询状态,不会导致DLL被加载或卸载。
  • 区分名称大小写:需确保传入的DLL名称与加载时的名称一致(通常不区分大小写,但路径需匹配)。
  • 支持路径:可传入完整路径或短名称(如 L"user32.dll")。

方法2:遍历进程已加载模块列表

如果需要获取所有已加载模块信息(如路径、基地址),可使用以下方法:

方案A:通过 EnumProcessModules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Windows.h>
#include <Psapi.h> // 需链接 Psapi.lib

bool IsDllLoaded(LPCWSTR lpDllName) {
HMODULE hModules[1024];
DWORD cbNeeded;
HANDLE hProcess = GetCurrentProcess();

// 枚举当前进程的所有模块
if (EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) {
DWORD moduleCount = cbNeeded / sizeof(HMODULE);
for (DWORD i = 0; i < moduleCount; i++) {
WCHAR szModName[MAX_PATH];
// 获取模块路径
if (GetModuleFileNameW(hModules[i], szModName, MAX_PATH)) {
// 比较DLL名称(可优化为提取文件名)
if (wcsstr(szModName, lpDllName) != NULL) {
return true;
}
}
}
}
return false;
}

方案B:通过TlHelp32快照

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <Windows.h>
#include <TlHelp32.h> // 需链接 kernel32.lib

bool IsDllLoaded(LPCWSTR lpDllName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
if (hSnapshot == INVALID_HANDLE_VALUE) return false;

MODULEENTRY32W me = { sizeof(me) };
if (Module32FirstW(hSnapshot, &me)) {
do {
if (wcscmp(me.szModule, lpDllName) == 0 || wcsstr(me.szExePath, lpDllName)) {
CloseHandle(hSnapshot);
return true;
}
} while (Module32NextW(hSnapshot, &me));
}
CloseHandle(hSnapshot);
return false;
}

特点:

  • 获取完整信息:可得到模块路径、基地址等。
  • 开销较大:需遍历模块列表,效率低于 GetModuleHandle
  • 适用复杂场景:如需要模糊匹配或批量检查。

关键注意事项

  1. 名称匹配规则
    • 若用短名称(如 "user32.dll"),需确保与加载时一致(通常不区分大小写)。
    • 若用完整路径,则需完全匹配(包括大小写和路径格式)。
  2. 静态链接的DLL
    • 静态链接的DLL在进程启动时自动加载,GetModuleHandle 可直接检测。
  3. 动态加载的DLL
    • 通过 LoadLibrary 加载的DLL,可用上述方法检测。
  4. 跨进程检测
    • 若需检测其他进程,需使用 EnumProcessModules 或TlHelp32,并具有 PROCESS_QUERY_INFORMATION 权限。

总结

  • 首选方案:使用 GetModuleHandle(简单高效,适用于精确名称匹配)。
  • 备选方案:遍历模块列表(需更多信息或模糊匹配时使用)。
  • 避免使用:尝试 LoadLibrary + FreeLibrary,这会改变引用计数且不安全。