Are there name restrictions on "Device Instance Path" names? - winapi

I am asking about Win32 Device Instance Path names. You see these types of paths in the Device Manager. An example device instance path name is ACPI\DLLK0706\3&11583659&0 for a keyboard.
Are there any restrictions on Device Instance Path names? For instance, I am not seeing any path names that exceed 255 characters in length, or use any non-ASCII characters, but are these restrictions real or just a coincidence?

Device Instance Path returned by PDO device when it handle IRP_MN_QUERY_ID. and exist several restrictions for length (must be less than MAX_DEVICE_ID_LEN characters long ) and can not use any non-ASCII characters (all must be in [0x20, 0x80) range and must not be ';' in string )
If a driver returns an ID with an illegal character, the system will
bug check. Characters with the following values are illegal in an ID
for this IRP:
Less than or equal to 0x20 (' ')
Greater than 0x7F
Equal to 0x2C (',')
A driver must conform to the following length restrictions for IDs:
Each hardware ID or compatible ID that a driver returns in this IRP must be less than MAX_DEVICE_ID_LEN characters long. This constant
currently has a value of 200 as defined in sdk\inc\cfgmgr32.h.
The container ID that a driver returns in this IRP must be formatted as a globally unique identifier (GUID), and must be
MAX_GUID_STRING_LEN characters, which includes the null terminator.
If a bus driver supplies globally unique instance IDs for its child devices (that is, the driver sets DEVICE_CAPABILITIES.UniqueID for
the devices), then the combination of device ID plus instance ID must
be less than (MAX_DEVICE_ID_LEN - 1) characters. The operating
system requires the additional character for a path separator.
If a bus driver does not supply globally unique instance IDs for its child devices, then the combination of device ID plus instance
ID must be less than (MAX_DEVICE_ID_LEN - 28). The value of
this equation is currently 172.

Related

How to identify a HID after it's moved to a different port on Windows

I'm on Windows and am trying to store calibration data for game controllers connected via USB and am trying to find a value which uniquely identifies them in a port independent way.
There is the HidD_GetSerialNumberString function but i've read here that it's uncommon for devices to have serial numbers and indeed when i try to read one f.e. from a PS4 controller HidD_GetSerialNumberString returns FALSE and GetLastError returns ERROR_INVALID_PARAMETER.
Is there any other data available which can be accessed to achieve this?
You can try to use instance ID for your HID device (call CM_Get_Device_Interface_Property with device interface path and DEVPKEY_Device_InstanceId property and use string after last & char). It should be unique and persistent per system restarts. But it is not guaranteed if serial number is not provided (in this case instance ID will be different if device is plugged into different usb port)...
More info on this here: https://stackoverflow.com/a/56885175/1795050

how to parse USB Device Instance ID (DIID)?

