1
votes

I'm now wrapping some functions in C++ dll whose original .h an .cpp file are not accessable. After learning the tutorial of ctypes, I still have the some questions. Let me show you some example: This is from the description file of the dll functions, just telling functions' names, effects and parameters:

#initialize network:
BOOL InitNetwork(char LocalIP[],char ServerIP[],int LocalDeviceID)

#judging if the server is online after network initialization:
BOOL GetOnlineStatus()

#get song name:
char* GetMusicSongName(int DirIndex,int SongIndex)

#making the device playing music:
int PlayServerMusic(int DirIndex,int MusicIndex,int DeviceCout,PUINT lpDeviceID,int UseListIndex,int UserMusicIndex,UINT TaskCode)

In order to wrap these functions in Python, what I'm tring to do is this:

import ctypes
import os

#load dll
cppdll = ctypes.WinDLL("C:\\VS_projects\\MusicWebService\\MusicWebService\\NetServerInterface.dll")

#wrap dll functions:

#initialize network:
def InitNetwork(LocalIP, ServerIP, LocalDeviceID):
    return cppdll.InitNetwork(LocalIP, ServerIP, LocalDeviceID)
InitNetwork.argtypes = [c_char, c_char, c_int]

#judging if the server is online after network initialization:
def GetOnlineStatus():
    return cppdll.GetOnlineStatus()

#get song name:
def GetMusicSongName(DirIndex, SongIndex):
    return cppdll.GetMusicSongName(DirIndex, SongIndex)
GetMusicSongName.argtypes = [c_int, c_int]

#making the device playing music:
def PlayServerMusic(DirIndex, MusicIndex, DeviceCout, lpDeviceID, UseListIndex, UserMusicIndex, TaskCode):
    return cppdll.PlayServerMusic(DirIndex, MusicIndex, DeviceCout, lpDeviceID, UseListIndex, UserMusicIndex, TaskCode)

When I type and define the first function (after importing packages and loading the dll) in the VS2015 python interactice window, it gives me an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'c_char' is not defined

Do I need to specify the type of input parameters? If so, how to do this? I can't recognize the type of some parameters in the forth function such as PUINT lpDeviceID and UINT TaskCode. How to specify them? Moreover, do I need to specify the functions' return value's type? If so, how to specify them? Could somebody give me the correct wrapping code of the examples above? Thanks for your attention!

2
InitNetwork.argtypes = [c_char, c_char, c_int] looks suspicious, as the original c-function accepts a pointer, not a character. Possibly you need c_void_p instead?Aconcagua
@Aconcagua Yes, you are right.YQ.Wang

2 Answers

1
votes

Your problem is that you don't have the namespaces quite right. Its

cppdll.InitNetwork.argtypes = [ctypes.c_char, ctypes.c_char, ctypes.c_int]

You can import the ctypes data you need directly into the module. And since ctypes creates function wrappers for you, you don't really need your own def to do the same thing. You can call them with cppdll.Whatever but if you like having the functions at the namespace level, you can just create variables for them.

from ctypes import WinDLL, c_char, c_int
import os

#load dll
cppdll = ctypes.WinDLL("C:\\VS_projects\\MusicWebService\\MusicWebService\\NetServerInterface.dll")

#initialize network:
InitNetwork = cppdll.InitNetwork
InitNetwork.argtypes = [c_char, c_char, c_int]

#judging if the server is online after network initialization:
GetOnlineStatus = cppdll.GetOnlineStatus

#get song name:
GetMusicSongName = cppdll.GetMusicSongName
GetMusicSongName.argtypes = [c_int, c_int]

#making the device playing music:
PlayServerMusic = cppdll.PlayServerMusic
PlayServerMusic = ...
1
votes

Here's a full set of definitions that should work. Note how to pass an output parameter by creating an instance of the type and passing it by reference. Many common Windows types are also defined in ctypes.wintypes as well.

Note for InitNetwork the first parameter types are char* in C, so you need c_char_p not c_char and you can directly pass Python byte strings as along as the C code doesn't write to pointers. ctypes.create_string_buffer() can be used to generate a writable char array if needed.

from ctypes import *
from ctypes import wintypes as w

dll = WinDLL('path/to/dll')

# BOOL InitNetwork(char LocalIP[],char ServerIP[],int LocalDeviceID)
dll.InitNetwork.argtypes = c_char_p,c_char_p,c_int
dll.InitNetwork.restype = w.BOOL

# BOOL GetOnlineStatus()
dll.GetOnlineStatus.argtypes = None
dll.GetOnlineStatus.restype = w.BOOL

# char* GetMusicSongName(int DirIndex,int SongIndex)
dll.GetMusicSongName.argtypes = c_int,c_int
dll.GetMusicSongName.restype = c_char_p

# int PlayServerMusic(int DirIndex,int MusicIndex,int DeviceCout,PUINT lpDeviceID,int UseListIndex,int UserMusicIndex,UINT TaskCode)
dll.PlayServerMusic.argtypes = c_int,c_int,w.PUINT,c_int,c_int,w.UINT
dll.PlayServerMusic.restype = c_int

dll.InitNetwork(b'1.1.1.1',b'2.2.2.2',7)
status = dll.GetOnlineStatus()
song = dll.GetMusicSongName(1,2)
DeviceCout = w.UINT()
result = dll.PlayServerMusic(1,2,3,byref(DeviceCout),4,5,6)