I am trying to build a DLL that reads Raw input, processes the data, and streams it to a client application that consumes this DLL. Both my DLL, and client application will be running in the background, or in the system tray. To achieve this behavior, I plan to use events. While I was trying to learn about the right approach to do this, I found conflicting guidance online and had trouble differentiating between these, and picking the right approach.
This article on event handling in native C++ suggests to setup an event source and event receiver using the event_source and event_receiver attributes. Though this approach might work in my situation, This documentation on event handling informs that event handling, though supported for native C++, is deprecated and will not be supported in future releases. This implies that I should not be using this approach. At the same time, This documentation on handling COM events looks like one potentially correct approach. I however am not able to fully understand the code here. Are there better examples or documentation that I could learn from?
Finally, This article on using C++ events in CLI discusses what I understand is a slightly different approach. The code below shows my approach for registering for input from a Precision Touchpad. I want to then override the WindowProc callback function to read input in the background. Finally, I want my DLL to raise my own events when a touch begins, is in progress, and ends. An application (running in the background) consuming this DLL should then be able to listen for the events I raise, and perform actions. What is the right, and non-deprecated approach to fire events in a C++ DLL, and handle it in the client?
My Code
// skipping headers and error handeling for brevity.
static std::vector<RAWINPUTDEVICELIST> getRawInputDevices()
{
std::vector<RAWINPUTDEVICELIST> devices(64);
while (true) {
UINT numDevices = devices.size();
UINT ret = GetRawInputDeviceList(&devices[0], &numDevices, sizeof(RAWINPUTDEVICELIST));
if (ret != (UINT)-1) {
devices.resize(ret);
return devices;
}
else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
devices.resize(numDevices);
}
else {
throw win32_error();
}
}
}
static RID_DEVICE_INFO getDeviceInfo(HANDLE HDevice)
{
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
UINT deviceSize;
deviceSize = sizeof(RID_DEVICE_INFO);
if (GetRawInputDeviceInfo(HDevice, RIDI_DEVICEINFO, &info, &deviceSize) == -1)
{
throw win32_error();
}
return info;
}
bool isPrecisionTouchAvailable()
{
bool isDigitizerAvailable = false;
std::vector<RAWINPUTDEVICELIST> devices = getRawInputDevices();
for (std::size_t i = 0; i < devices.size(); ++i)
{
RID_DEVICE_INFO info = getDeviceInfo(devices[i].hDevice);
if (info.dwType == RIM_INPUT && info.hid.usUsagePage == HID_USAGE_PAGE_DIGITIZER && info.hid.usUsage == HID_USAGE_DIGITIZER_TOUCH_PAD)
{
isDigitizerAvailable = true;
break;
}
else {
isDigitizerAvailable = false;
}
}
return isDigitizerAvailable;
}
bool registerTouchpadForInput()
{
bool registrationStatus = false;
bool precisionTouchStatus = isPrecisionTouchAvailable();
if (isPrecisionTouchAvailable != 0)
{
return registrationStatus;
}
else {
RAWINPUTDEVICE rid[1]; //one for precision touch when application is in background. Array because I plan to register for more devices like keyboard once I get things working.
rid[0].usUsagePage = HID_USAGE_PAGE_DIGITIZER; // for touchpad
rid[0].usUsage = HID_USAGE_DIGITIZER_TOUCH_PAD; // usage ID for touchpad
rid[0].dwFlags = RIDEV_INPUTSINK; //to receive events even in the background.
if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == false)
{
GetLastError();
//throw "error registering touchpad to get data.";
}
else { registrationStatus = true; }
}
return registrationStatus;
}
When my application launches, I want to call registerTouchpadForInput and let the user know that they will not be able to use my application if they do not have a Precision Touchpad on their device.