您好,欢迎来到意榕旅游网。
搜索
您的当前位置:首页[C++]如何动态加载DLL

[C++]如何动态加载DLL

来源:意榕旅游网

实际流程

1.动态加载动态库

LoadLibrary("xxxx.dll")	// 宏函数 依据项目定义字符格式决定函数版本
LoadLibraryA("xxxx.dll")// 窄字符版本
LoadLibraryW("xxxx.dll")// 宽字符版本

该函数返回模块句柄.

类型:HINSTANCE
本质是个结构体,里面包含一个int类型变量.
可以使用HMODULE来替换

或使用auto

例子1:

HINSTANCE MyModule{ LoadLibraryA("MyCode.dll") };	//倘若该对象内模块地址不会改变可以加const修饰

例子2:

HMODULE MyModule{ LoadLibraryA("MyCode.dll") };		//倘若该对象内模块地址不会改变可以加const修饰

例子3:

auto MyModule{ LoadLibraryA("MyCode.dll") };		//倘若该对象内模块地址不会改变可以加const修饰

2.获取导出函数地址

GetProcAddress(模块句柄, "导出函数名")

3.通过导出函数地址进行调用

int Add(int,int)

调用原理:

(int(*)(int,int))(导出函数地址)(参数1,参数2);

4.伪代码

例子1:

if (const auto MyModule{ LoadLibraryA("MyCode.dll") })
    {
        void* IntegerAdd{ GetProcAddress(MyModule, "IntegerAdd") };   
        void* DoubleAdd{ GetProcAddress(MyModule,"DoubleAdd") };                
        std::cout << static_cast<int(*)(int, int)>(IntegerAdd)(500, 123);          
        std::cout << std::endl;
        std::cout << static_cast<double(*)(double, double)>(DoubleAdd)(123.321, 123.321);
        FreeLibrary(MyModule);
    }

例子2:

if (const auto MyModule{ LoadLibraryA("MyCode.dll") })
    {
        std::cout << reinterpret_cast<int(*)(int, int)>(GetProcAddress(MyModule, "IntegerAdd"))(1, 2);
        std::cout << std::endl;
        std::cout << reinterpret_cast<double(*)(double, double)>(GetProcAddress(MyModule, "DoubleAdd"))(1., 2.);
        FreeLibrary(MyModule);
    }

例子3:

if (const auto MyModule{ LoadLibraryA("MyCode.dll") })
    {
        int(*IntegerAdd)(int, int) { reinterpret_cast<int(*)(int, int)>(GetProcAddress(MyModule, "IntegerAdd")) };
        double(*DoubleAdd)(double, double) { reinterpret_cast<double(*)(double, double)>(GetProcAddress(MyModule, "DoubleAdd")) };
        std::cout << IntegerAdd(1, 2);
        std::cout << std::endl;
        std::cout << DoubleAdd(1., 2.);
        FreeLibrary(MyModule);
    }
if (const auto MyModule{ LoadLibraryA("MyCode.dll") })
    {
        const auto IntegerAdd {reinterpret_cast<int(*)(int, int)>(GetProcAddress(MyModule, "IntegerAdd")) };
        const auto DoubleAdd { reinterpret_cast<double(*)(double, double)>(GetProcAddress(MyModule, "DoubleAdd")) };
        std::cout << IntegerAdd(1, 2);
        std::cout << std::endl;
        std::cout << IntegerAdd(55, 2);
        std::cout << std::endl;
        std::cout << DoubleAdd(1., 2.);
        FreeLibrary(MyModule);
    }

额外-关于函数调用

#include <iostream>

void 我是一个函数()
{
    std::cout << "很抱歉以这种方式认识你" << std::endl;
}

int main()
{
    void* 我是函数地址{ static_cast<void*>(&我是一个函数) };
    static_cast<void(*)()>(我是函数地址)();	// 我现在等价于函数,并且被调用
    return 0;
}

这是完全合法0error(s)0warning(s),在编译器(计算机)眼中很合理的代码


警告!
本文中出现使用static_cast和reinterpret_cast在对象指针和函数指针间进行转换是微软扩展语法
该语法本身未定义.
请不要在多系统兼容项目中使用,不保证任何兼容性,也不保证在非MSVC编译器中合法
为保障通用性,请使用C风格转换


动态加载DLL原理

1.将DLL加载到目标进程虚拟内存空间

加载
动态库
进程内存空间

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务