I want to know how "Device Instance ID" is made or how to parse it.
Take the following string as an example:
USB\VID_093A&PID_2700&MI_00\6&2703A67B&0&0000
As per my knowledge:
USB tells that this is a USB device
VID_093A indicates its vendor ID
similarly, PID_2700 is the product ID
However, I don't know about the rest.
MI is for multiple interfaces. A composite device has several interfaces.
6&2703A67B&0&0000 is the Instance ID.
The 6 at the beginning corresponds to the device node depth.
0 are root devices (e.g. volmgr, acpi_hal, they have Root\ prefix)
1 are acpi_hal devices (e.g. acpi (uses PNP0C08\0 instead of vid/pid/1), they have ACPI_HAL\ prefix)
2 are acpi devices (e.g. root pci bus controller (uses PNP0A08\0 instead of vid/pid/2), they have ACPI\ prefix)
3 are pci devices (e.g. xhci controller, they have PCI\ prefix)
4 are xhci devices (e.g. root hub, they have IUSB3\ prefix)
5+ are hub devices (e.g. usbccgp FDOs for composite devices, ubstor for storage etc., they have USB\ prefix)
6+ are usbstor devices (disk FDOs, USBSTOR\ prefix) or usbccgp composite interfaces (e.g. hidusb FDOs for input devices, USB\ prefix and have an MI)
7+ are endpoints (kbdhid FDOs for keyboards, mouhid FDOs for mice, HID\ prefix and have an MI)
The ID 2703A67B is an ID assigned by the parent. The xhci controller assigns the same one to all its root hubs; the separate hubs are identified by the value after the final ampersand, which is a simple incremental value. The root hub gives its child devices an ID that is the same across all devices and reboots; the separate devices are identified by the value after the final ampersand, again an incremental value. A composite device gives its children an ID that changes based on what hub/port it is plugged into; the separate interfaces are identified by the value after the final ampersand. An interface gives its children endpoints an ID that changes based on what hub/port it is plugged into; the separate endpoints are identified by the value after the final ampersand.
I can confirm that the ID that a hub assigns to its children changes if the hub is plugged into a different port on the root hub or a different hub altogether. I wrote '+' to indicate the presence of possible nested hubs. The PCI bus could also be nested and have a child bus (via PCIe to PCI bridge or PCIe root port aka. a PCIe to PCIe bridge), but I decided to leave that out. A root port is just a PCI device, basically a bridge/controller to a bus with only one slot (or more slots if the lanes are configured on the port to be split up), with a PCI\ prefix, and the child device will also have a PCI\ prefix.
By that token, the ID that the xHCI controller assigns probably depends on the PCI slot, and the ID the PCI bus controller assigns is probably dependent on what port the subordinate bus controller is connected to or whether it is the root controller.
This is why it installs drivers again when you insert a device into another port (unless it has a serial number). The drivers are considered installed when there is a registry entry for the DIID. The USB device will have a separate entry for each port and root hub combination they're plugged into. The composite device interfaces will have a separate entry for each port and root hub as well, as will the endpoints.
If the device has a serial number, which is uncommon, then the instance ID will be the serial number, and this will be the same regardless of where it is plugged into the system. If a composite device has a serial number instance ID then its interfaces probably have the same instance ID as that because the MI in the Device ID tells them apart. The endpoints are unlikely to have their own serial numbers and probably use the regular instance ID scheme.
Well, you really cant. This is the response from Microsoft regarding the same..
the device instance ID should be treated as opaque. if you want the VID/PID, query for the hardware and/or compa IDs and parse those. the hardware IDs are not considered opaque (but you still have to assume new hardware IDs will show up, so you need to detect the pattern you want to parse and have proactive code that handles other types of formats).
source: http://social.msdn.microsoft.com/Forums/en-US/4ff692bc-97c9-4943-b1ee-ec4f098e3b14/how-to-detect-sim-card-change-or-imsi-change-programatically-in-windows-phone-8?forum=wpdevelop
The Microsoft Device Instance ID page explains well how a Device Instance ID string is composed.
This page explains how a USB Identifier string (which composes the Device ID part of a Device Instance ID) is created.
Specifically, for your example:
USB\VID_093A&PID_2700&MI_00 is the Device ID, and
6&2703A67B&0&0000 is the Instance ID
Moreover, the Device ID tells you that:
USB\: this is a device under the USB enumerator
VID_093A: Pixart, Inc. manufactured this USB Device (you can find the USB Vendor ID list here)
PID_2700: this is the Product ID
MI_00: This is a Multiple Interface USB Device

WIA - determining the page count

I am using WIA2.0 on VB6.
I could do scanning without anyissues..
But, the problem is i could not figure out the number of pages scanned when it's ADF.
I could see something like this in msdn.
WIA_DPS_ENDORSER_STRING with a token as
$PAGE_COUNT$ The number of pages transferred.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms630195(v=vs.85).aspx
But, i don't know how to access this in VB6.
Any help would be appriciated.
Thanks.
-Dinakaran.AS
As far as I can tell this count is probably strictly local to the scanner itself when it has an endorser printer. It may even be a "hardware" counter much like photocopier counters. It probably can only be reset using a physical key or administrative password at the scanner to unlock and reset it. Looks as if it is meant for auditing purposes.
WIA_DPS_ENDORSER_CHARACTERS (ScannerDeviceEndorserCharacters)
Contains all the valid characters that an application can use to
create valid endorser strings. An endorser is a printer installed on a
scanner that imprints a text message on every page scanned. The
minidriver should validate the setting of the WIA_DPS_ENDORSER_STRING
property against the valid character set in this property. The
minidriver creates and maintains this property.
WIA_DPS_ENDORSER_STRING (ScannerDeviceEndorserString)
Contains a string that is to be endorsed (in other words, printed) on
each page that the minidriver scans. An application sets this property
using the valid character set that is reported in the
WIA_DPS_ENDORSER_CHARACTERS property. The minidriver should endorse
documents only if a string is set in this property. An empty string
means that the endorser functionality is disabled.
Then we have:
WIA_IPS_PAGES (ScannerPicturePages)
Note: This property is supported only by Windows Vista and later.
Contains the current number of pages to be acquired from an automatic
document feeder. The minidriver creates and maintains this property.
Type: VT_I4; Access: Read/Write; Valid values: WIA_PROP_RANGE This is
zero through the maximum number of pages that the scanner can scan.
The value is ALL_PAGES (= 0) if the scanner can scan continuously.
An application reads this property to determine the document feeder's
page capacity. The application also sets this property to the number
of pages it is going to scan.

The Uniqueness of IOCTL_MOUNTDEV_QUERY_UNIQUE_ID

The documentation on IOCTL_MOUNTDEV_QUERY_UNIQUE_ID is a bit confusing... exactly what kind of ID should be returned in the MOUNTDEV_UNIQUE_ID structure?
The documentation for
typedef struct _MOUNTDEV_UNIQUE_ID {
USHORT UniqueIdLength;
UCHAR UniqueId[1];
} MOUNTDEV_UNIQUE_ID, *PMOUNTDEV_UNIQUE_ID;
says:
UniqueIdLength
Contains the length of unique volume ID.
UniqueId
Contains the unique volume ID. The format for unique volume names is "\??\Volume{GUID}\", where GUID is a globally unique identifier that identifies the volume.
However, there's something weird here: What should be the exact format of UniqueId? If it's meant to be in the \??\Volume{GUID}\ format, then what's the point of the UniqueIdLength field -- aren't they all the same size? Otherwise, what format does the device ID need to be in?
Furthermore, is this a device ID or a volume ID? In other words, is this supposed to be unique per medium (e.g. CD) or per device (CD drive)?
This kind of struct is pretty common in MS APIs - the UniqueID[1] variable is just a placeholder, in reality it's used as a UniqueId[UniqueIdLength] variable.
The ID is unique both per medium and per device - it depends on whether you're talking to a volume driver or a device class driver. The ID is intended to identify "something that can be mounted" - so e.g. a CD-ROM device, a fixed disk partition or an unpartitioned removable disk. The mount manager uses the ID a.o. to lookup where this particular volume was mounted before, and remount it at the same point.
From MSDN
Maybe there is misunderstanding about this structure.
I called DeviceIoControl(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID) and got a string as the similar format to Device Interface Path, but it is just different of the prefix 4 characters, and then it saved in registry \HKLM\SYSTEM\MountedDevices.
MOUNTDEV_UNIQUE_ID is acquired upon a volume arrival notification where mountmgr!MountMgrMountedDeviceArrival invokes mountmgr!QueryDeviceInformation, which sends a IOCTL_MOUNTDEV_QUERY_UNIQUE_ID IRP to the volume PDO stack, which volmgr picks up, and I'm not sure what routine it is but in XP's ftdisk it was ftdisk!FtpQueryUniqueIdBuffer that determined whether to set the UniqueID member to a GPT partition GUID, a MBR signature + offset, or the symbolic link like STORAGE#RemovableMedia.... The symbolic link is based on the name of devnode that the volume PDO is part of, and the symbolic link was generated by IoRegisterDeviceInterface, which was then stored in the volume extension before alerting mountmgr of the volume arrival in the first place (alerting is done by IoSetDeviceInterfaceState Enable). On Windows 7 the volume PDO devnode name is STORAGE\Volume\_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_B lade&Rev_1.27#4C530399920812105355&0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}, the symbolic link is STORAGE#Volume#_??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b} but the MountedDevices data is _??_USBSTOR#Disk&Ven_SanDisk&Prod_Cruzer_Blade&Rev_1.27#4C530399920812105355&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}. The symbolic link that is created is always to the volume PDO name, because the volume PDO is supplied to the call, which is \Device\HarddiskVolumeX.
FtpQueryUniqueIdBuffer uses the MBR signature and partition offset if it's an MBR disk, and uses the GPT partition GUID if it's a GPT disk, and uses the symbolic link if it's neither, which tends to be a regular USB drive mass storage volume that doesn't have a boot sector, and ftdisk considers a disk without a boot sector to be a 'superfloppy', so it looks for that flag on the volume extension. So that's how unique it is, MBR signature and GPT GUID uniqueness speak for themselves, but the symlink doesn't so I'll elaborate: it contains the DIID of the USBSTOR device, which includes the USB serial number, or if it doesn't have one, a system wide unique number determine according to the following scheme.
Mountmgr creates further symbolic links between the drive letter and volume device name, and the volume GUID and the volume device name, and then puts them in the MountedDevices database but uses the unique ID instead of the volume device name. The volume GUID \??\Volume{GUID}\ it generates using ExUuidCreate. IOCTL_MOUNTMGR_QUERY_POINTS shows each symbolic link for a mounted device, so it will show \DosDevices\C: -> \Device\HarddiskVolumeX and \??\Volume{GUID}\ -> \Device\HarddiskVolumeX and the unique ID of the mounted device and the name of the mounted device. It does not however show the symbolic link to \Device\HarddiskVolumeX created by IoRegisterDeviceInterface because the symbolic link wasn't created by mount manager, so it doesn't know about it.

Windows Maximum Length of Key Container Name

Can anyone confirm that the maximum length of a key container name in Windows is 260 characters. I expect this to be the size because the value is stored as a file, but I have not found the specific answer as of yet.
In the meantime I'll see what trial and error I can do.
Updated:
I did trial and error with aspnet_reiis.exe and discovered that 260 is indeed the maximum length. 261 and above causes key creation failure.
I don't think there is one, or at least you shouldn't rely on there being one. From the documentation:
The key container name. This is a null-terminated string that identifies the key container to the CSP. This name is independent of the method used to store the keys. Some CSPs store their key containers internally (in hardware), some use the system registry, and others use the file system. When dwFlags is set to CRYPT_VERIFYCONTEXT, pszContainer must be set to NULL.
Piratically speaking you would probably be safe with 256 as that is the maximum length of both a file name and a registry key.

Resources