How does one uniquely identify a MIDI device with Windows Multimedia? - windows

I've been exploring the MIDI APIs available on macOS and Windows recently (Core MIDI and Windows Multimedia, respectively) and noticed:
On MacOS, after querying for the number of available sources, each source can be uniquely identified by checking the value of the property kMIDIPropertyUniqueID.
On Win32, I can't find a clear alternative - it seems that an input device's "ID" is no more than the index into the list of connected devices, which could change at any time as new devices are connected and disconnected. Information in the capabilities structure one can request from a device is also not particularly distinctive, as using two of the same MIDI keyboard at once would result in two identical capability sets right down to the product name.
Is there some way to uniquely identify these devices in WinMM?

Short answer is no.
ID of a device in WinMM is indeed just an index in the devices list. So if you unplug one device and plug another one with the same properties (name, for example), you won't be able to determine whether the device you work with is the old one or new. Name, of course, can be the same, so that's not an option.
So from programming side there is no way to distinguish two MIDI devices with the same properties in Windows. In an app you can provide a button like "Refresh devices" or "Test device" to be up to date with current devices and to be able to determine which object in GUI corresponds to a MIDI device to.
As for macOS, kMIDIPropertyUniqueID is an option, BUT there are nuances. From the documentation on the constant:
The system assigns unique IDs to all objects. You may set this
property on virtual endpoints; however, doing so may fail if the ID
isn’t unique.
So in some cases you can get not unique value. In my opinion, the most reliable way to identify a device in macOS is to use its reference. For example, when you get a source device with MIDIGetSource you get MIDIEndpointRef as the result. In fact it's a UInt32 number which is truly unique in the scope of the system.
So I in my .NET library DryWetMIDI rely on MIDIEndpointRef to distinguish MIDI devices in macOS. Also it's possible to provide MIDI devices watching (adding/removing). But for Windows it's not possible unfortunately.

Unfortunately there is no equivalent in WinMM.
The best you can do is open the device to get a handle to it. The handle will be unique and will always refer to the opened device, even if other devices are added and removed.
Once you have the handle, you can use midiInGetID() or midiOutGetID() to get the ID in case it has changed.

Related

Platform device and platform driver linking

While going through the usb code in linux. I came across platform_device_add() api.
My question is when we create a platform device using the above api, how does the associated driver gets bind to it?
As per my understanding is that the platform drivers register itself and when a match occurs with the device tree compatible string and the one mentioned in the driver, the probe of the driver is called.
So does it use something like a "compatible string" as in the case of the device tree?
Does it use the "name" field present in the "struct platform_device" and match it with the "struct platform_driver" 's "name" field.
Please correct me if I am wrong. Also any text source to learn more on this will be helpful as I am new to this.
So, you have asked a few questions here.
We call platform_device_add() whenever we 100% sure that on the given platform we expect the device in question to be present and functioning.
In most cases ->probe() callback is being called synchronously either at the moment of device addition (if driver is already loaded) or at driver loading stage if device is present in the system.
It does not use Device Tree, it's purely board file based enumeration (device presence is identified by other means than ACPI or Device Tree).
Indeed it uses driver name to match. When the API is called it matches by device name. See implementation of platform_match_id() for the actual code.

Detect if USB is Inserted through Application

I want to create an application or modify USB in a way so that, upon insertion into any PC, I can get the information that PC was inserted.
eg. upon insertion, I can read PC name and make an API call with this as post data so I'm able to know that my USB was inserted in some PC. But this should happen right away as USB is read by the machine, so even if the user formats it thereafter, it should not matter.
If it was earlier windows, I could write autorun and that would work. But I want this detection mechanism for Windows 7 and above.
I have done some research on the topic but could not find any reliable content. Some articles were related to USB based hacking attacks by changing wiring (USB hardware, to harm the computer) or something like that. But I totally don't want to do that. Just the detection, that USB was used.

retrieving detailed usb midi device information on windows xp

