【实战】如何在完全缺失头文件的情况下直接操作DLL

1. 引言:情况介绍

在常见的软件开发场景中,我们通常需要配套:

  • .lib 文件(静态链接文件)
  • .h 文件(头文件)

然而,实际工程中,有时只有 DLL 文件,没有配套头文件和静态库。 如果我们还想调用其中的函数,就需要自己动手来控制。

2. 技术基础:DLL 动态调用原理

一个 DLL 文件里包含了多个函数,其中通过 Export Table ( 导出表 ) 记录了函数名和地址。

进行调用的步骤:

  1. 使用 LoadLibraryA("xxx.dll"),把 DLL 加载到内存

  2. 使用 GetProcAddress(hDll, "FuncName"),根据函数名找到实际地址

【描述描述描述:DLL 动态调用流程】

[程序运行] 
   ↓
[加载 DLL: LoadLibraryA]
   ↓
[获取函数地址: GetProcAddress]
   ↓
[将地址转成函数指针]
   ↓
[正常调用函数]

注意:GetProcAddress 返回的是通用指针(void*),需要将其转成正确的函数指针类型!

3. 操作示例:无 .lib/.h 情况下调用 DLL

3.1 加载 DLL

#include <windows.h>
#include <iostream>

HMODULE hDll = LoadLibraryA("MyDriver.dll");
if (!hDll) {
    std::cerr << "LoadLibrary failed!" << std::endl;
    return -1;
}

3.2 解析函数

FARPROC funcAddress = GetProcAddress(hDll, "FunctionName");
if (!funcAddress) {
    std::cerr << "GetProcAddress failed!" << std::endl;
    return -1;
}

3.3 将地址转成函数指针

假设我们知道该函数类型:

typedef int (*MyFuncType)(int, int);

则可以:

MyFuncType myFunc = reinterpret_cast<MyFuncType>(funcAddress);
int result = myFunc(1, 2);
std::cout << "Result: " << result << std::endl;

4. 不知道函数类型怎么办?

  • 请厂商提供 API 文档,最简单也最稳健
  • 用 dumpbin /exports 或 Dependencies 查看导出的函数名

 

  • 后续实验:
    • 先从无参数函数或简单基础类型开始测试
    • 每次仅仅调用最基础操作,避免引起崩溃

5. 高级技巧:自定义的 DLL 加载器

可以封装成一个简单的类:

class DynamicDll {
public:
    DynamicDll(const char* dllPath) {
        hModule_ = LoadLibraryA(dllPath);
        if (!hModule_) throw std::runtime_error("Failed to load DLL");
    }

    ~DynamicDll() {
        if (hModule_) FreeLibrary(hModule_);
    }

    template<typename T>
    T loadFunction(const char* funcName) {
        FARPROC addr = GetProcAddress(hModule_, funcName);
        if (!addr) throw std::runtime_error("Function not found");
        return reinterpret_cast<T>(addr);
    }

private:
    HMODULE hModule_;
};

使用示例:

DynamicDll dll("MyDriver.dll");
auto myFunc = dll.loadFunction<int(*)(int, int)>("FunctionName");
int result = myFunc(1, 2);

6. 常见问题总结

问题 可能原因 解决办法
LoadLibrary  DLL 路径错误,或 DLL 缺少依赖库 检查路径,用 Dependency Walker
GetProcAddress  函数名写错,大小写敏感 检查导出名单,确认正确名称
调用时崩溃 函数类型猜错,参数传递不对 根据文档确定正确类型

7. 结论

即使没有 .lib 和 .h,我们也可以使用:

  • LoadLibrary 把 DLL 加载到内存
  • GetProcAddress 找到函数地址
  • 正确转类后调用函数
阅读剩余
THE END