如何在Python中使用DLL

0 投票
5 回答
2151 浏览
提问于 2025-04-16 12:24

我正在尝试在Python中加载一个DLL文件,我想用它里面的eConnect()函数,使用的是ctypes库。

关于这个DLL的源代码,我知道以下几点:

  • 从*.cpp源代码中可以看到:bool eConnect( const char *host, UINT port, int clientId=0);
  • 通过依赖工具查看到:这个函数的序号是6,未修饰的名称是
    ?eConnect@EClientSocket@@UAE_NPBDIH@Z

我尝试用两种方法来调用eConnect,分别是myfunction和myfunction2,但可能搞错了。以下是我的代码:

from ctypes import *

def main():

IP = c_char_p('127.0.0.1')
port = c_uint(7496)
client_id = c_int(0)

myfunction = getattr(cdll.TwsSocketClient, "?eConnect@EClientSocket@@UAE_NPBDIH@Z")
myfunction2= cdll.TwsSocketClient[6]

print myfunction
print myfunction2

print myfunction(IP, port, client_id,IP)

if __name__ == "__main__":
main()

我遇到了下面的错误:

"WindowsError: exception: access violation reading 0x0000002D"

我真的很需要一些帮助(我不懂C++)。谢谢!

5 个回答

1

你要调用的这个函数是 EClientSocket 类里的一个成员函数。你现在想从 Python 里调用这个函数,但没有传入 EClientSocket 的指针作为 this 参数。而且,ctypes 这个库对 __thiscall 这种调用方式也不太了解,所以即使你传入了一个 EClientSocket 的实例,它也会在栈上,而不是放在 ECX 寄存器里。

解决这个问题的一个办法是从你的 DLL 里导出一个 C 语言的包装函数,这个函数会把调用转发到 eConnect。比如:

extern "C" DLLEXPORT
bool EClientSocket_eConnect(EClientSocket *This, const char *host, UINT port, int clientId)
{
    return This->eConnect(host, port, clientId);
}

不过,即使这样,你在 Python 这边也要特别小心,确保构造一个合适的 EClientSocket 实例。我强烈建议你重新考虑一下你的做法。

4

为了让事情变得更简单、更符合Python的风格,你可以看看ctypesgen这个工具:

http://code.google.com/p/ctypesgen/

它可以为你生成合适的包装函数、数据类型等等。如果你只是想知道怎么使用ctypes,可以先从这个教程开始:

http://docs.python.org/library/ctypes.html

如果你有更具体的问题,我就需要查看你想用的DLL的API文档了。

0

谢谢大家的回答。我听了亚当的建议,重新考虑了一下我的方法。因为我不懂C++,所以一开始就选择它真的是个糟糕的主意。

在R语言中有一个非官方的替代API,它是基于官方的Java API构建的。这样一来,使用rPy2就可以很容易地把R和Python连接起来。

撰写回答