From 273ee15ed8a0c578450b8f2f2d3701c6d16ff81b Mon Sep 17 00:00:00 2001 From: Stefan Persson Date: Fri, 7 Oct 2011 10:58:40 +0000 Subject: [PATCH] Fixed missing implementation of deviceCallbackEvents, and added different handling of contexts. --- .../TelldusNETWrapper/TelldusNETWrapper.cs | 170 +++++++----------- 1 file changed, 63 insertions(+), 107 deletions(-) diff --git a/bindings/dotnet/TelldusNETWrapper/TelldusNETWrapper.cs b/bindings/dotnet/TelldusNETWrapper/TelldusNETWrapper.cs index 82164cb8..0d476504 100644 --- a/bindings/dotnet/TelldusNETWrapper/TelldusNETWrapper.cs +++ b/bindings/dotnet/TelldusNETWrapper/TelldusNETWrapper.cs @@ -51,23 +51,37 @@ namespace TelldusWrapper public const int TELLSTICK_CHANGE_PROTOCOL = 2; public const int TELLSTICK_CHANGE_MODEL = 3; - //variables for event callback (e.g. turnon, turnoff) public delegate int EventCallbackFunction(int deviceId, int method, string data, int callbackId, Object obj); - Dictionary eventList = new Dictionary(); - GCHandle eventContextHandle; + private struct DeviceEventFunctionContext + { + public EventCallbackFunction eventCallbackFunc; + public Object context; + public int callbackId; + } + Dictionary deviceEventList = new Dictionary(); int registeredEventFunctionId = -1; //variables for device event callback (e.g. change of name/protocol) public delegate int DeviceChangeEventCallbackFunction(int deviceId, int changeEvent, int changeType, int callbackId, Object obj); - Dictionary deviceChangeEventList = new Dictionary(); - GCHandle deviceChangeEventContextHandle; + private struct DeviceChangeEventFunctionContext + { + public DeviceChangeEventCallbackFunction changeEventCallbackFunc; + public Object context; + public int callbackId; + } + Dictionary deviceChangeEventList = new Dictionary(); int registeredDeviceChangeEventFunctionId = -1; //variables for raw controller listening callback (e.g. Tellstick Duo receives data) public delegate int RawListeningCallbackFunction(string data, int controllerId, int callbackId, Object obj); - Dictionary rawListenerList = new Dictionary(); - GCHandle rawListenerContextHandle; + private struct RawEventFunctionContext + { + public RawListeningCallbackFunction rawCallbackFunc; + public Object context; + public int callbackId; + } + Dictionary rawListenerList = new Dictionary(); int registeredRawListenerFunctionId = -1; public TelldusNETWrapper() @@ -90,18 +104,6 @@ namespace TelldusWrapper UnmanagedImport.tdUnregisterCallback(registeredRawListenerFunctionId); } UnmanagedImport.tdClose(); //Close the library and clean up the cache it uses. - if (eventContextHandle.IsAllocated) - { - eventContextHandle.Free(); - } - if (deviceChangeEventContextHandle.IsAllocated) - { - deviceChangeEventContextHandle.Free(); - } - if (rawListenerContextHandle.IsAllocated) - { - rawListenerContextHandle.Free(); - } } /// @@ -185,7 +187,7 @@ namespace TelldusWrapper public static extern void tdInit(); [DllImport("TelldusCore.dll")] - public static unsafe extern int tdRegisterDeviceEvent(Delegate eventFunction, void* context); + public static unsafe extern int tdRegisterDeviceEvent(Delegate deviceEventFunction, void* context); [DllImport("TelldusCore.dll")] public static extern int tdLastSentCommand(int deviceId, int methods); @@ -212,10 +214,10 @@ namespace TelldusWrapper public static unsafe extern int tdUnregisterCallback(int eventId); [DllImport("TelldusCore.dll")] - public static unsafe extern int tdRegisterDeviceChangeEvent(Delegate deviceEventFunction, void* context); + public static unsafe extern int tdRegisterDeviceChangeEvent(Delegate deviceChangeEventFunction, void* context); [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public unsafe delegate void EventFunctionDelegate(); //int deviceId, int method, int callbackId, void* context [MarshalAs(UnmanagedType.LPStr)]string data, + public unsafe delegate void EventFunctionDelegate(int deviceId, int method, char* data, int callbackId, void* context); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public unsafe delegate void DeviceChangeEventFunctionDelegate(int deviceId, int changeEvent, int changeType, int callbackId, void* context); @@ -447,31 +449,27 @@ namespace TelldusWrapper /// Callback function to be called /// Context object that will be echoed back when function is called. Only the object when the first function is registered will be used. Set to null if not used. /// Callback event id - public unsafe int tdRegisterDeviceEvent(EventCallbackFunction eventFunc, Object obj) + public unsafe int tdRegisterDeviceEvent(EventCallbackFunction deviceEventFunc, Object obj) { int returnValue = 0; - - if (eventList.Count == 0) + + if (deviceEventList.Count == 0) { //first added, register with dll too - //only the context object of the first event will be registered - UnmanagedImport.EventFunctionDelegate eventFunctionDelegate = new UnmanagedImport.EventFunctionDelegate(eventFunction); - if (obj != null) - { - eventContextHandle = GCHandle.Alloc(obj); - registeredEventFunctionId = UnmanagedImport.tdRegisterDeviceEvent(eventFunctionDelegate, (void*)GCHandle.ToIntPtr(eventContextHandle)); //context here or above? - } - else - { - registeredEventFunctionId = UnmanagedImport.tdRegisterDeviceEvent(eventFunctionDelegate, (void*)null); //context here or above? - } + UnmanagedImport.EventFunctionDelegate deviceEventFunctionDelegate = new UnmanagedImport.EventFunctionDelegate(deviceEventFunction); + + registeredEventFunctionId = UnmanagedImport.tdRegisterDeviceEvent(deviceEventFunctionDelegate, (void*)null); //context here or above? GC.Collect(); - callbackFunctionReferenceList.Add(registeredEventFunctionId, eventFunctionDelegate); + callbackFunctionReferenceList.Add(registeredEventFunctionId, deviceEventFunctionDelegate); } ++lastEventID; returnValue = lastEventID; - eventList.Add(returnValue, eventFunc); + DeviceEventFunctionContext deviceEventFuncContext = new DeviceEventFunctionContext(); + deviceEventFuncContext.eventCallbackFunc = deviceEventFunc; + deviceEventFuncContext.context = obj; + deviceEventFuncContext.callbackId = returnValue; + deviceEventList.Add(returnValue, deviceEventFuncContext); return returnValue; } @@ -482,31 +480,26 @@ namespace TelldusWrapper /// Callback function to be called /// Context object that will be echoed back when function is called. Only the object when the first function is registered will be used. Set to null if not used. /// Callback event id - public unsafe int tdRegisterDeviceChangeEvent(DeviceChangeEventCallbackFunction deviceEventFunc, Object obj) + public unsafe int tdRegisterDeviceChangeEvent(DeviceChangeEventCallbackFunction deviceChangeEventFunc, Object obj) { int returnValue = 0; if (deviceChangeEventList.Count == 0) { //first added, register with dll too //only the context object of the first event will be registered - UnmanagedImport.DeviceChangeEventFunctionDelegate deviceChangeEventFunctionDelegate = new UnmanagedImport.DeviceChangeEventFunctionDelegate(deviceEventFunction); + UnmanagedImport.DeviceChangeEventFunctionDelegate deviceChangeEventFunctionDelegate = new UnmanagedImport.DeviceChangeEventFunctionDelegate(deviceChangeEventFunction); - if (obj != null) - { - deviceChangeEventContextHandle = GCHandle.Alloc(obj); - registeredDeviceChangeEventFunctionId = UnmanagedImport.tdRegisterDeviceChangeEvent(deviceChangeEventFunctionDelegate, (void*)GCHandle.ToIntPtr(deviceChangeEventContextHandle)); - } - else - { - registeredDeviceChangeEventFunctionId = UnmanagedImport.tdRegisterDeviceChangeEvent(deviceChangeEventFunctionDelegate, (void*)null); - } + registeredDeviceChangeEventFunctionId = UnmanagedImport.tdRegisterDeviceChangeEvent(deviceChangeEventFunctionDelegate, (void*)null); GC.Collect(); callbackFunctionReferenceList.Add(registeredDeviceChangeEventFunctionId, deviceChangeEventFunctionDelegate); - } ++lastEventID; returnValue = lastEventID; - deviceChangeEventList.Add(returnValue, deviceEventFunc); + DeviceChangeEventFunctionContext deviceChangeEventFuncContext = new DeviceChangeEventFunctionContext(); + deviceChangeEventFuncContext.changeEventCallbackFunc = deviceChangeEventFunc; + deviceChangeEventFuncContext.context = obj; + deviceChangeEventFuncContext.callbackId = returnValue; + deviceChangeEventList.Add(returnValue, deviceChangeEventFuncContext); return returnValue; } @@ -526,22 +519,17 @@ namespace TelldusWrapper //only the context object of the first event will be registered UnmanagedImport.RawListeningDelegate listeningFunctionDelegate = new UnmanagedImport.RawListeningDelegate(rawListeningFunction); - if (obj != null) - { - rawListenerContextHandle = GCHandle.Alloc(obj); - - registeredRawListenerFunctionId = UnmanagedImport.tdRegisterRawDeviceEvent(listeningFunctionDelegate, (void*)GCHandle.ToIntPtr(rawListenerContextHandle)); - } - else - { - registeredRawListenerFunctionId = UnmanagedImport.tdRegisterRawDeviceEvent(listeningFunctionDelegate, (void*)null); - } + registeredRawListenerFunctionId = UnmanagedImport.tdRegisterRawDeviceEvent(listeningFunctionDelegate, (void*)null); GC.Collect(); callbackFunctionReferenceList.Add(registeredRawListenerFunctionId, listeningFunctionDelegate); } ++lastEventID; returnValue = lastEventID; - rawListenerList.Add(returnValue, listeningFunc); + RawEventFunctionContext rawEventFuncContext = new RawEventFunctionContext(); + rawEventFuncContext.rawCallbackFunc = listeningFunc; + rawEventFuncContext.context = obj; + rawEventFuncContext.callbackId = returnValue; + rawListenerList.Add(returnValue, rawEventFuncContext); return returnValue; } @@ -667,16 +655,18 @@ namespace TelldusWrapper /// Id of callback even to unregister public void unregisterCallback(int eventId) { - eventList.Remove(eventId); - if (eventList.Count == 0) + deviceEventList.Remove(eventId); + if (deviceEventList.Count == 0) { //no more events in list UnmanagedImport.tdUnregisterCallback(registeredEventFunctionId); callbackFunctionReferenceList.Remove(registeredEventFunctionId); + /* if (eventContextHandle.IsAllocated) { eventContextHandle.Free(); } + */ } deviceChangeEventList.Remove(eventId); @@ -685,10 +675,6 @@ namespace TelldusWrapper //no more events in list UnmanagedImport.tdUnregisterCallback(registeredDeviceChangeEventFunctionId); callbackFunctionReferenceList.Remove(registeredDeviceChangeEventFunctionId); - if (deviceChangeEventContextHandle.IsAllocated) - { - deviceChangeEventContextHandle.Free(); - } } rawListenerList.Remove(eventId); @@ -697,10 +683,6 @@ namespace TelldusWrapper //no more events in list UnmanagedImport.tdUnregisterCallback(registeredRawListenerFunctionId); callbackFunctionReferenceList.Remove(registeredRawListenerFunctionId); - if (rawListenerContextHandle.IsAllocated) - { - rawListenerContextHandle.Free(); - } } } @@ -780,26 +762,16 @@ namespace TelldusWrapper /// Callback event id /// Context (optional) /// 0 - private unsafe void eventFunction() //int deviceId, int method, int callbackId, void* context[MarshalAs(UnmanagedType.LPStr)]string data + private unsafe void deviceEventFunction(int deviceId, int method, char* data, int callbackId, void* context) { - foreach (EventCallbackFunction eventFunc in eventList.Values) + foreach (DeviceEventFunctionContext deviceEventFuncContext in deviceEventList.Values) { - /* - if (context != null) - { - GCHandle eventContextHandle = GCHandle.FromIntPtr((IntPtr)context); - eventFunc(deviceId, method, "", callbackId, (Object)eventContextHandle.Target); //data - } - else - { - eventFunc(deviceId, method, "", callbackId, null); - } - */ - eventFunc(1, 1, "", 1, null); + deviceEventFuncContext.eventCallbackFunc(deviceId, method, getString(data, false), deviceEventFuncContext.callbackId, deviceEventFuncContext.context); GC.Collect(); } } + /// /// Event function wrapper that will call all registered device change event functions with C#-arguments when /// this device change event function is called from telldus core, with C++-style arguments. This function will @@ -811,19 +783,11 @@ namespace TelldusWrapper /// Callback event id /// Context (optional) /// 0 - private unsafe void deviceEventFunction(int deviceId, int changeEvent, int changeType, int callbackId, void* context) + private unsafe void deviceChangeEventFunction(int deviceId, int changeEvent, int changeType, int callbackId, void* context) { - foreach (DeviceChangeEventCallbackFunction deviceEventFunc in deviceChangeEventList.Values) + foreach (DeviceChangeEventFunctionContext deviceChangeEventFuncContext in deviceChangeEventList.Values) { - if (context != null) - { - GCHandle deviceChangeEventContextHandle = GCHandle.FromIntPtr((IntPtr)context); - deviceEventFunc(deviceId, changeEvent, changeType, callbackId, (Object)deviceChangeEventContextHandle.Target); - } - else - { - deviceEventFunc(deviceId, changeEvent, changeType, callbackId, null); - } + deviceChangeEventFuncContext.changeEventCallbackFunc(deviceId, changeEvent, changeType, deviceChangeEventFuncContext.callbackId, deviceChangeEventFuncContext.context); GC.Collect(); } } @@ -840,17 +804,9 @@ namespace TelldusWrapper /// 0 private unsafe void rawListeningFunction(char* data, int controllerId, int callbackId, void* context) { - foreach (RawListeningCallbackFunction rawListeningFunc in rawListenerList.Values) + foreach (RawEventFunctionContext rawListeningFuncContext in rawListenerList.Values) { - if (context != null) - { - GCHandle rawListenerContextHandle = GCHandle.FromIntPtr((IntPtr)context); - rawListeningFunc(getString(data, false), controllerId, callbackId, (Object)rawListenerContextHandle.Target); //strings cannot be released here, since they are still in use by calling core (sent to other clients aswell), let the core take care of it with shared pointer - } - else - { - rawListeningFunc(getString(data, false), controllerId, callbackId, null); - } + rawListeningFuncContext.rawCallbackFunc(getString(data, false), controllerId, rawListeningFuncContext.callbackId, rawListeningFuncContext.context); GC.Collect(); } }