VS创建和加载动态库

    科技2022-08-14  96

    VS创建和加载动态库

    一、动态库使用的优点:

    1.使资源数据独立于可执行程序之外,但又能较方便快速地访问它。 2.节省内存并减少页面交换。 3.大型软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。 4.保护自己的知识产权,与第三方合作时,只提供库,不用给源码。 ......

    二、创建动态链接库

    1.打开VS:“文件”-“新建”-“项目” 2.打开:“已安装”-“模板”-“Visual C++”-“Win32”-“Win32 控制台应用程序” 把文件“名称”加上,为自己的工程名称;把“位置”加上,为自己的工程所在位置; 3.点击:“下一步” 4.选择“DLL”和“空项目”,然后点击“完成” 5.新建头文件和源文件,如:“MyDll.h”、“MyDll.cpp”: 6.在MyDll.h里添加: #pragma once #include <iostream> #include <vector> #define DLL_API __declspec(dllexport) typedef void(*funCallBack)(std::vector<int> &_data); //外部调用接口 extern "C" DLL_API void Dll_Void_Fun(); extern "C" DLL_API int Dll_Int_Fun(int a, int b); funCallBack m_callBackFun = nullptr; //回调接口,主动通知外部程序 extern "C" DLL_API void Dll_CallBack_Fun(funCallBack pfunc); //创建模拟数据 void makeSimulateData(); //数据创建线程函数 void makeDataThread(); 7.在MyDll.cpp里添加: #include "MyDll.h" #include <thread> #include <mutex> void Dll_Void_Fun() { std::cout << "void dll func called" << std::endl; } int Dll_Int_Fun(int a, int b) { std::cout << "int dll func called" << std::endl; return a + b; } void Dll_CallBack_Fun(funCallBack pfunc) { m_callBackFun = pfunc; makeSimulateData(); //创建模拟数据 } void makeSimulateData() { //创建数据线程 std::thread data_thread(makeDataThread); data_thread.join(); } //创建数据线程,创建模拟数据,回调通知外部程序 void makeDataThread() { while (1) { std::vector<int> SimulateDataVector; SimulateDataVector.push_back(0); SimulateDataVector.push_back(1); if(SimulateDataVector.size() != 0) { std::mutex m_mutex; std::lock_guard<std::mutex> locker(m_mutex); m_callBackFun(SimulateDataVector); //执行回调 } std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //每隔1000ms通知一次 } } 7.生成解决方案,找到生成的dll,查看接口是否生成正确,打开vs工具命令提示符 8.cd到dll生成目录,运行dumpbin -exports MyDll.dll(对应的dll),红色框内就是生成的接口,至此dll生成完成。 9.示例程序说明:总共3个接口,其中2个接口用于外部调用,另外一个接口是回调,也就是将外部函数的地址作为参数传递进来,定义一个函数指针指向它,一有数据就调用它,然后就会调用外部函数,以实现回调,这样输入输出就都有了。

    三、应用动态链接库

    1.新建项目,win32控制台应用程序,点击:“下一步”,选择控制台应用程序,点击完成 2.在main.cpp里添加: #include "stdafx.h" #include <iostream> #include <windows.h> #include <vector> typedef void(*func_void)(); typedef int(*func_int)(int a, int b); typedef void(*funCallBack)(std::vector<int> &_data); typedef void(*func_call_back)(funCallBack func); //dll回调 void callBack(std::vector<int> &_data) { std::cout << "dll call back" << std::endl; for (auto var : _data) { std::cout << var << std::endl; } } int main() { func_void m_func_void = nullptr; func_int m_func_int = nullptr; func_call_back m_func_call_back = nullptr; HMODULE h_module = LoadLibrary(L"MyDll.dll"); //加载dll DWORD errorid = GetLastError(); //获取错误,返回0就是没有错误 if (h_module) { //函数指针指向dll的函数名(函数的地址) m_func_void = (func_void)GetProcAddress(h_module, "Dll_Void_Fun"); m_func_int = (func_int)GetProcAddress(h_module, "Dll_Int_Fun"); m_func_call_back = (func_call_back)GetProcAddress(h_module, "Dll_CallBack_Fun"); } else { std::cout << "dll加载失败"; } if (m_func_void&&m_func_int&&m_func_call_back) { //调用dll接口 m_func_void(); int sum = m_func_int(3, 4); std::cout << "sum is " << sum; m_func_call_back(callBack); //注册回调接口 } getchar(); return 0; } 3.生成解决方案,运行。

    四、动态链接库的调用与回调理解(自己理解的,仅供参考)

    简单理解,调用就是将函数的地址暴露给外部程序,外部程序定义函数指针指定对应函数地址实现调用, 回调就是将函数的地址暴露给外部程序的同时,将外部程序的函数地址作为参数传递进来,定义函数指针 指向该地址,这样在调用时就会找到外部程序的地址调用外部程序,把需要传递的数据作为参数传递出去 实现回调。调用就是外部程序调用dll内的函数,回调是调用dll内的函数的同时将自身的某个函数地址作为 参数传递进去,让dll内部调用。
    Processed: 0.028, SQL: 8