我正在尝试使用Python中的ctypes从MacOSX中的CoreFoundation框架访问CoreMidi函数。
当我调用一个没有任何参数的函数时,一切都很顺利。例如,以下代码:
from ctypes import *
core_midi = cdll.LoadLibrary("/System/Library/Frameworks/CoreMIDI.framework/Versions/A/CoreMIDI")
numOfDevices = core_midi.MIDIGetNumberOfDevices()
print numOfDevices
返回
3
这是我电脑中MIDI设备的数量。
但是,我无法执行需要参数的函数。检查这个例子(编辑:正如eryksun指出的那样,我使用char *作为client_name,函数原型需要一个CFString。我在下面的代码示例中更正了这一点,但我仍然得到相同的错误):
core_midi = cdll.LoadLibrary("/System/Library/Frameworks/CoreMIDI.framework/Versions/A/CoreMIDI")
client_name = core_foundation.CFStringCreateWithCString(None, "MIDI Client", 0)
midi_client = c_uint()
result = core_midi.MIDIClientCreate(client_name, None, None, byref(midi_client))
print midi_client
print result
此代码根本不打印任何内容,甚至不会引发异常。 MIDIClientCreate函数的原型是:
extern OSStatus MIDIClientCreate(
CFStringRef name,
MIDINotifyProc notifyProc,
void *notifyRefCon,
MIDIClientRef *outClient );
MIDIClientRef定义为UInt32,据我所知,它接收一个指向创建的MIDIClient结构的指针,这就是我使用byref()将其作为参数传递的原因。如果我只传递没有byref()的变量,函数调用返回一个值-50,这可能表示一些奇怪的错误。
编辑:我不确定我是否正确创建了CFString。我尝试使用以下代码测试结果,但它不会在屏幕上打印任何内容。
client_name = core_foundation.CFStringCreateWithCString(None, "MIDI Client", 0)
cstr = ctypes.create_string_buffer(20)
core_foundation.CFStringGetCString(client_name, cstr, 20, 0)
print cstr
谢谢!
编辑:由eryksun回答!
我当然不知道这一点,但设置指针并不像我天真的例子那样明显。
class _CFString(Structure):
pass
cf_path = ctypes.util.find_library("CoreFoundation")
cm_path = ctypes.util.find_library("CoreMIDI")
core_foundation = ctypes.cdll.LoadLibrary(cf_path)
core_midi = ctypes.cdll.LoadLibrary(cm_path)
CFStringRef = POINTER(_CFString)
midi_client = ctypes.c_uint()
core_foundation.CFStringCreateWithCString.restype = CFStringRef
core_foundation.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_uint32]
client_name = core_foundation.CFStringCreateWithCString(None, "MIDI Client", 0)
core_midi.MIDIClientCreate.argtypes = [CFStringRef, c_void_p, c_void_p, POINTER(c_uint32)]
result = core_midi.MIDIClientCreate(client_name, None, None, byref(midi_client))
print midi_client
print result
实际上,虽然restype和argtypes并没有影响函数的执行方式或参数传递给它们的方式,但似乎它们确实如此。
上面的代码导致:
c_uint(4657178L)
0
也就是说,我的MIDI客户端是在某处创建的,函数返回时没有错误。 再次感谢eryksun!