【发布时间】:2020-02-01 22:45:03
【问题描述】:
我有一个公开函数的 Windows DLL。我们称之为Fn。它接受两个CStrings作为参数并返回一个CString:
CString Fn(CString a, CString b)
您在下面看到的 C++ 代码成功加载 DLL 并调用 Fn。 Fn 的一个副作用是它将参数 a 的值打印到 stdtout。所以我明白了:
Parameter a has value "A"
但是,当我从 Python 执行相同操作时,我得到:
Parameter a has value "B"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000005
所以Fn 以某种方式接收参数b 而不是参数a。
我的问题是:为什么我的函数参数在从 Python 调用 DLL 而不是从 C++ 调用时会损坏?
其实这个问题不仅出现在我从Python调用Fn的时候,也出现在我从NSIS通过以下方式调用的时候:
System::Call "My::Fn(m 'A', m 'B') m .r0"
我认为这可能是调用约定的问题。所以我将windll.LoadLibrary 更改为cdll.LoadLibrary。不幸的是,这会产生完全相同的输出。
Python 代码(不工作)
from ctypes import *
f = windll.LoadLibrary('My.dll').Fn
f.argtypes = [c_char_p, c_char_p]
f.restype = c_char_p
f(b"A", b"B")
C++ 代码(工作)
#include <atlstr.h>
typedef CString (*Fn)(CString, CString);
int main( void ) {
HINSTANCE dll = LoadLibrary("My.dll");
Fn f = (Fn) GetProcAddress(dll, "Fn");
f("A", "B");
FreeLibrary(dll);
return 0;
}
【问题讨论】:
-
C++ 类
CString不是指针,这使得这种方法存在缺陷。 -
ctypes 代表 C (!!! NOT !!! C++) 类型。
-
至少(我敢建议)您应该使用明确的
__stdcall(可能)或__cdecl(可能)声明/定义导出的函数。但我不是Python程序员,所以不知道该语言的调用约定是什么。也许使用普通的旧字符串而不是 CString 进行语言间 (?) 调用。 -
感谢您的 cmets。我无权访问
Fn的实现,但我可以让实现者使用CString以外的字符串类型。我应该告诉他使用什么? -
唯一可以从 python 调用的字符串类型是
char*
标签: python c++ windows dll ctypes