如何查找加载程序 DLL 的路径

How to find path of loader DLL?

本文关键字:程序 DLL 路径 加载 何查找 查找      更新时间:2023-10-16

我想读取我的DLL的加载器DLL的二进制文件。但是有一个exe和2个DLL,我使用第一个(X DLL)来加载第二个(Y DLL)。当我通过 exe 从 X DLL 加载 Y dll 时,GetModuleFileNameA(NULL, szEXEPath, 2048);函数只给我 exe 路径。我想获取 X DLL 路径。我可以使用GetModuleFileNameA("X DLL Name", szEXEPath, 2048);但我不知道X DLL的名称。

当我阅读 MSDN 帮助以获取GetModuleFileName时,我在下面看到了有关函数的第一个参数的描述。

正在请求其路径的已加载模块的句柄。如果这个 参数为 NULLGetModuleFileName检索 当前进程的可执行文件。

不想获取可执行文件的路径,我只想确定哪个 DLL 加载我当前的 DLL。有没有办法找到加载程序路径 DLL?

若要获取"父"dll 的名称,可以创建一个函数作为需要调用的 API 的一部分,该函数传入父 dll 的HMODULE句柄。

将下面的 get_current_module_handle() 函数创建为inline并将其包装成某种宏将简化客户端代码的过程。

//... control header
inline HMODULE get_current_module_handle() {/*...*/}
#define PARENT_MODULE get_current_module_handle()
void SetControlParent(HMODULE parent);
//... client code to initialise the "parent"
SetControlParent(PARENT_MODULE);

若要获取 dll 名称(在子项中),可以使用 GetModuleFileNameExGetModuleHandleEx 函数的组合。诀窍在于GetModuleHandleEx函数,它允许通过指向函数(即 dll 中的函数)的指针获取模块句柄;特别是旗帜的使用GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS.

以下是一些应该可以解决问题的代码片段;

HMODULE get_current_module_handle()
{
    HMODULE moduleHandle = NULL;
    if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        (LPCTSTR)get_current_module_handle, &moduleHandle))
        throw std::runtime_error("unable to get the module handle");
    return moduleHandle;
}
std::basic_string<TCHAR> get_module_name(HMODULE moduleHandle)
{
    std::vector<TCHAR> filename(2048, _T('?')); // allocate some space
    DWORD filenameLength = ::GetModuleFileNameEx(::GetCurrentProcess(), moduleHandle, &filename.front(), filename.size());
    if (filenameLength && filenameLength < filename.size()) {
        return std::basic_string<TCHAR>(&filename.front(), filenameLength);
    }
    return std::basic_string<TCHAR>(_T("unknown"));
}
//...
std::basic_string<TCHAR> dllname = get_module_name(get_current_module_handle()); // current dll
std::basic_string<TCHAR> parentdllname = get_module_name(parentHModule); // for "parent" dll

请注意,上面复制了一个简化版本(基于 OP 中的 2048 长度)。还介绍了一个递归实现来考虑长文件名(检查编辑)。

dllname将是模块的完全限定路径,因此要获取基本文件名,例如_splitpath .或者,您可以直接在上面的代码中使用GetModuleBaseName

std::basic_string<TCHAR> get_module_name(HMODULE moduleHandle)
{
    std::vector<TCHAR> filename(MAX_PATH, _T('?')); // MAX_PATH is 260
    DWORD filenameLength = ::GetModuleBaseName(::GetCurrentProcess(), moduleHandle, &filename.front(), filename.size());
    if (filenameLength && filenameLength < filename.size()) {
        return std::basic_string<TCHAR>(&filename.front(), filenameLength);
    }
    return std::basic_string<TCHAR>(_T("unknown"));
}

您可以使用 dllpath 函数定义自己的路径,并将其作为参数传递给链接的路径。