如何在Python中使用DLL
我正在尝试在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 个回答
你要调用的这个函数是 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
实例。我强烈建议你重新考虑一下你的做法。
为了让事情变得更简单、更符合Python的风格,你可以看看ctypesgen这个工具:
http://code.google.com/p/ctypesgen/
它可以为你生成合适的包装函数、数据类型等等。如果你只是想知道怎么使用ctypes,可以先从这个教程开始:
http://docs.python.org/library/ctypes.html
如果你有更具体的问题,我就需要查看你想用的DLL的API文档了。
谢谢大家的回答。我听了亚当的建议,重新考虑了一下我的方法。因为我不懂C++,所以一开始就选择它真的是个糟糕的主意。
在R语言中有一个非官方的替代API,它是基于官方的Java API构建的。这样一来,使用rPy2就可以很容易地把R和Python连接起来。