使用Python Ctypes加载dll

8

我看了这里给出的例子ctypes - 初学者,并按照相同步骤使用不同的C代码。 我使用此处给出的C代码构建了一个.dll和.lib文件:http://wolfprojects.altervista.org/articles/dll-in-c-for-python/

  //test.c
__declspec(dllexport) int sum(int a, int b) {
    return a + b;
}

在我的wrapper.py文件中,我有以下内容:
import ctypes

testlib = ctypes.CDLL("C:\\Users\\xyz\\Documents\\Python\\test.dll")

当我运行这个脚本时,出现了以下错误:

self._handle = _dlopen(self._name, mode)

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

如果我使用
testlib = ctypes.LibraryLoader("C:\\Users\\xyz\\Documents\\Python\\test.dll")

如果我运行脚本时没有出现任何错误,但是如果我尝试执行以下操作:

testlib.sum(3,4)

我遇到了以下错误:

dll = self._dlltype(name)

TypeError: 'str' object is not callable

dll文件和.py文件在同一个文件夹中。有谁能帮助我理解这是怎么回事?我已经花了几个小时来尝试解决这个问题,但是一直没有头绪。谢谢。


好的,我发现问题是因为我正在从Spyder运行脚本。如果我像这样从Windows命令提示符中运行脚本:python wrapper.py,那么我就不会看到[WinError 193]错误。但是尝试调用Python脚本中的sum函数会导致属性错误。我在这里做错了什么? - kronosjt
2个回答

12

确保您的编译器和Python版本都是32位或64位。不能混合使用,这是导致 OSError: [WinError 193] %1 is not a valid Win32 application 的原因。

接下来,请确保将其编译为C程序而不是C ++。这就是您回答中提到的名称重整的原因。

示例(请注意,编译器是针对x86而不是x64):

C:\>cl /LD /W4 test.c
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
Microsoft (R) Incremental Linker Version 11.00.61030.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.dll
/dll
/implib:test.lib
test.obj
   Creating library test.lib and object test.exp

现在使用一个32位的Python:

C:\>py -2
Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> lib = CDLL('test')
>>> lib.sum(2, 3)
5

如果您以C++编译,仍然可以将函数导出为C并调用它们,这可以防止C++名称混淆:

test.cpp

extern "C" __declspec(dllexport) int sum(int a, int b) {
    return a + b;
}

感谢您的回答。我使用64位Windows,并安装了64位版本的Anaconda,因此我的Python是64位的。我没有自己编译dll,因为我没有相关工具。因此,问题可能是由于编译引起的。 - kronosjt
1
你可以提到Python可以安装32位和64位版本...因为我安装了64位版本,无法重新编译dll文件(据我所知),所以我安装了32位的Python 3.8版本,它非常好用。谢谢! - Shmack
@ShanerM13,你刚才提到了它。如果你安装了多个Python版本并且没有将它们添加到路径中,你可以使用Python Launcher选项,轻松地在任何版本之间切换,甚至可以在shebang(#!)注释中调用特定版本来运行脚本。 - Mark Tolonen

2
进一步挖掘后,我已经找到了解决方法。C编译器捆绑了函数的名称,这就是为什么在调用sum方法时会出现Attribute错误的原因。我必须使用link.exe来确定捆绑名称,然后使用getattr方法。更多细节和解释可以在此帖子中找到: Python: 使用ctypes访问DLL函数--按函数*名称*访问失败

1
名称不应该被搞乱。你是编译成了 C++ 而不是 C 吗?这是 ctypes 不是 cpptypes :) - Mark Tolonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接