Python中如何调用DLL文件?

我想要调用一个别人给的 dll 文件,总是出错,于是我想着写个最简单的 hello world 版的 dll 文件,调用一下,来确定我在网上找的调用代码是正确的

这是我看的制作 dll 文件的教程:http://wolfprojects.altervista.org/dllforpyinc.php

//main.cpp
#define DLLEXPORT extern "C" __declspec(dllexport)

DLLEXPORT int sum(int a, int b) { return a + b; }

//main.h
int sum(int, int);

我用 Code::Blocks 自带的 GCC 和 VS2008 分别编译出了 dll 文件,但是调用的时候都会报错

OSError: [WinError 193] %1 不是有效的 Win32 应用程序。

我的环境是 Windows 7(64),Python 3.6.0(64),我也将生成的 dll 放到 XP 上运行过,XP 上是 Python2.7(32)

  File "C:\Python27\lib\ctypes\__init__.py", line 440, in LoadLibrary
    return self._dlltype(name)
  File "C:\Python27\lib\ctypes\__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
WindowsError: [Error 14001]

尝试多次,我按照上边教程中的,在 Linux 下生成 so 库,运行的比较正常

这是 python 代码,后来我想到下载了一个标准库 msvcrt,可以正常调用

#!/bin/env python
# -*- coding: utf-8 -*-

from ctypes import cdll

mydll = cdll.LoadLibrary(‘msvcrt.dll’)

mydll.printf(b"hello world!")

mydll = cdll.LoadLibrary(‘test.dll’) print(mydll)

所以我感觉问题还是出在 dll 这方面,这是我的分析:

1,可能是调用方式问题,查询看 dll 有不同的调用方式有,stdcall cdecl 等,不过我换用 ctypes 的 windll 调用还是不行

2,可能是编码问题,查询过程中有 ANSI,和 Unicode 两种,看到有人给出如下代码,我用 msvcrt 测试,不过我运行会提示 AttributeError: function 'printf' not found

libHandle = ctypes.cdll.kernel32.LoadLibraryW('msvcrt.dll')
lib = ctypes.CDLL(None, handle=libHandle)
lib.printf(b"hello world!")

现在有点不知从哪里入手解决,先谢谢了


Python中如何调用DLL文件?

8 回复

没用过这种方式调用 C

一般是按 PyObject 写 C++,编译之后直接在 python 里面 import


在Python里调用DLL,用ctypes库就行,这是标准库的一部分,不用额外装。基本流程就是加载DLL,然后指定函数参数和返回类型,最后调用。

下面是一个完整的例子。假设我们有一个叫example.dll(Windows)或libexample.so(Linux/macOS)的库,里面有个add函数,接收两个int参数,返回一个int

import ctypes
import sys

# 1. 加载DLL
# Windows
if sys.platform == "win32":
    my_dll = ctypes.WinDLL("./example.dll")  # 或者用绝对路径
# Linux/macOS
else:
    my_dll = ctypes.CDLL("./libexample.so")

# 2. 指定函数的参数类型和返回类型
# 找到DLL里的函数
add_func = my_dll.add
# 告诉ctypes这个函数接收两个int,返回一个int
add_func.argtypes = [ctypes.c_int, ctypes.c_int]
add_func.restype = ctypes.c_int

# 3. 调用函数
result = add_func(5, 3)
print(f"5 + 3 = {result}")  # 输出:5 + 3 = 8

关键点说明:

  • 加载方式:Windows用ctypes.WinDLL,类Unix系统用ctypes.CDLL。如果DLL依赖其他库,可能需要处理路径问题。
  • 类型映射argtypesrestype必须设对,不然会乱或者崩溃。C的int对应ctypes.c_intdouble对应c_doublechar*字符串对应c_char_p,等等。
  • 调用约定:默认是cdeclCDLL)。如果DLL用的是stdcall(常见于Win32 API),就用ctypes.WinDLL,它会自动处理。

如果函数参数里有指针(比如要返回多个值或修改传入的数组),或者结构体,会稍微复杂点,需要用到byrefpointer或者定义Structure类。但核心就是上面这三步。

一句话总结:用ctypes,三步走:加载、定义类型、调用。

可能是平台问题。我自己试过,一个 so 库在 centos 可以工作,在 debian 上不能使用

msvcrt 不用显式 load
>>> ctypes.cdll.msvcrt.printf(b’hello world!\n’)
hello world!
13

你用错了调用方式,kernel32 不是 cdll, 是 windll,
>>> libHandle = ctypes.windll.kernel32.LoadLibraryW(‘msvcrt.dll’)
>>> lib = ctypes.CDLL(None, handle=libHandle)
>>> lib.printf(b’hello world!\n’)
hello world!
13

至于你自己的 dll,你确定你的 Python 是 64bit 的吗?
OSError: [WinError 193] %1 不是有效的 Win32 应用程序。
这句错误可以看出 python 期望你的 dll 是 32bit,所以它自己应该是 32bit 才对。

“不是有效的 win32 程序”

说明 loadlibrary 这一步就错了,大概率是 x86,x64 匹配的原因

LoadLibrary 14001 错误
是因为你的 DLL 没有写 DLLmain,LoadLibrary 在载入 DLL 的时候会自动加载 DLLmain 函数,但是你没有写的话就找不到这个函数,所以加载失败。
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved
)

{return true;}
把这段代码粘进去就好了。

感谢各位的回复,这段时间有点忙,今天腾出时间又研究了一下,解决了问题

记录一下,说不定会有遇到类似问题的朋友通过搜索进来

主要两个原因

1,我的 Python 版本是 64 位,dll 是 32 位的,在另一台机器上装上 Python32 位的解决载入的问题(都是 windows7 64 位系统)
2,调用 dll 的时候我没有进行类型转换,导致函数运行一直没有结果(函数期待 char*,我却传的 python str 类型)

另外还要注意的是 dll 的类型(__cdecl 还是__stdcall ),还有 dll 的编码方式( ANSI 还是 Unicode ),使用 CDLL 或者 WinDLL 应该可以自动分辨编码

楼上朋友提到 DLLmain,我没写,生成的 dll 也是可以用的,可能是 code::blocks 创建的工程自动给我添加了

放两个链接,第一个是我的笔记,第二个链接中介绍了传参及返回值转换

Python 调用 DLL 文件
https://blog.yasking.org/a/python-use-dll.html

python ctypes 探究 ---- python 与 c 的交互
http://www.cnblogs.com/night-ride-depart/p/4907613.html

回到顶部