我现在将一些函数包装在C ++ dll中,其原始.h .cpp文件不可访问。在学习了ctypes教程之后,我仍然有一些问题。让我举几个例子: 这是来自dll函数的描述文件,只是告诉函数的名称,效果和参数:
#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)
为了在Python中包装这些函数,我要做的是:
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)
当我在VS2015 python interactice窗口中键入并定义第一个函数(在导入包并加载dll之后)时,它给出了一个错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'c_char' is not defined
我是否需要指定输入参数的类型?如果是这样,怎么办?我无法识别第四个函数中某些参数的类型,例如PUINT lpDeviceID
和UINT TaskCode
。如何指定它们?
而且,我是否需要指定函数的返回值的类型?如果是这样,如何指定它们?
有人可以给我上面例子的正确包装代码吗?谢谢你的关注!
答案 0 :(得分:1)
您的问题是您没有完全正确的名称空间。其
cppdll.InitNetwork.argtypes = [ctypes.c_char, ctypes.c_char, ctypes.c_int]
您可以将所需的ctypes数据直接导入模块。由于ctypes
为您创建函数包装器,因此您不需要自己的def
来执行相同的操作。您可以使用cppdll.Whatever
调用它们,但如果您希望在命名空间级别具有这些功能,则可以为它们创建变量。
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 :(得分:1)
这是一整套应该有效的定义。注意如何通过创建类型的实例并通过引用传递它来传递输出参数。许多常见的Windows类型也在ctypes.wintypes
中定义。
注意,对于InitNetwork,C中的第一个参数类型是char*
,因此您需要c_char_p
而不是c_char
,并且您可以直接传递Python字节字符串,因为C代码不是写指针。如果需要,ctypes.create_string_buffer()
可用于生成可写char数组。
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)