winamp/Src/Plugins/Library/ml_devices/eventRelay.cpp

466 lines
10 KiB
C++

#include "main.h"
#include "./eventRelay.h"
#include <vector>
#define EVENT_RELAY_WINDOW_CLASS L"NullsoftEventRelay"
typedef struct EventHandler
{
size_t cookie;
DeviceEventCallbacks callbacks;
void *user;
} EventHandler;
typedef std::vector<EventHandler*> 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);
}