So i'm building an app for a school PC that tracks all inserted devices.
I managed to use RegisterDeviceNotification()
to get a notification in the main thread whenever i plug in or remove a device.
All i can get though, is the LParam
, a pointer that is device unique.
I can't find anything about how to get the friendly name of the device using that LParam. The only resource i can find is this CodeProject from 2006 (in C++).
I can't find anything on pinvoke.net and the only thing i found (i don't remember exactly where) is using a ManagementObjectSearcher
to get this data, but it finds null data. (here's the code)
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select Name from Win32_PnpEntity");
foreach (ManagementObject devices in searcher.Get())
{
foreach (var v in devices.Properties)
{
Console.WriteLine(v.Value);
}
}
searcher.Dispose();
Can anyone please help me figure out how to get the friendly name of the device?
you need register device notifications with
RegisterDeviceNotificationW
static DEV_BROADCAST_DEVICEINTERFACE dbd = { sizeof(dbd), DBT_DEVTYP_DEVICEINTERFACE };
_hDevNot = RegisterDeviceNotificationW(hwnd, &dbd,
DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
as result you will receive WM_DEVICECHANGE
message
here you need check wParam for for DBT_DEVICEARRIVAL
and
DBT_DEVICEREMOVECOMPLETE
events
check that dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE
inside DEV_BROADCAST_DEVICEINTERFACE_W.dbcc_name
you got
device interface name
you can use this name inside CM_Get_Device_Interface_PropertyW
function with DEVPKEY_Device_InstanceId
on
DBT_DEVICEARRIVAL
event
you got Device Instance ID
use it in call CM_Locate_DevNodeW
use result in call CM_Get_DevNode_PropertyW
with
DEVPKEY_NAME
or DEVPKEY_DeviceInterface_FriendlyName
on DBT_DEVICEREMOVECOMPLETE
- you can only look in self
database (if you create it on arrival) for such name and friendly
name.
demo code:
struct DeviceName : public LIST_ENTRY
{
ULONG InterfaceHash;
WCHAR Name[];
void* operator new(size_t cb, size_t len)
{
return LocalAlloc(0, cb + len);
}
void operator delete(void* pv)
{
LocalFree(pv);
}
};
volatile const UCHAR guz = 0;
CONFIGRET GetFriendlyNameByDevNode(DeviceName** pp, DEVINST dnDevInst)
{
CONFIGRET status;
ULONG cb = 32;
DEVPROPTYPE PropertyType;
do
{
if (DeviceName* p = new(cb) DeviceName)
{
status = CM_Get_DevNode_PropertyW(
dnDevInst, &DEVPKEY_DeviceInterface_FriendlyName, &PropertyType, (PBYTE)p->Name, &cb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
*pp = p;
return CR_SUCCESS;
}
else
{
status = CR_WRONG_TYPE;
}
}
delete p;
}
else
{
status = CR_OUT_OF_MEMORY;
}
} while (CR_BUFFER_SMALL == status);
return status;
}
CONFIGRET GetFriendlyNameByInterface(DeviceName** pp, PCWSTR pszDeviceInterface)
{
// RTCu must be disabled !
ULONG cb = 0, rcb = 64;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
CONFIGRET status;
union {
PVOID pv;
PWSTR DeviceID;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
} while (CR_BUFFER_SMALL == (status = CM_Get_Device_Interface_PropertyW(
pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0)));
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DEVINST dnDevInst;
status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL);
return status == CR_SUCCESS ? GetFriendlyNameByDevNode(pp, dnDevInst) : status;
}
else
{
status = CR_WRONG_TYPE;
}
}
return status;
}
case WM_DESTROY:
if (_hDevNot)
{
UnregisterDeviceNotification(_hDevNot);
PLIST_ENTRY head = &_DevListHead, entry = head->Flink;
while (entry != head)
{
DeviceName* p = static_cast<DeviceName*>(entry);
entry = entry->Flink;
delete p;
}
}
break;
case WM_DEVICECHANGE:
switch (wParam)
{
case DBT_DEVICEREMOVECOMPLETE:
case DBT_DEVICEARRIVAL:
if (reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceName* p;
ULONG InterfaceHash;
UNICODE_STRING dbcc_name;
RtlInitUnicodeString(&dbcc_name, reinterpret_cast<PDEV_BROADCAST_DEVICEINTERFACE>(lParam)->dbcc_name);
RtlHashUnicodeString(&dbcc_name, FALSE, HASH_STRING_ALGORITHM_DEFAULT, &InterfaceHash);
if (wParam == DBT_DEVICEARRIVAL)
{
if (CR_SUCCESS == GetFriendlyNameByInterface(&p, dbcc_name.Buffer))
{
p->InterfaceHash = InterfaceHash;
InsertHeadList(&_DevListHead, p);
DbgPrint("inserted %S ( %wZ )\n", p->Name, &dbcc_name);
}
}
else
{
PLIST_ENTRY head = &_DevListHead, entry = head;
while ((entry = entry->Flink) != head)
{
if (static_cast<DeviceName*>(entry)->InterfaceHash == InterfaceHash)
{
DbgPrint("removed %S ( %wZ )\n",
static_cast<DeviceName*>(entry)->Name, &dbcc_name);
RemoveEntryList(entry);
delete static_cast<DeviceName*>(entry);
break;
}
}
}
}
break;
}
return 0;
case WM_CREATE:
InitializeListHead(&_DevListHead);
static DEV_BROADCAST_DEVICEINTERFACE dbd = { sizeof(dbd), DBT_DEVTYP_DEVICEINTERFACE };
_hDevNot = RegisterDeviceNotificationW(hwnd, &dbd, DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
break;