diff --git a/include/boo/inputdev/DeviceBase.hpp b/include/boo/inputdev/DeviceBase.hpp index 7565a8d..e219938 100644 --- a/include/boo/inputdev/DeviceBase.hpp +++ b/include/boo/inputdev/DeviceBase.hpp @@ -5,6 +5,12 @@ #include #include #include +#include +#include "boo/System.hpp" + +#if _WIN32 +#include +#endif namespace boo { @@ -45,7 +51,11 @@ public: size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length); /* High-Level API */ +#if _WIN32 + const PHIDP_PREPARSED_DATA getReportDescriptor(); +#else std::vector getReportDescriptor(); +#endif bool sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message=0); size_t receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message=0); // Prefer callback version virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/, uint32_t /*message*/) {} diff --git a/include/boo/inputdev/DeviceFinder.hpp b/include/boo/inputdev/DeviceFinder.hpp index 30406bc..97229cc 100644 --- a/include/boo/inputdev/DeviceFinder.hpp +++ b/include/boo/inputdev/DeviceFinder.hpp @@ -20,8 +20,6 @@ namespace boo { -static class DeviceFinder* skDevFinder = NULL; - class DeviceFinder { public: @@ -31,6 +29,7 @@ public: static inline DeviceFinder* instance() {return skDevFinder;} private: + static class DeviceFinder* skDevFinder; /* Types this finder is interested in (immutable) */ DeviceSignature::TDeviceSignatureSet m_types; diff --git a/include/boo/inputdev/GenericPad.hpp b/include/boo/inputdev/GenericPad.hpp index 146854f..0fde410 100644 --- a/include/boo/inputdev/GenericPad.hpp +++ b/include/boo/inputdev/GenericPad.hpp @@ -29,7 +29,7 @@ public: void initialCycle(); void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message); - void enumerateValues(std::function& valueCB) const; + void enumerateValues(const std::function& valueCB) const; }; } diff --git a/include/boo/inputdev/HIDParser.hpp b/include/boo/inputdev/HIDParser.hpp index 048ff70..b860960 100644 --- a/include/boo/inputdev/HIDParser.hpp +++ b/include/boo/inputdev/HIDParser.hpp @@ -5,6 +5,11 @@ #include #include #include +#include + +#if _WIN32 +#include +#endif namespace boo { @@ -157,6 +162,8 @@ struct HIDMainItem HIDMainItem() = default; HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx); + HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, + HIDRange logicalRange, int32_t reportSize); const char* GetUsagePageName() const; const char* GetUsageName() const; }; @@ -171,22 +178,35 @@ public: Error }; private: + + ParserStatus m_status = ParserStatus::OK; +#if _WIN32 + std::vector m_itemPool; + mutable std::vector m_dataList; + PHIDP_PREPARSED_DATA m_descriptorData = nullptr; +#else std::unique_ptr m_itemPool; using Report = std::pair>; std::unique_ptr m_reportPool; std::pair m_inputReports = {}; std::pair m_outputReports = {}; std::pair m_featureReports = {}; - ParserStatus m_status = ParserStatus::OK; bool m_multipleReports = false; ParserStatus ParseItem(HIDReports& reportsOut, - std::stack& stateStack, std::stack& collectionStack, + std::stack& stateStack, + std::stack& collectionStack, const uint8_t*& it, const uint8_t* end); +#endif + public: +#if _WIN32 + ParserStatus Parse(const PHIDP_PREPARSED_DATA descriptorData); +#else ParserStatus Parse(const uint8_t* descriptorData, size_t len); +#endif operator bool() const { return m_status == ParserStatus::Done; } - void EnumerateValues(std::function& valueCB) const; - void ScanValues(std::function& valueCB, + void EnumerateValues(const std::function& valueCB) const; + void ScanValues(const std::function& valueCB, const uint8_t* data, size_t len) const; }; diff --git a/lib/inputdev/DeviceBase.cpp b/lib/inputdev/DeviceBase.cpp index 1f11dc9..2c86b9f 100644 --- a/lib/inputdev/DeviceBase.cpp +++ b/lib/inputdev/DeviceBase.cpp @@ -54,12 +54,21 @@ size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) return false; } +#if _WIN32 +const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() +{ + if (m_hidDev) + return m_hidDev->_getReportDescriptor(); + return {}; +} +#else std::vector DeviceBase::getReportDescriptor() { if (m_hidDev) return m_hidDev->_getReportDescriptor(); return {}; } +#endif bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { diff --git a/lib/inputdev/DeviceFinder.cpp b/lib/inputdev/DeviceFinder.cpp index f650eac..6483dd5 100644 --- a/lib/inputdev/DeviceFinder.cpp +++ b/lib/inputdev/DeviceFinder.cpp @@ -9,6 +9,8 @@ namespace boo { +DeviceFinder* DeviceFinder::skDevFinder = nullptr; + #if _WIN32 /* Windows-specific WM_DEVICECHANGED handler */ LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam) diff --git a/lib/inputdev/GenericPad.cpp b/lib/inputdev/GenericPad.cpp index f74c3e9..816b2cf 100644 --- a/lib/inputdev/GenericPad.cpp +++ b/lib/inputdev/GenericPad.cpp @@ -20,8 +20,13 @@ void GenericPad::deviceDisconnected() void GenericPad::initialCycle() { +#if _WIN32 + const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor(); + m_parser.Parse(reportDesc); +#else std::vector reportDesc = getReportDescriptor(); m_parser.Parse(reportDesc.data(), reportDesc.size()); +#endif if (m_cb) m_cb->controllerConnected(); } @@ -39,11 +44,9 @@ void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReport m_parser.ScanValues(func, data, length); } -void GenericPad::enumerateValues(std::function& valueCB) const +void GenericPad::enumerateValues(const std::function& valueCB) const { - std::function func = - [&](uint32_t rep, const HIDMainItem& item) { return valueCB(item); }; - m_parser.EnumerateValues(func); + m_parser.EnumerateValues(valueCB); } } diff --git a/lib/inputdev/HIDDeviceWinUSB.cpp b/lib/inputdev/HIDDeviceWinUSB.cpp index 5b6da2c..ab4aceb 100644 --- a/lib/inputdev/HIDDeviceWinUSB.cpp +++ b/lib/inputdev/HIDDeviceWinUSB.cpp @@ -27,7 +27,7 @@ namespace boo class HIDDeviceWinUSB final : public IHIDDevice { DeviceToken& m_token; - DeviceBase& m_devImp; + std::shared_ptr m_devImp; HANDLE m_devHandle = 0; HANDLE m_hidHandle = 0; @@ -68,7 +68,7 @@ class HIDDeviceWinUSB final : public IHIDDevice return 0; } - static void _threadProcUSBLL(HIDDeviceWinUSB* device) + static void _threadProcUSBLL(std::shared_ptr device) { unsigned i; char errStr[256]; @@ -87,7 +87,7 @@ class HIDDeviceWinUSB final : public IHIDDevice _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().c_str(), device->m_devPath.c_str(), GetLastError()); - device->m_devImp.deviceError(errStr); + device->m_devImp->deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); return; @@ -98,7 +98,7 @@ class HIDDeviceWinUSB final : public IHIDDevice _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().c_str(), device->m_devPath.c_str(), GetLastError()); - device->m_devImp.deviceError(errStr); + device->m_devImp->deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); CloseHandle(device->m_devHandle); @@ -112,7 +112,7 @@ class HIDDeviceWinUSB final : public IHIDDevice _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().c_str(), device->m_devPath.c_str(), GetLastError()); - device->m_devImp.deviceError(errStr); + device->m_devImp->deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); CloseHandle(device->m_devHandle); @@ -137,10 +137,10 @@ class HIDDeviceWinUSB final : public IHIDDevice device->m_initCond.notify_one(); /* Start transfer loop */ - device->m_devImp.initialCycle(); + device->m_devImp->initialCycle(); while (device->m_runningTransferLoop) - device->m_devImp.transferCycle(); - device->m_devImp.finalCycle(); + device->m_devImp->transferCycle(); + device->m_devImp->finalCycle(); /* Cleanup */ WinUsb_Free(device->m_usbHandle); @@ -148,7 +148,7 @@ class HIDDeviceWinUSB final : public IHIDDevice device->m_devHandle = 0; } - static void _threadProcBTLL(HIDDeviceWinUSB* device) + static void _threadProcBTLL(std::shared_ptr device) { std::unique_lock lk(device->m_initMutex); @@ -158,17 +158,19 @@ class HIDDeviceWinUSB final : public IHIDDevice device->m_initCond.notify_one(); /* Start transfer loop */ - device->m_devImp.initialCycle(); + device->m_devImp->initialCycle(); while (device->m_runningTransferLoop) - device->m_devImp.transferCycle(); - device->m_devImp.finalCycle(); + device->m_devImp->transferCycle(); + device->m_devImp->finalCycle(); } size_t m_minFeatureSz = 0; size_t m_minInputSz = 0; size_t m_minOutputSz = 0; - static void _threadProcHID(HIDDeviceWinUSB* device) + PHIDP_PREPARSED_DATA m_preparsedData = nullptr; + + static void _threadProcHID(std::shared_ptr device) { char errStr[256]; std::unique_lock lk(device->m_initMutex); @@ -187,30 +189,28 @@ class HIDDeviceWinUSB final : public IHIDDevice _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().c_str(), device->m_devPath.c_str(), GetLastError()); - device->m_devImp.deviceError(errStr); + device->m_devImp->deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); return; } - PHIDP_PREPARSED_DATA preparsedData; - if (!HidD_GetPreparsedData(device->m_hidHandle, &preparsedData)) + if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) { _snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n", device->m_token.getProductName().c_str(), device->m_devPath.c_str(), GetLastError()); - device->m_devImp.deviceError(errStr); + device->m_devImp->deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); return; } HIDP_CAPS caps; - HidP_GetCaps(preparsedData, &caps); + HidP_GetCaps(device->m_preparsedData, &caps); device->m_minFeatureSz = caps.FeatureReportByteLength; device->m_minInputSz = caps.InputReportByteLength; device->m_minOutputSz = caps.OutputReportByteLength; - HidD_FreePreparsedData(preparsedData); /* Return control to main thread */ device->m_runningTransferLoop = true; @@ -218,21 +218,23 @@ class HIDDeviceWinUSB final : public IHIDDevice device->m_initCond.notify_one(); /* Allocate read buffer */ - size_t inBufferSz = std::max(device->m_minInputSz, device->m_devImp.getInputBufferSize()); + size_t inBufferSz = device->m_minInputSz; std::unique_ptr readBuf(new uint8_t[inBufferSz]); /* Start transfer loop */ - device->m_devImp.initialCycle(); + device->m_devImp->initialCycle(); while (device->m_runningTransferLoop) { device->ReadCycle(readBuf.get(), inBufferSz); - device->m_devImp.transferCycle(); + if (device->m_runningTransferLoop) + device->m_devImp->transferCycle(); } - device->m_devImp.finalCycle(); + device->m_devImp->finalCycle(); /* Cleanup */ CloseHandle(device->m_overlapped.hEvent); CloseHandle(device->m_hidHandle); + HidD_FreePreparsedData(device->m_preparsedData); device->m_hidHandle = nullptr; } @@ -244,6 +246,11 @@ class HIDDeviceWinUSB final : public IHIDDevice std::vector m_sendBuf; std::vector m_recvBuf; + const PHIDP_PREPARSED_DATA _getReportDescriptor() + { + return m_preparsedData; + } + bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length)); @@ -323,7 +330,7 @@ class HIDDeviceWinUSB final : public IHIDDevice public: - HIDDeviceWinUSB(DeviceToken& token, DeviceBase& devImp) + HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr& devImp) : m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) @@ -335,11 +342,11 @@ public: std::unique_lock lk(m_initMutex); DeviceType dType = m_token.getDeviceType(); if (dType == DeviceType::USB) - m_thread = std::thread(_threadProcUSBLL, this); + m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast(shared_from_this())); else if (dType == DeviceType::Bluetooth) - m_thread = std::thread(_threadProcBTLL, this); + m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast(shared_from_this())); else if (dType == DeviceType::HID) - m_thread = std::thread(_threadProcHID, this); + m_thread = std::thread(_threadProcHID, std::static_pointer_cast(shared_from_this())); else throw std::runtime_error("invalid token supplied to device constructor"); m_initCond.wait(lk); @@ -348,7 +355,8 @@ public: ~HIDDeviceWinUSB() { m_runningTransferLoop = false; - m_thread.join(); + if (m_thread.joinable()) + m_thread.detach(); } OVERLAPPED m_overlapped = {}; @@ -362,7 +370,12 @@ public: if (!Result) { DWORD Error = GetLastError(); - if (Error != ERROR_IO_PENDING) + if (Error == ERROR_DEVICE_NOT_CONNECTED) + { + m_runningTransferLoop = false; + return; + } + else if (Error != ERROR_IO_PENDING) { fprintf(stderr, "Read Failed: %08X\n", Error); return; @@ -373,7 +386,7 @@ public: } } - m_devImp.receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]); + m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]); } }; diff --git a/lib/inputdev/HIDListenerWinUSB.cpp b/lib/inputdev/HIDListenerWinUSB.cpp index 5174a1d..eac152c 100644 --- a/lib/inputdev/HIDListenerWinUSB.cpp +++ b/lib/inputdev/HIDListenerWinUSB.cpp @@ -135,6 +135,32 @@ class HIDListenerWinUSB final : public IHIDListener &devpropType, (BYTE*)manufW, 1024, &manufSz, 0); WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr); + if (type == DeviceType::HID) + { + HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + if (INVALID_HANDLE_VALUE == devHnd) + continue; + PHIDP_PREPARSED_DATA preparsedData; + if (!HidD_GetPreparsedData(devHnd, &preparsedData)) + { + CloseHandle(devHnd); + continue; + } + HIDP_CAPS caps; + HidP_GetCaps(preparsedData, &caps); + HidD_FreePreparsedData(preparsedData); + CloseHandle(devHnd); + /* Filter non joysticks and gamepads */ + if (caps.UsagePage != 1 || (caps.Usage != 4 && caps.Usage != 5)) + continue; + } + /* Store as a shouting string (to keep hash-lookups consistent) */ CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath); diff --git a/lib/inputdev/HIDParser.cpp b/lib/inputdev/HIDParser.cpp index fb45859..f5f9369 100644 --- a/lib/inputdev/HIDParser.cpp +++ b/lib/inputdev/HIDParser.cpp @@ -1,5 +1,9 @@ #include "boo/inputdev/HIDParser.hpp" #include +#include + +#undef min +#undef max namespace boo { @@ -289,6 +293,12 @@ HIDMainItem::HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t rep m_reportSize = state.m_reportSize; } +HIDMainItem::HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage, + HIDRange logicalRange, int32_t reportSize) +: m_flags(uint16_t(flags)), m_usagePage(usagePage), m_usage(usage), + m_logicalRange(logicalRange), m_reportSize(reportSize) +{} + const char* HIDMainItem::GetUsagePageName() const { if (int(m_usagePage) >= std::extent::value) @@ -385,9 +395,92 @@ struct HIDReports void AddFeatureItem(uint32_t flags, const HIDItemState& state) { _AddItem(m_featureReports, flags, state); } }; +#if _WIN32 +HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorData) +{ + /* User mode HID report descriptor isn't available on Win32. + * Opaque preparsed data must be enumerated and sorted into + * iterable items. + * + * Wine's implementation has a good illustration of what's + * going on here: + * https://github.com/wine-mirror/wine/blob/master/dlls/hidclass.sys/descriptor.c + * + * (Thanks for this pointless pain-in-the-ass Microsoft) + */ + + m_descriptorData = descriptorData; + HIDP_CAPS caps; + HidP_GetCaps(descriptorData, &caps); + m_dataList.resize(HidP_MaxDataListLength(HidP_Input, descriptorData)); + + std::map inputItems; + + { + /* First enumerate buttons */ + USHORT length = caps.NumberInputButtonCaps; + std::vector bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS()); + HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData); + for (const HIDP_BUTTON_CAPS& caps : bCaps) + { + if (caps.IsRange) + { + int usage = caps.Range.UsageMin; + for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) + { + inputItems.insert(std::make_pair(i, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), + HIDUsage(usage), std::make_pair(0, 1), 1))); + } + } + else + { + inputItems.insert(std::make_pair(caps.NotRange.DataIndex, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), + HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1))); + } + } + } + + { + /* Now enumerate values */ + USHORT length = caps.NumberInputValueCaps; + std::vector vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS()); + HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData); + for (const HIDP_VALUE_CAPS& caps : vCaps) + { + if (caps.IsRange) + { + int usage = caps.Range.UsageMin; + for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage) + { + inputItems.insert(std::make_pair(i, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage), + std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); + } + } + else + { + inputItems.insert(std::make_pair(caps.NotRange.DataIndex, + HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage), + HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize))); + } + } + } + + m_itemPool.reserve(inputItems.size()); + for (const auto& item : inputItems) + m_itemPool.push_back(item.second); + + m_status = ParserStatus::Done; + return ParserStatus::Done; +} +#else + HIDParser::ParserStatus HIDParser::ParseItem(HIDReports& reportsOut, - std::stack& stateStack, std::stack& collectionStack, + std::stack& stateStack, + std::stack& collectionStack, const uint8_t*& it, const uint8_t* end) { ParserStatus status = ParserStatus::OK; @@ -567,8 +660,24 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l return m_status; } +#endif -void HIDParser::EnumerateValues(std::function& valueCB) const +#if _WIN32 +void HIDParser::EnumerateValues(const std::function& valueCB) const +{ + if (m_status != ParserStatus::Done) + return; + + for (const HIDMainItem& item : m_itemPool) + { + if (item.IsConstant()) + continue; + if (!valueCB(item)) + return; + } +} +#else +void HIDParser::EnumerateValues(const std::function& valueCB) const { if (m_status != ParserStatus::Done) return; @@ -579,11 +688,50 @@ void HIDParser::EnumerateValues(std::function& valueCB, + const uint8_t* data, size_t len) const +{ + if (m_status != ParserStatus::Done) + return; + + ULONG dataLen = m_dataList.size(); + if (HidP_GetData(HidP_Input, m_dataList.data(), &dataLen, + m_descriptorData, PCHAR(data), len) != HIDP_STATUS_SUCCESS) + return; + + int idx = 0; + auto it = m_dataList.begin(); + auto end = m_dataList.begin() + dataLen; + for (const HIDMainItem& item : m_itemPool) + { + if (item.IsConstant()) + continue; + int32_t value = 0; + if (it != end) + { + const HIDP_DATA& data = *it; + if (data.DataIndex == idx) + { + value = data.RawValue; + ++it; + } + } + if (!valueCB(item, value)) + return; + ++idx; + } +} +#else class BitwiseIterator { @@ -618,7 +766,7 @@ public: } }; -void HIDParser::ScanValues(std::function& valueCB, +void HIDParser::ScanValues(const std::function& valueCB, const uint8_t* data, size_t len) const { if (m_status != ParserStatus::Done) @@ -646,11 +794,14 @@ void HIDParser::ScanValues(std::function +#if _WIN32 +#include +#endif + namespace boo { @@ -15,7 +19,11 @@ class IHIDDevice : public std::enable_shared_from_this virtual void _deviceDisconnected()=0; virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0; virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0; +#if _WIN32 + virtual const PHIDP_PREPARSED_DATA _getReportDescriptor()=0; +#else virtual std::vector _getReportDescriptor()=0; +#endif virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0; virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0; virtual void _startThread()=0; diff --git a/lib/win/ApplicationWin32.cpp b/lib/win/ApplicationWin32.cpp index 5aa5e90..adc0a86 100644 --- a/lib/win/ApplicationWin32.cpp +++ b/lib/win/ApplicationWin32.cpp @@ -316,11 +316,11 @@ public: /* Lookup boo window instance */ auto search = m_allWindows.find(hwnd); if (search == m_allWindows.end()) - return 0; + return DefWindowProc(hwnd, uMsg, wParam, lParam);; std::shared_ptr window = search->second.lock(); if (!window) - return 0; + return DefWindowProc(hwnd, uMsg, wParam, lParam); switch (uMsg) { @@ -527,7 +527,7 @@ int ApplicationRun(IApplication::EPlatformType platform, }; wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101)); wndClass.hCursor = WIN32_CURSORS.m_arrow; - RegisterClassW(&wndClass); + ATOM a = RegisterClassW(&wndClass); APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args, singleInstance); return APP->run();