【问题标题】:ctypes.ArgumentError when calling DLL functions with Python使用 Python 调用 DLL 函数时出现 ctypes.ArgumentError
【发布时间】:2018-05-14 07:28:25
【问题描述】:

我正在使用 ctypes 根据描述 DLL 函数参数和返回的描述文件调用 DLL 文件中的函数。这是该 DLL 中的一个函数,称为 InitNetwork。下面是它的描述:

Function:BOOL InitNetwork(char  LocalIP[],char  ServerIP[],int  LocalDeviceID);
Arguments:LocalIP
           ServerIP
           LocalDeviceID
Return:Success:TRUE;
        Faile:FALSE;

我在 Python 中做的事情是这样的:

from ctypes import *
import os

#Load Dll:
cppdll = CDLL("C:\\VS_projects\\MusicServer_Flask\\NetServerInterface.dll")

#Get the function:
initnetwork = getattr(cppdll, "?InitNetwork@@YAHQAD0H@Z")  # The function can be successfully accessed.

#specify arguments' types:
initnetwork.argtypes = [c_char_p,c_char_p,c_int]

在此之后,我尝试:

initnetwork("192.168.1.103", "192.168.1.103", 1111)

得到一个错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

如果我试试这个:

initnetwork(LocalIP = "192.168.1.103", ServerIP = "192.168.1.103", LocalDeviceID = 1111)

我会得到:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: this function takes at least 3 arguments (0 given)

为什么会出现这些错误?如何成功调用此函数?任何建议表示赞赏。感谢您的关注!

【问题讨论】:

    标签: python c++ dll ctypes


    【解决方案1】:

    ctypes 官方文档:[Python 3.5]: ctypes - A foreign function library for Python.

    创建了一个虚拟 .dll 来模仿你的行为。

    dll.c

    #include <stdio.h>
    #include <Windows.h>
    
    
    __declspec(dllexport) BOOL InitNetwork(char LocalIP[], char ServerIP[], int LocalDeviceID) {
        printf("From C:\n\tLocalIP: [%s]\n\tServerIP: [%s]\n\tLocalDeviceID: %d\n", LocalIP, ServerIP, LocalDeviceID);
        return TRUE;
    }
    

    查看[SO]: How to compile a 64-bit dll written in C? (@CristiFati's answer) 了解如何构建它的详细信息(采取完全相同的步骤,本例中的命令是:cl /nologo /LD /DWIN64 /DWIN32 /Tp dll.c /link /OUT:NetServerInterface.dll)。

    (主要)问题是在Python3 中,char* 不再映射到 string,而是映射到 bytes 对象。

    code.py

    import sys
    import ctypes
    from ctypes import wintypes
    
    
    FILE_NAME = "NetServerInterface.dll"
    FUNC_NAME = "?InitNetwork@@YAHQEAD0H@Z"  # Name different than yours: if func was declared as `extern "C"`, the "normal" name would be required
    
    
    def main():
        net_server_interface_dll = ctypes.CDLL(FILE_NAME)
        init_network = getattr(net_server_interface_dll, FUNC_NAME)
    
        init_network.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
        init_network.restype = wintypes.BOOL
    
        init_network(b"192.168.1.103", b"192.168.1.103", 1111)
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    输出

    (py35x64_test) e:\Work\Dev\StackOverflow\q050325050>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
    Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
    
    From C:
            LocalIP: [192.168.1.103]
            ServerIP: [192.168.1.103]
            LocalDeviceID: 1111
    

    【讨论】:

    • 解决问题的超级具体答案。不能再感谢你了!
    • 很高兴听到这个消息!
    【解决方案2】:

    我认为问题出在您的 C++ 接口上。我想如果你把它改成 Function:BOOL InitNetwork(char * LocalIP,char * ServerIP,int LocalDeviceID);

    您的第一次调用(没有关键字)应该可以工作,但我认为您可能需要删除最后一个参数周围的引号(毕竟它是一个 int)。

    【讨论】:

    • 哦,是的,最后一个参数的引号应该被删除。这个DLL是别人提供的,我无法访问它的原始代码。所以我不能改变 C++ 函数。在ctypes中处理char LocalIp[]是不可能的吗?
    • 抱歉,回复延迟 - 我一直在回家。我现在要做的是用接口 BOOL kludge(char *, char *,int); 编写一个小的 c 例程;简称为 InitNetwork。很抱歉我不知道在windows上做这个的来龙去脉,我是一个linux女孩。
    猜你喜欢
    • 2020-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多