使用MinGW GCC 创建拥有 __stdcall 方式的 DLL动态链接库

本文详细介绍了如何通过预编译、链接等步骤创建DLL文件及相应的lib库文件,并特别强调了-Wl,--kill-at参数的作用。同时指出Eclipse CDT环境下查看DLL接口的方法。

    被这个问题困扰了两天,才在网上找到解决方法

 

 

    案例:test.c

    编译步骤:
1、预编译成object file,获得test.o
gcc -c -DTEST_EXPORT test.c
2、链接object file为dll文件,并输出def文件
gcc -shared -o test.dll test.o -Wl,--kill-at -Wl,--output-def,test.def
3、根据dll文件和def文件创建lib库文件
dlltool -d test.def --dllname test.dll --output-lib test.lib --kill-at

 

 

    这几步里,最关键的就是-Wl,--kill-at,它的功能就是删除所有@[n]输出的名称,这样就能被LoadLibrary和GetProcAddress调用,不过即使这样eclipse with CDT也无法查看接口,只有__cdcel方式的接口能被eclipse with CDT看到

在 Python 中运行 `.dll`(动态链接库)文件,通常使用的是 `ctypes` 模块。`ctypes` 是 Python 标准库中用于调用 C 语言函数的模块,可以加载 `.dll` 文件并调用其中的函数。 --- ## ✅ 一、基本步骤 ### 1. 加载 `.dll` 文件 ```python import ctypes # 加载 DLL(注意路径) my_dll = ctypes.CDLL('path_to_dll.dll') ``` 也可以使用 `WinDLL` 来加载,适用于 Windows 平台的调用约定(如 `stdcall`): ```python my_dll = ctypes.WinDLL('path_to_dll.dll') ``` --- ### 2. 调用 DLL 中的函数 假设你的 DLL 中有如下函数: ```c // dllmain.c #include <windows.h> extern "C" __declspec(dllexport) int add(int a, int b) { return a + b; } ``` 在 Python 中调用: ```python result = my_dll.add(5, 7) print("结果:", result) # 输出 12 ``` --- ### 3. 设置函数参数和返回类型(推荐) 为了确保类型安全,建议设置函数的参数类型和返回值类型: ```python my_dll.add.argtypes = [ctypes.c_int, ctypes.c_int] my_dll.add.restype = ctypes.c_int ``` --- ## ✅ 二、完整示例 ### 1. C/C++ 编写 DLL使用 MinGW 编译) ```c // add.c #include <stdio.h> int add(int a, int b) { return a + b; } ``` 编译为 DLL: ```bash gcc -shared -o add.dll add.c ``` ### 2. Python 调用代码 ```python import ctypes # 加载 DLL add_dll = ctypes.CDLL('./add.dll') # 设置函数签名 add_dll.add.argtypes = [ctypes.c_int, ctypes.c_int] add_dll.add.restype = ctypes.c_int # 调用函数 res = add_dll.add(10, 20) print("调用 DLL 函数结果:", res) ``` --- ## ✅ 三、常见问题与解决方法 ### ❗ 1. 无法加载 DLL(`OSError: [WinError 126] 找不到指定的模块`) - **原因**:DLL 路径错误,或依赖的其他 DLL 缺失。 - **解决**: - 确保路径正确; - 使用 `Dependency Walker` 或 `Process Monitor` 检查依赖项。 ### ❗ 2. 调用函数时报错(如 `AttributeError`) - **原因**:函数名拼写错误或未正确导出。 - **解决**: - 使用 `dumpbin /exports add.dll` 查看导出函数名; - 确保 C/C++ 中使用了 `__declspec(dllexport)` 和 `extern "C"`。 --- ## ✅ 四、进阶:调用带有指针、结构体的函数 ### 示例:C 函数处理结构体 ```c typedef struct { int x; int y; } Point; extern "C" __declspec(dllexport) void move_point(Point* p, int dx, int dy) { p->x += dx; p->y += dy; } ``` ### Python 调用: ```python class Point(ctypes.Structure): _fields_ = [("x", ctypes.c_int), ("y", ctypes.c_int)] move_point = add_dll.move_point move_point.argtypes = [ctypes.POINTER(Point), ctypes.c_int, ctypes.c_int] move_point.restype = None p = Point(10, 20) move_point(p, 5, 5) print(f"Point moved to ({p.x}, {p.y})") # 输出 (15, 25) ``` --- ## ✅ 五、总结 | 步骤 | 工具 | 说明 | |------|------|------| | 编写 DLL | C/C++ | 使用 `__declspec(dllexport)` 导出函数 | | 编译 DLL | MinGW / MSVC | `gcc -shared` 或 Visual Studio | | 加载 DLL | `ctypes.CDLL` / `WinDLL` | Python 中加载 DLL | | 调用函数 | `dll.func(...)` | 注意设置 `argtypes` 和 `restype` | | 调试 DLL | `dumpbin`, `Dependency Walker` | 检查导出函数和依赖 | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值