使用ctypes从CoreFoundation调用带有参数的函数

时间:2014-04-03 15:09:13

标签: python macos ctypes coremidi

我正在尝试使用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!

0 个答案:

没有答案