#include "main.h" #include "./eventRelay.h" #include #define EVENT_RELAY_WINDOW_CLASS L"NullsoftEventRelay" typedef struct EventHandler { size_t cookie; DeviceEventCallbacks callbacks; void *user; } EventHandler; typedef std::vector EventHandlerList; typedef struct EventRelay { EventHandlerList handlerList; DeviceManagerHandler *managerHandler; DeviceHandler *deviceHandler; } EventRelay; #define EVENTRELAY(_hwnd) ((EventRelay*)(LONGX86)GetWindowLongPtrW((_hwnd), 0)) #define EVENTRELAY_RET_VOID(_self, _hwnd) {(_self) = EVENTRELAY((_hwnd)); if (NULL == (_self)) return;} #define EVENTRELAY_RET_VAL(_self, _hwnd, _error) {(_self) = EVENTRELAY((_hwnd)); if (NULL == (_self)) return (_error);} static LRESULT CALLBACK EventRelay_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam); static ATOM EventRelay_GetClassAtom(HINSTANCE instance) { WNDCLASSEXW klass; ATOM klassAtom; klassAtom = (ATOM)GetClassInfoExW(instance, EVENT_RELAY_WINDOW_CLASS, &klass); if (0 != klassAtom) return klassAtom; memset(&klass, 0, sizeof(klass)); klass.cbSize = sizeof(klass); klass.style = 0; klass.lpfnWndProc = EventRelay_WindowProc; klass.cbClsExtra = 0; klass.cbWndExtra = sizeof(EventRelay*); klass.hInstance = instance; klass.hIcon = NULL; klass.hCursor = NULL; klass.hbrBackground = NULL; klass.lpszMenuName = NULL; klass.lpszClassName = EVENT_RELAY_WINDOW_CLASS; klass.hIconSm = NULL; klassAtom = RegisterClassExW(&klass); return klassAtom; } HWND EventRelay_CreateWindow() { HINSTANCE instance; ATOM klassAtom; HWND hwnd; instance = GetModuleHandleW(NULL); klassAtom = EventRelay_GetClassAtom(instance); if (0 == klassAtom) return NULL; hwnd = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY, MAKEINTATOM(klassAtom), NULL, WS_OVERLAPPED, 0, 0, 0, 0, HWND_MESSAGE, NULL, instance, NULL); return hwnd; } static size_t EventRelay_GenerateCookie(EventRelay *self) { size_t cookie; EventHandler *handler; if (NULL == self) return 0; cookie = self->handlerList.size() + 1; for(;;) { size_t index = self->handlerList.size(); while(index--) { handler = self->handlerList[index]; if (cookie == handler->cookie) { cookie++; break; } } if (((size_t)-1) == index) return cookie; } return cookie; } static EventHandler * EventRelay_CreateEventHandler(EventRelay *self, DeviceEventCallbacks *callbacks, void *user) { EventHandler *handler; size_t cookie; if (NULL == self || NULL == callbacks) return NULL; cookie = EventRelay_GenerateCookie(self); if (0 == cookie) return NULL; handler = (EventHandler*)malloc(sizeof(EventHandler)); if (NULL == handler) return NULL; handler->user = user; handler->cookie = cookie; handler->callbacks.deviceCb = callbacks->deviceCb; handler->callbacks.typeCb = callbacks->typeCb; handler->callbacks.connectionCb = callbacks->connectionCb; handler->callbacks.commandCb = callbacks->commandCb; handler->callbacks.discoveryCb = callbacks->discoveryCb; return handler; } static void EventRelay_DestroyEventHandler(EventHandler *handler) { if (NULL == handler) return; free(handler); } static LRESULT EventRelay_OnCreate(HWND hwnd, CREATESTRUCT *createStruct) { EventRelay *self; ifc_deviceobjectenum *enumerator; ifc_deviceobject *object; ifc_device *device; if (NULL == WASABI_API_DEVICES) return -1; self = new EventRelay(); if (NULL == self) return -1; self->deviceHandler = NULL; self->managerHandler = NULL; SetLastError(ERROR_SUCCESS); if (!SetWindowLongPtr(hwnd, 0, (LONGX86)self) && ERROR_SUCCESS != GetLastError()) return -1; if (FAILED(DeviceHandler::CreateInstance(&self->deviceHandler))) return -1; self->deviceHandler->SetRelayWindow(hwnd); if (SUCCEEDED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator))) { while(S_OK == enumerator->Next(&object, 1, NULL)) { if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device))) { self->deviceHandler->Advise(device); device->Release(); } object->Release(); } enumerator->Release(); } if (FAILED(DeviceManagerHandler::CreateInstance(&self->managerHandler))) return -1; self->managerHandler->SetRelayWindow(hwnd); if (FAILED(self->managerHandler->Advise(WASABI_API_DEVICES))) return -1; return 0; } static void EventRelay_OnDestroy(HWND hwnd) { EventRelay *self; MSG msg; self = EVENTRELAY(hwnd); SetWindowLongPtr(hwnd, 0, 0); if (NULL == self) return; size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; EventRelay_DestroyEventHandler(handler); } if (NULL != self->managerHandler) { self->managerHandler->SetRelayWindow(NULL); if (NULL != WASABI_API_DEVICES) self->managerHandler->Unadvise(WASABI_API_DEVICES); self->managerHandler->Release(); } if (NULL != self->deviceHandler) { self->deviceHandler->SetRelayWindow(NULL); if (NULL != WASABI_API_DEVICES) { ifc_deviceobjectenum *enumerator; ifc_deviceobject *object; ifc_device *device; if (SUCCEEDED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator))) { while(S_OK == enumerator->Next(&object, 1, NULL)) { if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device))) { self->deviceHandler->Unadvise(device); device->Release(); } object->Release(); } enumerator->Release(); } } self->deviceHandler->Release(); } delete self; // finish pumping messages while(FALSE != PeekMessage(&msg, hwnd, EVENTRELAY_WM_FIRST, EVENTRELAY_WM_LAST, PM_REMOVE)) { EventRelay_WindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); } } static LRESULT EventRelay_OnRegisterHandler(HWND hwnd, DeviceEventCallbacks *callbacks, void *user) { EventRelay *self; EventHandler *handler; EVENTRELAY_RET_VAL(self, hwnd, 0); handler = EventRelay_CreateEventHandler(self, callbacks, user); if(NULL == handler) return 0; self->handlerList.push_back(handler); return (LRESULT)handler->cookie; } static LRESULT EventRelay_OnUnregisterHandler(HWND hwnd, size_t cookie) { EventRelay *self; EVENTRELAY_RET_VAL(self, hwnd, FALSE); size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (handler->cookie == cookie) { self->handlerList.erase(self->handlerList.begin() + index); EventRelay_DestroyEventHandler(handler); return TRUE; } } return FALSE; } static void EventRelay_OnNotifyDevice(HWND hwnd, ifc_device *device, DeviceEvent eventId) { ReplyMessage(0); if (NULL != device) { EventRelay *self; self = EVENTRELAY(hwnd); if (NULL != self) { switch(eventId) { case Event_DeviceAdded: if (NULL != self->deviceHandler) self->deviceHandler->Advise(device); break; case Event_DeviceRemoved: if (NULL != self->deviceHandler) self->deviceHandler->Unadvise(device); break; } size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (NULL != handler->callbacks.deviceCb) handler->callbacks.deviceCb(device, eventId, handler->user); } } device->Release(); } } static void EventRelay_OnNotifyDiscovery(HWND hwnd, api_devicemanager *manager, DeviceDiscoveryEvent eventId) { ReplyMessage(0); if (NULL != manager) { EventRelay *self; self = EVENTRELAY(hwnd); if (NULL != self) { size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (NULL != handler->callbacks.discoveryCb) handler->callbacks.discoveryCb(manager, eventId, handler->user); } } manager->Release(); } } static void EventRelay_OnNotifyType(HWND hwnd, ifc_devicetype *type, DeviceTypeEvent eventId) { ReplyMessage(0); if (NULL != type) { EventRelay *self; self = EVENTRELAY(hwnd); if (NULL != self) { size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (NULL != handler->callbacks.typeCb) handler->callbacks.typeCb(type, eventId, handler->user); } } type->Release(); } } static void EventRelay_OnNotifyConnection(HWND hwnd, ifc_deviceconnection *connection, DeviceConnectionEvent eventId) { ReplyMessage(0); if (NULL != connection) { EventRelay *self; self = EVENTRELAY(hwnd); if (NULL != self) { size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (NULL != handler->callbacks.connectionCb) handler->callbacks.connectionCb(connection, eventId, handler->user); } } connection->Release(); } } static void EventRelay_OnNotifyCommand(HWND hwnd, ifc_devicecommand *command, DeviceCommandEvent eventId) { ReplyMessage(0); if (NULL != command) { EventRelay *self; self = EVENTRELAY(hwnd); if (NULL != self) { size_t index = self->handlerList.size(); while(index--) { EventHandler *handler = self->handlerList[index]; if (NULL != handler->callbacks.commandCb) handler->callbacks.commandCb(command, eventId, handler->user); } } command->Release(); } } static LRESULT CALLBACK EventRelay_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CREATE: return EventRelay_OnCreate(hwnd, (CREATESTRUCT*)lParam); case WM_DESTROY: EventRelay_OnDestroy(hwnd); return 0; case EVENTRELAY_WM_REGISTER_HANDLER: return EventRelay_OnRegisterHandler(hwnd, (DeviceEventCallbacks*)lParam, (void*)wParam); case EVENTRELAY_WM_UNREGISTER_HANDLER: return EventRelay_OnUnregisterHandler(hwnd, (size_t)lParam); case EVENTRELAY_WM_NOTIFY_DEVICE: EventRelay_OnNotifyDevice(hwnd, (ifc_device*)lParam, (DeviceEvent)wParam); return 0; case EVENTRELAY_WM_NOTIFY_DISCOVERY: EventRelay_OnNotifyDiscovery(hwnd, (api_devicemanager*)lParam, (DeviceDiscoveryEvent)wParam); return 0; case EVENTRELAY_WM_NOTIFY_TYPE: EventRelay_OnNotifyType(hwnd, (ifc_devicetype*)lParam, (DeviceTypeEvent)wParam); return 0; case EVENTRELAY_WM_NOTIFY_CONNECTION: EventRelay_OnNotifyConnection(hwnd, (ifc_deviceconnection*)lParam, (DeviceConnectionEvent)wParam); return 0; case EVENTRELAY_WM_NOTIFY_COMMAND: EventRelay_OnNotifyCommand(hwnd, (ifc_devicecommand*)lParam, (DeviceCommandEvent)wParam); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }