I wrote a wrapper for the Corsair Utility Engine SDK, but there is one function that I have not been able to wrap. It's an async function that accepts a callback function, but I cannot seem to figure out how to give it that callback.
The function looks like this:
bool CorsairSetLedsColorsAsync(int size, CorsairLedColor* ledsColors, void (*CallbackType)(void* context, bool result, CorsairError error), void *context)
These are the implementations that I have tried so far:
def SetLedsColorsAsync(self, size, led_color, callback, context):
c_func = CFUNCTYPE(c_void_p, c_void_p, c_bool, c_int)
c_callback = c_func(callback)
self._libcue.CorsairSetLedsColorsAsync.restype = c_bool
self._libcue.CorsairSetLedsColorsAsync.argtypes = [c_int, POINTER(CorsairLedColor), c_void_p, c_void_p]
return self._libcue.CorsairSetLedsColorsAsync(size, led_color, c_callback, context)
as well as
def SetLedsColorsAsync(self, size, led_color, callback, context):
c_func = CFUNCTYPE(None, c_void_p, c_bool, c_int)
c_callback = c_func(callback)
self._libcue.CorsairSetLedsColorsAsync.restype = c_bool
self._libcue.CorsairSetLedsColorsAsync.argtypes = [c_int, POINTER(CorsairLedColor), c_func, c_void_p]
return self._libcue.CorsairSetLedsColorsAsync(size, led_color, c_callback, context)
The code I'm testing with is
from cue_sdk import *
import time
def test(context, result, error):
print context, result, error
return 0
Corsair = CUE("CUESDK.x64_2013.dll")
Corsair.RequestControl(CAM_ExclusiveLightingControl)
Corsair.SetLedsColorsAsync(1, CorsairLedColor(CLK_H, 255, 255, 255), test, 1)
while True:
time.sleep(1)
The time.sleep() is there just to keep the program alive.
When running it, it crashes with error code 3221225477 (STATUS_ACCESS_VIOLATION) on Windows.
If you need to see the actual wrapper, you can find it here.
CallbackType?id(callback). Pass this ID as the context value. Then when the permanent callback is called, it can use the ID as a key to pop the user's callable from the dict and call it._libcueand all of the function prototypes should be defined only once at either the module or class level. It's a waste of time to do this for every instance and method call.user_context = (callback, context). Use the ID of this tuple as the key in the class callback mapping, and pass this ID as the callback context, e.g.context = id(user_context);self._callback_map[context] = user_context. Then the permanent callback can use the ID to pop the tuple with the user's callback and context parameter.