I am developing a tool that displays a status about various hardware components on a system we use at work. Currently, we have 16 touch screen monitors (all by 3M) plugged in to a Windows 10 box. I need to verify that any given monitor has an associated touch screen recognized by windows. This is to assess the system for any hardware malfunctions i.e. bad cable, bad USB port, bad Monitor, etc. We see this more than we would like to admit, usually where a monitor's display will be working fine but the USB controller on either end drops out and needs to be reset by unplugging/plugging back in
Unfortunately my code posting will be limited due to work constraints.
I can enumerate all of the monitors plugged in to the system via winapi's EnumDisplayDevices and EnumerateDisplayMonitors. I am able to build a list of all the HID touch screen devices using HIDApi.
From here I have no direction on where to go to link these two things together, if it is even possible. My first thought was the HID device information should have some sort of identifier shared by the results of calling the EnumDisplayDevices and EnumerateDisplayMonitors, but I have not found this to be the case. Another possibility would be to compare the coordinates/size of a monitor to a region that one of the touch controllers is responsible for. Again, not sure if that is possible.
In short, is there a way to associate a Touch device with it's corresponding monitor via c++?
I think you were just lucky that this driver suffix matched your monitor configuration. In my Windows 10 multi-monitor setup I get wrong displays when I look them up with this number in the driver entry as you described.
A reliable way for associating a HID device with a display seems to be:
- Call
GetRawInputDeviceList()
to obtain the HID devices
- Call
GetRawInputDeviceInfo()
with RIDI_DEVICEINFO
to determine Usage
and UsagePage
- Call
GetRawInputDeviceInfo()
with RIDI_DEVICENAME
to get a device string in the form \\\\?\\HID#VID_0EEF&PID_7200&Col01#6&152cc7f9&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
- Query the registry for the mapping table at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wisp\Pen\Digimon
and look up the display device name. In my case the HID names are all prefixed with 20-
there but the remaining part seems to match the name queried by GetRawInputDeviceInfo()
exactly. As a fallback method in case there is no match, I also parse the middle part as Clay Brooks described in his answer.
- Call
EnumDisplayDevices()
with a null pointer for lpDevice
and 0 for dwFlags
in a loop until the function returns zero.
- Within each loop iteration, call
EnumDisplayDevices()
again with the current device as lpDevice
and EDD_GET_DEVICE_INTERFACE_NAME
for dwFlags
and observe that it returns a DeviceID
in the form \\\\?\\DISPLAY#ELO2243#5&607b301&0&UID24833#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
- Loop until a HID <-> display match is found and take the
DeviceName
returned by the "outer" EnumDisplayDevices()
call which should be something like \\.\DISPLAY3
After the suggestions in the comments and looking deeper into the registry, I've found a way to link Touch controllers to a monitor.
Using HIDApi, you can poll the system and find a list of all the Touch Controllers you need to monitor. I filtered by the VID of the monitors we are using. A sample return value for the path looks something like this:
"\\?\hid#vid_0596&pid_0520&col02#8&33d9e616&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
The bold part can be used to link to the entries in HKLM/Software/Microsoft/Wisp/Pen/Digimon. An example entry is this:
"\\?\HID#VID_0596&PID_0520&Col03#8&33d9e616&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}" "\\?\DISPLAY#MSY1C2B#7&1083071f&0&UID524#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
The first bold matches the data found through HIDApi and the second set of bolding, the monitor name and a UID, is listed in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY. Under here you can use the combination of monitor name and UID to find the Driver entry. Below is a sample driver entry:
{4d36e96e-e325-11ce-bfc1-08002be10318}\0010
The last bold number can then be used to match up with a DeviceID returned from EnumDisplayDevices(). Below is a sample DeviceID:
"MONITOR\MSY1C2B\{4d36e96e-e325-11ce-bfc1-08002be10318}\0010".
Then you can use this bolded section to match up to names of monitors returned from EnumDisplayMonitors().