3

I'm using ctypes to call functions in a DLL file according to a description file that describe the DLL functions' parameters and returns. Here is one function in this DLL called InitNetwork. Below is its description:

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

What I'm doing in Python is like this:

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]

After this, I try:

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

Get an Error:

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

If I try this:

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

I will get:

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

Why these errors comes out? How can I call this function successfully? Any suggestion is appreciated. Thank you for your attention!

0

3 Answers 3

4

ctypes official doc: [Python 3.5]: ctypes - A foreign function library for Python.

Created a dummy .dll to mimic your behavior.

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;
}

Check [SO]: How to compile a 64-bit dll written in C? (@CristiFati's answer) for details how to build it (took the exact same steps, command in this case was: cl /nologo /LD /DWIN64 /DWIN32 /Tp dll.c /link /OUT:NetServerInterface.dll).

The (main) problem is that in Python3, char* no longer maps to a string, but to a bytes object.

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()

Output:

(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
Sign up to request clarification or add additional context in comments.

2 Comments

Super specific answer which get the problem killed. Can't thank you more!
Glad to hear that!
1

I think the problem is in your C++ interface. I think if you change it to Function:BOOL InitNetwork(char * LocalIP,char * ServerIP,int LocalDeviceID);

your first call (without the keywords) should work but I think you might need to remove the quotes around the last argument (it is an int after all).

2 Comments

Oh yes, the last argument's quotes should be removed. This DLL is provided by another person, I can't access its original code. So I can't change the C++ function. Is it impossible to deal with char LocalIp[] in ctypes?
Sorry for the delay in replying - I've been travelling home. What I would do now is to write a small c routine with interface BOOL kludge(char *, char *,int); which simply called InitNetwork. I am sorry that I don't know the ins and outs of doing this on windows, I'm a linux girl.
0

Faced the same issue with Python 3.7, which is UTF-8 by default. So used utf to bytes

library_handler = ctypes.windll.LoadLibrary('my_api.dll')

dll_fu = library_handler.DllFunc
dll_fu.argtypes = [ctypes.c_char_p,
                     ctypes.c_char_p,
                     ctypes.c_char_p,
                     ctypes.c_char_p]

result_code = dll_fu(param1.encode('utf-8'),
                    param2.encode('utf-8'),
                    param3.encode('utf-8'),
                    param4.encode('utf-8'))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.