从 Python 调用 Windows DLL 函数时出错

Error invoking Windows DLL function from Python

我有一个公开函数的 Windows DLL。我们称它为 Fn。它需要两个 CStrings 作为参数和 returns 一个 CString:

CString Fn(CString a, CString b)

您在下面看到的 C++ 代码成功加载了 DLL 并调用了 FnFn 的一个副作用是它将参数 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 而不是从 C++ 调用 DLL 时会被破坏?

其实这个问题不仅出现在我从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;
}

根据对我的问题的评论,我设法找到了解决方案。

问题似乎是 CString 是一个 MFC 概念,Python 和 NSIS 都不知道。将 Fn 的签名更改为

LPCTSTR Fn(LPCTSTR, LPCTSTR)

解决了问题。