HID Parser for Win32

This commit is contained in:
Jack Andersen 2017-09-15 12:26:39 -10:00
parent 0f2a838bfb
commit 1f14cc09a1
12 changed files with 289 additions and 48 deletions

View File

@ -5,6 +5,12 @@
#include <stdlib.h>
#include <stdio.h>
#include <memory>
#include <vector>
#include "boo/System.hpp"
#if _WIN32
#include <hidsdi.h>
#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<uint8_t> 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*/) {}

View File

@ -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;

View File

@ -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<bool(const HIDMainItem& item)>& valueCB) const;
void enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
};
}

View File

@ -5,6 +5,11 @@
#include <vector>
#include <stack>
#include <functional>
#include <memory>
#if _WIN32
#include <hidsdi.h>
#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<HIDMainItem> m_itemPool;
mutable std::vector<HIDP_DATA> m_dataList;
PHIDP_PREPARSED_DATA m_descriptorData = nullptr;
#else
std::unique_ptr<HIDMainItem[]> m_itemPool;
using Report = std::pair<uint32_t, std::pair<uint32_t, uint32_t>>;
std::unique_ptr<Report[]> m_reportPool;
std::pair<uint32_t, uint32_t> m_inputReports = {};
std::pair<uint32_t, uint32_t> m_outputReports = {};
std::pair<uint32_t, uint32_t> m_featureReports = {};
ParserStatus m_status = ParserStatus::OK;
bool m_multipleReports = false;
ParserStatus ParseItem(HIDReports& reportsOut,
std::stack<HIDItemState>& stateStack, std::stack<HIDCollectionItem>& collectionStack,
std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& 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<bool(uint32_t rep, const HIDMainItem& item)>& valueCB) const;
void ScanValues(std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
void ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const;
};

View File

@ -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<uint8_t> 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)
{

View File

@ -9,6 +9,8 @@
namespace boo
{
DeviceFinder* DeviceFinder::skDevFinder = nullptr;
#if _WIN32
/* Windows-specific WM_DEVICECHANGED handler */
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)

View File

@ -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<uint8_t> 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<bool(const HIDMainItem& item)>& valueCB) const
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const
{
std::function<bool(uint32_t, const HIDMainItem&)> func =
[&](uint32_t rep, const HIDMainItem& item) { return valueCB(item); };
m_parser.EnumerateValues(func);
m_parser.EnumerateValues(valueCB);
}
}

View File

@ -27,7 +27,7 @@ namespace boo
class HIDDeviceWinUSB final : public IHIDDevice
{
DeviceToken& m_token;
DeviceBase& m_devImp;
std::shared_ptr<DeviceBase> 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<HIDDeviceWinUSB> 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<HIDDeviceWinUSB> device)
{
std::unique_lock<std::mutex> 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<HIDDeviceWinUSB> device)
{
char errStr[256];
std::unique_lock<std::mutex> 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<uint8_t[]> 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<uint8_t> m_sendBuf;
std::vector<uint8_t> 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<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
@ -335,11 +342,11 @@ public:
std::unique_lock<std::mutex> 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<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, this);
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, this);
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceWinUSB>(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]);
}
};

View File

@ -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);

View File

@ -1,5 +1,9 @@
#include "boo/inputdev/HIDParser.hpp"
#include <map>
#include <algorithm>
#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<decltype(UsagePageNames)>::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<uint32_t, HIDMainItem> inputItems;
{
/* First enumerate buttons */
USHORT length = caps.NumberInputButtonCaps;
std::vector<HIDP_BUTTON_CAPS> 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<HIDP_VALUE_CAPS> 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<HIDItemState>& stateStack, std::stack<HIDCollectionItem>& collectionStack,
std::stack<HIDItemState>& stateStack,
std::stack<HIDCollectionItem>& 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<bool(uint32_t rep, const HIDMainItem& item)>& valueCB) const
#if _WIN32
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& 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<bool(const HIDMainItem& item)>& valueCB) const
{
if (m_status != ParserStatus::Done)
return;
@ -579,11 +688,50 @@ void HIDParser::EnumerateValues(std::function<bool(uint32_t rep, const HIDMainIt
for (uint32_t j=rep.second.first ; j<rep.second.second ; ++j)
{
const HIDMainItem& item = m_itemPool[j];
if (!valueCB(rep.first, item))
if (item.IsConstant())
continue;
if (!valueCB(item))
return;
}
}
}
#endif
#if _WIN32
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& 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<bool(const HIDMainItem& item, int32_t value)>& valueCB,
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
const uint8_t* data, size_t len) const
{
if (m_status != ParserStatus::Done)
@ -646,11 +794,14 @@ void HIDParser::ScanValues(std::function<bool(const HIDMainItem& item, int32_t v
int32_t val = bitIt.GetUnsignedValue(item.m_reportSize, status);
if (status == ParserStatus::Error)
return;
if (item.IsConstant())
continue;
if (!valueCB(item, val))
return;
}
break;
}
}
#endif
}

View File

@ -5,6 +5,10 @@
#include "boo/inputdev/DeviceBase.hpp"
#include <memory>
#if _WIN32
#include <hidsdi.h>
#endif
namespace boo
{
@ -15,7 +19,11 @@ class IHIDDevice : public std::enable_shared_from_this<IHIDDevice>
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<uint8_t> _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;

View File

@ -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<IWindow> 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();