The function midiOutGetDevCaps returns a structure MIDIOUTCAPS.
I'd need more specific information when querying a usb midi device on windows xp, in particular I'd need the information displayed under "Location" when opening the respective device using the Device Manager.
I need this information in order to programmatically distinguish between several MIDI Interfaces connected to a computer. Using midiOutGetDevCaps, I uniformly get "USB Audio Device" for every midi usb interface connected to the computer, so distinguishing between the interfaces is impossible.
To make matters worse, this string is localized, so e.g. on a German Windows you'll get "USB Audiogerät" instead of "USB Audio Device".
I guess it depends on how desperate you are. I've had my own run in with USB devices. In my case I needed to enumerate certain USB COM port related devices . . . regardless if they are currently attached to the system or not.
It is all company proprietary code, sorry I cannot post it, but the search for all information regarding USB related devices starts here (Perl):
$hostnamePrefix = "//$hostname/";
my $baseKey = "${hostnamePrefix}HKEY_LOCAL_MACHINE/System/CurrentControlSet/";
my $regVidList = Win32::TieRegistry->new("${baseKey}Enum/USB/", $optionsRef);
If memory serves me it is a reasonably straight forward structure. I believe you actually have to loop through two separate sections of the registry to get everything you need . . . if you are desperate enough to attempt this, I'm happy to answer questions where I can, but posting code would required approval from our legal department. (Not impossible, but it would take weeks to obtain.)
Also, while this will work on XP . . . I have no idea how it will work on Win7. (I don't know either way, nobody has tried it yet that I am aware of.)
Coding this was not that bad (resulting Perl Script is around 1000 lines of code which is almost 50% comments), but working out all the relationships between the keys and the special cases took several days.

What's the best way to authorize a USB Key

We have an auto update for our software that is installed via USB key (with the auto run). If I wanted to ensure that only authorized USB Keys were used, what's the best way?
Our installer is already signed, and it won't run otherwise. But I'm more wanting to inspect the USB Key for a signed installer, and if it's not there, just ignore, or even "Eject" the USB device.
And I should be able to tell the difference (in code) between a usb storage device, and say a camera, or keyboard.
I'm only wanting to disable non-authorized storage devices.
Thank you for your ideas.
non-authorized storage devices? This depends on how secure you want it to be. For the most secure level, it would consist of:
special firmware written to the flash drive to get extra "meta info" (read: expensive custom manufacturing of flash drives)
special windows driver to read that meta info from the flash drive
your program talking to that device driver to confirm it's authorized.
Or to the least secure level you have these options:
using a hidden file and a special key(possibly hashed time of last filesystem modification or something?) (dd breakable)
dropping below the filesystem level and recreating your own very simple filesystem.. (more security through obscurity though and dd could break that)
Also, for the "most secure" option, you really need a more secure way of running the program than auto-run and a device driver(which could be half-baked to make anything appear authorized). Why do you want it to only update from an authorized flash drive anyway?
You might be able to read the USB drive's serial number (assuming you get USB drives that have serial numbers; not all do). Then your application could call home to get the latest list of authorized serial numbers, and check to see if there is a match.
Earlz response is good, though I don't think you'd need custom manufacturing of flash drives... you would just need flash drives with some sort of unique firmware encrypted identifier. Perhaps something in the Kingston Data Traveler Line might do the trick. (I've never actually used one of these encrypted usb sticks, so I'm a bit foggy on the actual implementation details).

Question regarding guidInstance in DirectInput library; also deals with enumeration of devices

Regarding guidInstance in DIDEVICEINSTANCE
Microsoft says:
Unique identifier for the instance of the device. An application can save the instance globally unique identifier (GUID) into a configuration file and use it at a later time. Instance GUIDs are specific to a particular computer. An instance GUID obtained from one computer is unrelated to instance GUIDs on another.
So, if I connect my device to the computer and my program does enumeration and finds the guid, do I ever have to enumerate again? Even if the user plugs and unplugs the device. If another device of the same type is plugged in, does it still recognize that the second device is not the same as the first and therefore requires a different guid? Should I just renumerate all the interfaces all the time my program runs to find my device or is once enough for a given pc?
Thanks.
I'm actually trying to solve a similar problem. According to the MSDN here, it looks like InstanceGUID is supposed to always be the same on the same computer. I've verified that if I unplug my USB device and plug it into a different port, it does indeed keep the same Instance GUID. However, if a different user logs into the same PC, DirectInput shows the same device having a different InstanceGUID!! I can't find any acknowledgement from Microsoft that this is a known problem.
So, I can partially answer your question. If you have two identical devices, you will get different InstanceGUIDs, and identical ProductGUIDs. Those InstanceGUIDs will stay consistent if you unplug your devices and move them to different USB ports. HOWEVER you will get different InstanceGUIDs if a different user logs in. At least I can verify that this is an issue on Windows 7 64bit.
The InstanceGuid will always be a unique identifier for every device plugged in - but if you remove the installation information (e.g. uninstalling a usb device) you also lose that InstanceGuid. The device will get some new unpredictable Guid when plugged in again.
The ProductGuid will always be the same for one device, since it's stored in the devices USB HID chip. It may happen though that two devices of the exact same type have the same ProductGuid. If they do, you can only identify them by their InstanceGuid (which may become invalid in some cases, as written above...).

Resources