Brief Description:
My HID Device holds many top-level collections.
Application constantly queries for collection details.
Bottleneck is - SetupDiGetClassDevs() seems to be very slow.
Detailed Description:
My code basically follows MS recommendations on how to find and obtain a handle to a HID collection. Then, I use this handle to obtain the corresponding preparsed data from which I get the data I need.
Currently, my code does this every time the user needs to obtain data (e.g. number of buttons, Axis min/max). This is a slow business. The profiler clearly says that the main culprit is SetupDiGetClassDevs() which seems to be very slow.
It is impossible to save the handle (Or so I think) as it may block the system from making changes such as removing the device or rearranging the devices. I still need to see what happens if I hold the top-level handle open for the entire session.
Another option I am contemplating is to save the preparsed data. MS implores us to release it by calling to HidD_FreePreparsedData(). What happens if we don't?
The last thing I was thinking of was to speed-up SetupDiGetClassDevs(). My current usage is:
HDEVINFO hardwareDeviceInfo =
SetupDiGetClassDevs (
&HidGuid,
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_DEVICEINTERFACE)); // Function class devices.
Will it be sped up if I changed the parameters?
Simply release the preparsed data once you are done with the device. If the device is removed, a read or write to it will fail, and you can detect that by looking at the error code by calling GetLastError()
Related
I'm working in C++ in Windows and I need to deal with an input device with force feedback. I found out that one solution could be to use DirectInput and so I start looking at that.
FIRST QUESTION: any suggestions on other ways for dealing with force feedback devices? (Win32 app, not UWP)
Coming back to DirectInput
The reference starting point I have got in my mind is the DirectInput Samples, in particular the FFconst example where a constant feedback force is applied to the first device axis according to a value grabbed from a simple GUI. In my case what I want to achieve is having a simple console application where I set a constant force according to a value grabbed from the standard input.
The basic steps for using the DirectInput API, according to the samples and the documentation, are:
create direct input device calling DirectInput8Create;
look for devices calling EnumDevices filtering devices and limiting scope to the enumeration according to what you are looking for (in my case I'm filtering for looking only in DI8DEVCLASS_GAMECTRL devices and limiting the scope to DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK);
set data format for the selected device(s) calling SetDataFormat in order to be able to acquire the device;
set the cooperative level for the device(s) calling SetCooperativeLevel once again in order to acquire the device;
use the device...
Now, all goes well until we encounter the SetCooperativeLevel mehtod since it needs as input a HWND window handle "to be associate to the device" and which "must be a valid top-level window handle that belongs to the process". Since I'm writing a console application I need to find a valid HWND pointer: I sorted the problem out following this suggestion. Anyway, the HWND pointer I get in that way seems not to be a valid window handle since I get a E_HANDLE error, as I would specify nullptr as argument. I found out that specifying the argument through the call of GetTopWindow allows not to get the invalid handle error. However I'm not able to acquire the device and I get the DIERR_OTHERAPPHASPRIO error, which is nothing more than E_ACCESSDENIED. I found that it seems someone use to treat that error in the same way the DIERR_INPUTLOST error is treated, i.e. re-acquiring the device in a while loop as shown in the Joystick direct input sample in the UpdateInputState function. Anyway trying this I'm not able to exit that loop, i.e. the device device keep being denied.
That said I end up with the
SECOND QUESTION: how to use the DirectInput API in a console application or inside a DLL? (Win32) In case of a console application I'd like to understand why the steps I've done don't work, and in case of a DLL I'd like to know if anyone has an idea on which HWND pointer could be used.
Microsoft provides a function to get a console application's window for uses like this.
HWND WINAPI GetConsoleWindow(void);
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().
I'll try to keep this as short as possible.
I have an app that has worked for years with a single mouse input. I am looking to incorporate the ability for my users to use other forms of input, such as interactive projectors, touch devices, or pretty much anything that provides WM_INPUT messages when you register for them.
The general idea I had was I would have a list of Vendor IDs and/or Product IDs that I would handle with Raw Input (which provides VID/PID, device handle and other information) for each message (WM_INPUT) received. Any devices that are not handled in the Raw Input code would be handled in the Mouse Input code (WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_RBUTTONDOWN, etc).
Ideally, I would be able to leave all of my Mouse Input code as is, or close to it. This way, if a user plugs in two mice, or a mouse and an unsupported pointing device (meaning my Raw Input code doesn't handle it based on VID/PID) the devices would both use the same system cursor. Any device that is known by my Raw Input code would be given separate cursors that exist only within my app.
The problem is simple: Mouse Input does not provide any information about the source of the message (such as WM_MOUSEMOVE, etc). Knowing that the message originated from touch helps (I have this implemented) but is definitely not enough. I need some kind of unique identifier. If I could know the source of the Mouse Input, I could only handle Mouse Input from devices that aren't on my list of known devices, and I could only handle Raw Input that are on my list of known devices.
Unfortunately, I cannot seem to find a way to achieve this.
Any ideas?
Thanks for your time sorry for the lengthy post.
TL;DR - Can you identify the source of Mouse Input (not Raw Input) in Windows? Determining whether or not the source is touch is not enough information, I need some kind of unique identifier.
Mouse Input - http://msdn.microsoft.com/en-us/library/windows/desktop/ff468877(v=vs.85).aspx
Raw Input - http://msdn.microsoft.com/en-us/library/windows/desktop/ms645536(v=vs.85).aspx
I don't know of any API for getting some sort of device id after the fact.
You could use the fact that WM_INPUT messages come before all other input messages, and when you handle WM_INPUT you could use GetRawInputDeviceInfo and a hash of the name returned by RIDI_DEVICENAME to use as a unique id. Or, you might be able to use the hDevice member of the RAWINPUTHEADER structure.
edit2: The answer to this question is "Not possible", you can't do it. Don't bother trying, but if you do and I'm wrong please explain. The fact of the matter is you can't rely on Windows to provide messages in any particular order consistently, which is what I was attempting to do. This bit me big time. Either use raw input (WM_INPUT) or use mouse messages (wm_mouse) don't try to combine the two somehow.
I never really got the answer I wanted, but I got something that works so I thought it was worth sharing.
I am working on a huge assumption, as I can't find any documentation from Windows to support this assumption (and probably wouldn't really even trust it if I found documentation from windows). To my understanding, when a mouse event is generated at the lowest level it comes through the system as a raw input message first (WM_INPUT). After the WM_INPUT message is posted, the OS gets the message and applies the ballistics and whatever else it does before a WM_*MOUSE* message is posted. The huge assumption is that this process is serial in that it is always 1 WM_INPUT message followed by 1 WM_*MOUSE* message in the queue.
With this assumption I am working with the following:
When an input message is received, store all relevant information about the source device as the "current input information"
When a mouse message is received, process it using the "current input information" as the source of the mouse message
This allows me to use n inputs in my application independently.
I'd also like to add that per Brandon's suggestion I am using the hDevice member of the RAWINPUTHEADER structure to uniquely identify each input. Since a unique device can have multiple inputs, I have yet to come up with a good way of uniquely identifying each device. VID/PID doesn't work because you can have 2 of the exact same device with multiple inputs each plugged in. I'm still working on this, see Windows HID Device Name Format
Please let me know if anyone would like me to elaborate!
edit: not marking this as the answer since I believe the correct answer is "Not possible"
I'm currently working on a small program using directshow library.The program among others should be able to select any camera connected to computer and record stream.
My problem is that I'm not sure how to free of memory dshow filters.
Let's give you an example:
For example when I want to set the output filename I have to create an AVI Mux filter like so:
IBaseFilter * aviMux;
bGraph->SetOutputFileName(
&MEDIASUBTYPE_Avi,
L"example.avi",
&aviMux,
NULL);
Now I'd like to change the filename and use the SetOutputFileName() function again, but how to free of memory AVI Mux (by the way obviously the function creates a FileWriter filter as well which I'd like to free as well)? Only I can do is that:
aviMux->Release();
fGraph->RemoveFilter(aviMux);
But will the memory be freed before the end of the program now? I'd like to do something like this:
delete aviMux;
but that's an error obviously.
Thanks in advice for any answers and help..
Standard COM rules apply:
you don't need an interface pointer anymore - you do IUnkonwn::Release
once you want to explicitly stop filter graph activity - you do IGraphBuilder::Stop to stop the filters
as soon as you release all interface pointers you hold to the graph and filters and their interfaces, all underlying resources are freed automatically
To make it more reliable you can also consider removing all filters from stopped graph explicitly (which internally forces pin disconnection).
Specifically to capture filter graph, changing a file name is almost the same complexity as building new graph from scratch. So this is what makes sense to do: stop, full cleanup, new graph, start new capture to new file. Reusing filters is possible (using IFileSinkFilter::SetFileName on a filter writer already added to stopped filter graph), however it is unlikely to speed up file switch any visibly - there will anyway be a certain delay involved.
For a seamless file switch you need two graphs - a capture graph, and a writing graph. And communication between the two, such as bridging.
I'm developing in windows with C/C++ and I want to know is it possible to get an apropriate \\.\SCSI device name by \\.\PhysicalDrive ?..
For example, it's wonderful to know how to get that \\.\PhysicalDrive0 is the same that \\.\SCSI0.
Look at the code which I posted in my answer to the question. The author of the question had changed the text of the question so many time and the last version of text clear nor really what the original problem was.
In the example, which C source code you can download here, I show how to get many kind of information about the local drive using different Windows API. The important thing which you need is that some name conversion like DeviceType and DeviceNumber (received by IOCTL_STORAGE_GET_DEVICE_NUMBER) like the following
DeviceType: 7, DeviceNumber: 5, PartitionNumber: 1
are unique in the operation system and can be used to identify the same devices. The reference to the statement you can find in the documentation of IOCTL_STORAGE_GET_DEVICE_NUMBER control code:
The values in the
STORAGE_DEVICE_NUMBER structure are
guaranteed to remain unchanged until
the device is removed or the system is
restarted. It is not guaranteed to be
persistent across device restarts or
system restarts.
In the way you can compare \\.\SCSI0 devices and \\.\PhysicalDrive0 and find out the correspondence.