如何从驱动器号获取设备实例 ID?
我的流程从设备到达消息开始。我已成功从到达消息中获取驱动器号并打开 DVD 托盘。
我已经搜索了各种 Setup API 项目;但我还没有找到任何可以让我从驱动器号到设备实例 ID 的东西。
C# 或 VB.NET 中的解决方案将是理想的,但我愿意从任何其他语言中找出它,只要我能看到 API 调用。
提前致谢...
如何从驱动器号获取设备实例 ID?
我的流程从设备到达消息开始。我已成功从到达消息中获取驱动器号并打开 DVD 托盘。
我已经搜索了各种 Setup API 项目;但我还没有找到任何可以让我从驱动器号到设备实例 ID 的东西。
C# 或 VB.NET 中的解决方案将是理想的,但我愿意从任何其他语言中找出它,只要我能看到 API 调用。
提前致谢...
你不能直接这样做。
该链接是使用STORAGE_DEVICE_NUMBER
. 您可以在您的设备名称上使用 DeviceIoControlIOCTL_STORAGE_GET_DEVICE_NUMBER
来填充此结构。将此值放在一边。
然后,您需要通过SetupDiGetClassDevs
将 GUIDS 设置为适当的来获取系统上的设备信息,指示您感兴趣的驱动器。然后使用SetupDiEnumDeviceInfo
. 然后使用枚举接口SetupDiEnumDeviceInterfaces
,最后使用SetupDiGetDeviceInterfaceDetail
. 在返回的这个结构中,您可以获得一个 DevicePath,您可以使用它来获取STORAGE_DEVICE_NUMBER
上述内容。将其与您的驱动器号匹配STORAGE_DEVICE_NUMBER
,您现在已将驱动器号链接到您的结构。呸!在这个结构内部是一个 DevInst。
我知道现在对你来说已经晚了,但不是每个人都知道^^
我有同样的需求,这是我做到这一点的主线:
- 您需要一个窗口来接收设备到达和移除(如您所说)
- 然后创建一个 DeviceNotificationFilter 启动到 dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE
- 然后在窗口的消息循环中查找 VM_DEVICECHANGE
- 如果 wParam == DBT_DEVICEARRIVAL,当你收到它时,使用 lParam 检查它是 DBT_DEVTYPE_VOLUME(我在这里得到了驱动器的字母和类型)还是 DBT_DEVTYPE_DEVICEINTERFACE(在那里你可以使用你精心制作的 lParam 来获取 InstanceId从输入结构)。
当您连接驱动器时,您会先接收 DEVINTERFACE,然后再连接另一个驱动器。我只给出主线,因为我很久以前就这样做了,我这里没有代码,而且我在网上找到了很多代码片段(很久以前所以现在应该有更多^^^)也许msdn现在给出一个完整的代码示例来做到这一点。
如果您阅读本文并需要更多信息,如果许多人需要,我会回复或提供完整的文档答案。
希望它会帮助你们中的一些人。
我知道那是几年后的事了,但我不得不这样做,搜索把我带到了这里,@DanDan 的回答奏效了。为了为未来的人们节省大量工作,我想我会回馈一些并更明确地介绍该技术。您仍然需要编写一些代码,但我发现困难的部分如下代码:
正如 DanDan 所提到的,这个想法是使用CreateFile
并DeviceIoControl
获取STORAGE_DEVICE_NUMBER
与文件路径关联的磁盘的 Windows,然后使用 Setup API 枚举磁盘设备,直到我们找到其设备实例等于 SDN 的设备。
首先,这是您如何STORAGE_DEVICE_NUMBER
从路径中获取的摘要(例如c:\\users\\bob
);
C:
其前面加上\\\\.\\
\\\\.\\C:
CreateFileW
以获取元数据DeviceIoControl
withIOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
获取范围DiskNumber
从返回的第一个范围中获取成员。\\\\.\\PhysicalDrive<n>
哪里<n>
DeviceIoControl
与代码一起使用以IOCTL_STORAGE_GET_DEVICE_NUMBER
使其填写一个STORAGE_DEVICE_NUMBER
结构作为输出SetupDiGetClassDevs
与参数一起使用&GUID_DEVCLASS_DISKDRIVE
并DICGF_PRESENT
获取系统上的所有磁盘SetupDiEnumDeviceInfo
获取一个SP_DEVINFO_DATA
(在上面步骤 #8 返回的设备列表上)并调用下面的函数来确定哪个(如果有)与STORAGE_DEVICE_NUMBER
给定路径匹配。(这被编辑以删除我在 SO 网页上的自定义实用程序类,所以我可能引入了错误/错别字)
bool DoesDeviceInstanceEqualStorageDeviceNumber(
const std::string& devInstance,
STORAGE_DEVICE_NUMBER sdn)
{
// Open up this device instance, specifying that we want the *interfaces*.
// The interfaces are key key because examining them will let us get a
// string we can use the Win32 CreateFile function.
const auto hDevInfo = SetupDiGetClassDevsA(
nullptr,
devInstance.c_str(),
nullptr,
DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);
if (hDevInfo == INVALID_HANDLE_VALUE)
throws std::runtime_error("Unable to get disk devices");
DWORD dwSize = 0;
SP_DEVINFO_DATA did;
WCHAR buffer[4096];
did.cbSize = sizeof (did);
bool foundValidMatch = false;
int deviceNumber = 0;
// Iterate through all such devices, looking for one that has a storage device number that matches the given one.
while ( !foundValidMatch && SetupDiEnumDeviceInfo(hDevInfo, deviceNumber, &did))
{
deviceNumber++;
DEVPROPTYPE devPropType;
// We'll only bother comparing this one if it is fixed. Determine that.
const auto getPropResult = SetupDiGetDevicePropertyW (
hDevInfo,
&did,
&DEVPKEY_Device_RemovalPolicy, // Ask for the "removal policy"
&devPropType,
(BYTE*)buffer,
sizeof(buffer),
&dwSize,
0);
if (!getPropResult)
{
std::cerr << "Unable to to get removal policy for disk device: " << ::GetLastError() << std::endl;
continue;
}
/* This bit *would* skip removable disks, you wanted...
else if (buffer[0] != 1)
{
std::cerr << "Skipping removable disk device " << devInstance << std::endl;
continue;
}
*/
// OK this is a fixed disk so it might be the one we'll compare against
// 1. Get the very first disk interface from this particular disk device
// 2. Open a file on it
// 3. Query the resulting file for its device number.
// 4. Compare the device number to the one we determined above
// 5. If it matches ours, then we succeed. If not, continue
SP_DEVICE_INTERFACE_DATA devIntData;
devIntData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// Get the disk interfaces
const auto result = SetupDiEnumDeviceInterfaces(
hDevInfo,
&did, //&did,
&GUID_DEVINTERFACE_DISK, // Get Disk Device Interface (from winioctl.h)
0, // We only need the very FIRST one. I think...
&devIntData);
if (!result)
continue;
DWORD dwRequiredSize = 0;
// Want to get the detail but don't yet know how much space we'll need
// Do a dummy call to find out
SetupDiGetDeviceInterfaceDetail(
hDevInfo,
&devIntData,
nullptr,
0,
&dwRequiredSize,
nullptr);
if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError())
{
std::cerr << "Unable to get device interface Detail: " << ::GetLastError() << std::endl;;
}
else
{
// Get the detail data so we can get the device path and open a file.
std::vector<TCHAR> buf(dwRequiredSize);
auto pDidd = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(buf.data());
// WARNING: HARD CODED HACK
// ------------------------
// https://stackoverflow.com/questions/10405193/vb-net-hid-setupdigetdeviceinterfacedetail-getlasterror-shows-1784-error-inv
//
// Don't ask. Just do what they tell you.
// -----------------------------------------------------------------
#ifdef BUILD_64
pDidd->cbSize = 8;
#else
pDidd->cbSize = 6;
#endif
// -----------------------------------------------------------------
if (!SetupDiGetDeviceInterfaceDetail(
hDevInfo,
&devIntData,
pDidd,
dwRequiredSize,
&dwRequiredSize,
nullptr))
{
std::cerr << "Cannot get interface detail: " << ::GetLastError());
}
else
{
// FINALLY: We now have a DevicePath that we can use to open up
// in a Win32 CreateFile() call. That will let us get the
// STORAGE_DEVICE_NUMBER and compare it to the one we were given.
const auto hFile = ::CreateFileW(pDidd->DevicePath, 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
std::cerr << "Unable to open logical volume: " + devicePath << std::endl;
continue;
}
STORAGE_DEVICE_NUMBER sdnTest;
ZeroMemory(&sdnTest, sizeof(STORAGE_DEVICE_NUMBER));
if (0 == DeviceIoControl(
hDevInfo
IOCTL_STORAGE_GET_DEVICE_NUMBER,
nullptr, // output only so not needed
0, // output only so not needed
&sdnTest,
sizeof(STORAGE_DEVICE_NUMBER),
nullptr,
nullptr))
{
std::cerr << "Unable to determine storage device number: " << ::GetLastError() << std::endl;);
}
else
{
// All this for a one-line test...
foundValidMatch = sdnTest.DeviceNumber == sdn.DeviceNumber;
}
}
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return foundValidMatch;
}
我希望这可以让某人头疼