RT
本文记录使用C封装动态库dll,并使用C++、Qt及C#进行dll库的显式调用方式。
C语言封装dll与C++有不同,只做记录。文章包含dll项目源码与C++调用方式及Qt调用方式。
本文项目使用VS2019编译。项目地址:https://github.com/LisonLiou/dll_master
1. C语言dll项目master.h与master.c文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // master.h #ifndef MASTER_H #define MASTER_H
#define MASTER_API __declspec(dllexport)
#ifdef __cplusplus extern "C" { #endif // __cplusplus
MASTER_API int divide(int param);
#ifdef __cplusplus } #endif // __cplusplus
#endif // !
|
1 2 3 4 5 6 7 8
| // master.c #include "master.h"
int divide(int param) { return param / 2; }
|
2. C++调用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> #include <Windows.h> #include "cdll/master.h"
typedef int __declspec(dllimport)(*FUNC_divide)(int arg);
int main() { HINSTANCE hDll = LoadLibrary(L"cdll\\Dll_Master.dll");
if (hDll == NULL) { std::cout << "dll load failed " << GetLastError(); } else { FUNC_divide eval; eval = (FUNC_divide)GetProcAddress(hDll, "divide"); int ret = eval(13);
std::cout << "Hello World! " << ret << "\n";
FreeLibrary(hDll); } }
|
3. Qt调用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <QtCore/QCoreApplication> #include <QDebug> #include <QLibrary>
typedef int (*FUNC_divide)(int arg);
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv);
QString pathDll = "cdll/Dll_Master.dll"; QLibrary master(pathDll); if (master.load()) {
qDebug() << "ffffffffff";
FUNC_divide divide = (FUNC_divide)master.resolve("divide"); qDebug() << "Hello world "<<divide(19);
master.unload(); } else { qDebug() << "dll load failed"; }
return a.exec(); }
|
4. C#调用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| [DllImport("kernel32.dll")] private extern static IntPtr LoadLibrary(String path);//path 就是dll路径 返回结果为0表示失败。 [DllImport("kernel32.dll")] private extern static IntPtr GetProcAddress(IntPtr lib, String funcName);//lib是LoadLibrary返回的句柄,funcName 是函数名称 返回结果为0标识失败。 [DllImport("kernel32.dll")] private extern static bool FreeLibrary(IntPtr lib);
//声明委托 //[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] delegate int divide(int arg);
static void Main(string[] args) { string dllPath = Environment.CurrentDirectory + "\\cdll\\Dll_Master.dll";
IntPtr hLib = LoadLibrary(dllPath);//加载函数 IntPtr apiFunction1 = GetProcAddress(hLib, "divide");//获取函数地址
int i = Marshal.GetLastWin32Error(); if (apiFunction1.ToInt32() == 0)//0表示函数没找到 return;
//获取函数接口,相当于函数指针 divide div = Marshal.GetDelegateForFunctionPointer(apiFunction1, typeof(divide)) as divide;
Console.WriteLine(div(22));
// //释放句柄 FreeLibrary(hLib);
Console.Read(); }
|
5. dll项目生成事件之后的宏示例
用于在dll编译成功后将文件拷贝到引用dll的项目的输出路径,具体可根据情况自行编写自定义build步骤bash
1 2 3 4 5
| xcopy $(LocalDebuggerWorkingDirectory)master.h D:\repos\c\Dll_Master_Test\cdll /e/h/y/f && xcopy $(TargetPath) D:\repos\c\Dll_Master_Test\cdll /e/h/y/f && xcopy $(TargetPath) D:\repos\c\Dll_Master_TestQt\cdll /e/h/y/f && xcopy $(TargetPath) D:\repos\c\Dll_Master_TestCSharp\cdll /e/h/y/f
|
注意事项:
- dll文件存放位置需与调用方可执行文件在相同路径,具体看代码
- System.BadImageFormatException:“试图加载格式不正确的程序的解决办法 因dll是32位程序,C#调用方可能默认为x64,需要将生成的目标平台改为x86,与dll的目标平台保持一致