如何从驱动器号转到设备实例ID?
我的流程从设备到达消息开始。我已经成功地从到达消息和打开DVD托盘中获取驱动器号。
我搜索了各种Setup API项目;但是我没有找到任何能让我从驱动器号转到设备实例ID的内容。
C#或VB.NET中的解决方案是理想的,但只要我能看到API调用,我就愿意从任何其他语言中找到它。
提前致谢...
答案 0 :(得分:4)
你不能直接这样做。
链接是使用STORAGE_DEVICE_NUMBER
。您可以在设备名称上使用带有IOCTL_STORAGE_GET_DEVICE_NUMBER
的DeviceIoControl来填充此结构。把这个值放在一边
然后,您需要使用SetupDiGetClassDevs
将GUID设置为适当的方式在您的系统上获取设备信息,指示您感兴趣的驱动器。然后使用SetupDiEnumDeviceInfo
枚举设备。然后使用SetupDiEnumDeviceInterfaces
枚举接口,最后使用SetupDiGetDeviceInterfaceDetail
获取信息。在返回的此结构中,您可以获得可用于获取STORAGE_DEVICE_NUMBER
的DevicePath,如上所述。将其与您的驱动器号中的STORAGE_DEVICE_NUMBER
相匹配,现在您已将驱动器号与您的结构相关联。唷!在这个结构里面是一个DevInst。
答案 1 :(得分:1)
我知道现在已经很晚了,但不是每个人都知道^^
我有同样的需求,这是我如何做到的主线:
- 你需要一个窗口来接收和移除设备(如你所说)
- 然后创建一个启动到dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE的DeviceNotificationFilter
- 然后在窗口的消息循环中查找VM_DEVICECHANGE
- 如果wParam == DBT_DEVICEARRIVAL你收到它,请使用lParam来检查它是否是DBT_DEVTYPE_VOLUME(我在这里得到了字母和驱动器的类型)或DBT_DEVTYPE_DEVICEINTERFACE(你可以使用你的wellPated lParam来从输入结构中获取InstanceId。
连接驱动器时,首先接收DEVINTERFACE,然后接收另一个。 我只给了主线因为我很久以前就这么做了,我没有这里的代码,而且我在网上找到了很多代码片段(很久以前所以现在应该有更多的^^^)也许msdn现在提供一个完整的代码示例。
如果您阅读此内容并需要更多信息,如果有需要,我会回复或提供完整的文件回答。
希望它会帮助你们中的一些人。
答案 2 :(得分:0)
我知道已经过了几年,但是我不得不这样做,搜索将我带到了这里,@ DanDan的答案起作用了。为了节省将来的人们很多工作,我想我会回馈一点,并更明确地介绍这项技术。您仍然需要编写一些代码,但是我发现困难的部分如下所示:
如DanDan所述,其想法是使用CreateFile
和DeviceIoControl
来获取与文件路径关联的磁盘的Windows STORAGE_DEVICE_NUMBER
,然后使用Setup API枚举磁盘直到找到一个其设备实例等于SDN的设备。
首先,这是如何从路径中获取STORAGE_DEVICE_NUMBER
的摘要(例如c:\\users\\bob
);
C:
)并在其前面加上\\\\.\\
,这样您就拥有\\\\.\\C:
CreateFileW
与该路径打开以获取元数据DeviceIoControl
与IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
一起使用以获取范围DiskNumber
成员。\\\\.\\PhysicalDrive<n>
,其中<n>
是第一个扩展区中的那个DiskNumber 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;
}
我希望这可以使人免于头痛