- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
当启用 Windows 10 存储空间时,我需要获取系统中所有物理磁盘的以下信息。
到目前为止我尝试了什么:
使用 WMI 类 MSFT_PhysicalDisk虽然这个类给了我适配器号(所以我可以不用磁盘 PNP),但当磁盘连接到不同的 PCI 存储 Controller (例如 Marvell 92xx SATA 6g Controller )时,它提供的位置信息并不完整。
二手 SetupDiGetClassDevs使用 GUID_DEVINTERFACE_DISK
,将句柄传递给 SetupDiGetDeviceInterface并使用 SetupDiGetDeviceInterfaceDetail用于位置信息(总线/目标 ID/LUN)、PNP Id 和设备路径。我可以将设备路径传递给 CreateFile并获取其余信息(类似于 this 方法)。这个问题是它没有给我所有的物理磁盘。省略存储空间池下的磁盘。
使用与第二种方法类似的方法,但使用 SetupDiEnumDeviceInfo 代替 SetupDiGetDeviceInterface 和 SetupDiGetDeviceInterfaceDetail。和 CM_Get_DevNode_Registry_Property (使用 here 中的磁盘驱动器 Guid)。虽然这为我提供了所有物理磁盘的位置和 PNP id,但我不能在这里使用任何东西(据我所知)来调用 CreateFile 并获取其余详细信息。
启用存储空间后,如何获取每个物理磁盘的上述详细信息?
附带说明一下,如果有一种方法可以使用 CreateFile 和 DeviceIoControl 从磁盘索引中获取磁盘 PNP id ,这对我也很有帮助。
最佳答案
首先我们需要通过调用CM_Get_Device_Interface_ListW
枚举系统中的所有磁盘和 CM_Get_Device_Interface_List_SizeW
与 GUID_DEVINTERFACE_DISK
#include <Shlwapi.h>
#include <cfgmgr32.h>
#undef _NTDDSTOR_H_
#include <ntddstor.h>
#include <ntdddisk.h>
static volatile UCHAR guz;
CONFIGRET EnumDisks(PCSTR prefix, PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
DbgPrint("Interface=[%S]\n", pszDeviceInterface);
HANDLE hFile = CreateFileW(pszDeviceInterface, FILE_GENERIC_READ,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
GetDiskPropertyByHandle(hFile);
CloseHandle(hFile);
}
GetPropertyByInterface(prefix, pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return CR_SUCCESS;
}
}
}
CONFIGRET EnumDisks()
{
char prefix[256];
memset(prefix, '\t', sizeof(prefix));
prefix[sizeof(prefix) - 1] = 0;
prefix[0] = 0;
return EnumDisks(prefix + sizeof(prefix) - 1, const_cast<PGUID>(&GUID_DEVINTERFACE_DISK));
}
CM_Get_Device_Interface_ListW
返回多个以 NULL 结尾的 Unicode 字符串,每个字符串代表接口(interface)实例的符号链接(symbolic link)名称。
从一方面来说,这个符号链接(symbolic link)名称可以传递给 CreateFileW
以打开磁盘设备。在此之后我们可以将一些 ioctl 设置到磁盘 - 用于获取
例子:
void GetDiskPropertyByHandle(HANDLE hDisk)
{
HANDLE hPartition;
IO_STATUS_BLOCK iosb;
STORAGE_DEVICE_NUMBER sdn;
GET_LENGTH_INFORMATION li;
NTSTATUS status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, &sdn, sizeof(sdn));
if (0 <= status && sdn.DeviceType == FILE_DEVICE_DISK && !sdn.PartitionNumber)
{
DbgPrint("\\Device\\Harddisk%d\n", sdn.DeviceNumber);
WCHAR sz[64], *c = sz + swprintf(sz, L"\\Device\\Harddisk%d\\Partition", sdn.DeviceNumber);
WCHAR szSize[32];
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_LENGTH_INFO, 0, 0, &li, sizeof(li))))
{
DbgPrint("Length = %S (%I64x)\n",
StrFormatByteSizeW(li.Length.QuadPart, szSize, RTL_NUMBER_OF(szSize)),
li.Length.QuadPart);
}
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
PSTORAGE_DEVICE_DESCRIPTOR psdd;
PCSTR psz;
};
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery };
ULONG cb = 0, rcb = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x40, PartitionCount = 4;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
switch (status = (NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, cb)))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR))
{
if (psdd->Size > cb)
{
rcb = psdd->Size;
status = STATUS_BUFFER_OVERFLOW;
}
else
{
if (psdd->SerialNumberOffset)
{
DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
}
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
break;
}
} while (status == STATUS_BUFFER_OVERFLOW);
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 0, 0, buf, cb)))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
RtlInitUnicodeString(&ObjectName, sz);
DbgPrint("%wZ\nOffset=%S ", &ObjectName,
StrFormatByteSizeW(PartitionEntry->StartingOffset.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
DbgPrint("Length=%S\n",
StrFormatByteSizeW(PartitionEntry->PartitionLength.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
char PartitionName[256], *szPartitionName;
switch (PartitionEntry->PartitionStyle)
{
case PARTITION_STYLE_MBR:
DbgPrint("MBR: type=%x boot=%x", PartitionEntry->Mbr.PartitionType, PartitionEntry->Mbr.BootIndicator);
break;
case PARTITION_STYLE_GPT:
if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID))
{
szPartitionName = "UNUSED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_SYSTEM_GUID))
{
szPartitionName = "SYSTEM";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RESERVED_GUID))
{
szPartitionName = "RESERVED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_BASIC_DATA_GUID))
{
szPartitionName = "DATA";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RECOVERY_GUID))
{
szPartitionName = "RECOVERY";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_SNAPSHOT_GUID))
{
szPartitionName = "SNAPSHOT";
}
else
{
sprintf(szPartitionName = PartitionName, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
PartitionEntry->Gpt.PartitionType.Data1,
PartitionEntry->Gpt.PartitionType.Data2,
PartitionEntry->Gpt.PartitionType.Data3,
PartitionEntry->Gpt.PartitionType.Data4[0],
PartitionEntry->Gpt.PartitionType.Data4[1],
PartitionEntry->Gpt.PartitionType.Data4[2],
PartitionEntry->Gpt.PartitionType.Data4[3],
PartitionEntry->Gpt.PartitionType.Data4[4],
PartitionEntry->Gpt.PartitionType.Data4[5],
PartitionEntry->Gpt.PartitionType.Data4[6],
PartitionEntry->Gpt.PartitionType.Data4[7]);
}
DbgPrint("[%s] %I64x \"%S\"",
szPartitionName,
PartitionEntry->Gpt.Attributes,
PartitionEntry->Gpt.Name);
break;
}
if (0 <= NtOpenFile(&hPartition, FILE_GENERIC_READ, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
union {
BYTE bb[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 32*sizeof(WCHAR) ];
FILE_FS_ATTRIBUTE_INFORMATION ffai;
};
switch (NtQueryVolumeInformationFile(hPartition, &iosb, &ffai, sizeof(bb), FileFsAttributeInformation))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
DbgPrint(" \"%.*S\"\n", ffai.FileSystemNameLength >> 1 , ffai.FileSystemName);
break;
}
NtClose(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return ;
}
switch (status)
{
case STATUS_BUFFER_OVERFLOW:
PartitionCount = pdli->PartitionCount;
continue;
case STATUS_INFO_LENGTH_MISMATCH:
case STATUS_BUFFER_TOO_SMALL:
PartitionCount <<= 1;
continue;
default:
return ;
}
}
}
}
从另一个尺寸我们可以得到Device Instance ID通过调用从接口(interface)字符串 CM_Get_Device_Interface_PropertyW
与 DEVPKEY_Device_InstanceId
.之后我们调用CM_Locate_DevNodeW
用于获取设备实例句柄。
CONFIGRET GetPropertyByInterface(PCSTR prefix, PCWSTR pszDeviceInterface)
{
ULONG cb = 0, rcb = 256;
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);
}
status = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%sDeviceID = %S\n", prefix, DeviceID);
DEVINST dnDevInst;
if (CR_SUCCESS == (status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL)))
{
GetPropertyByDeviceID(prefix, dnDevInst);
}
}
else
{
status = CR_WRONG_TYPE;
}
break;
}
} while (status == CR_BUFFER_SMALL);
return status;
}
使用设备实例句柄,我们可以通过CM_Get_DevNode_PropertyW
查询许多设备属性像: DEVPKEY_Device_LocationInfo
, DEVPKEY_NAME
, DEVPKEY_Device_PDOName
, DEVPKEY_Device_FirmwareVersion
, DEVPKEY_Device_Model
, DEVPKEY_Device_DriverVersion
和许多其他 - 查看 devpkey.h
最后我们可以调用CM_Get_Parent
并递归查询父设备的所有这些属性,直到我们不丰富堆栈顶部:
#define OPEN_PDO
void GetPropertyByDeviceID(PCSTR prefix, DEVINST dnDevInst)
{
#ifdef OPEN_PDO
HANDLE hFile;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
#endif
CONFIGRET status;
ULONG cb = 0, rcb = 0x80;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
static struct
{
CONST DEVPROPKEY *PropertyKey;
PCWSTR PropertyName;
} PropertyKeys[] = {
{ &DEVPKEY_Device_PDOName, L"PDOName"},
{ &DEVPKEY_Device_Parent, L"Parent"},
{ &DEVPKEY_Device_DriverVersion, L"DriverVersion"},
{ &DEVPKEY_Device_LocationInfo, L"LocationInfo"},
{ &DEVPKEY_Device_FirmwareVersion, L"FirmwareVersion"},
{ &DEVPKEY_Device_Model, L"Model"},
{ &DEVPKEY_NAME, L"NAME"},
{ &DEVPKEY_Device_InstanceId, L"DeviceID"}
};
do
{
int n = RTL_NUMBER_OF(PropertyKeys);
do
{
CONST DEVPROPKEY *PropertyKey = PropertyKeys[--n].PropertyKey;
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_DevNode_PropertyW(dnDevInst, PropertyKey, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%s%S=[%S]\n", prefix, PropertyKeys[n].PropertyName, sz);
#ifdef OPEN_PDO
if (!n)
{
// DEVPKEY_Device_PDOName can use in NtOpenFile
RtlInitUnicodeString(&ObjectName, sz);
if (0 <= NtOpenFile(&hFile, FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,
&iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
NtClose(hFile);
}
}
#endif
}
}
} while (status == CR_BUFFER_SMALL);
} while (n);
if (!*--prefix) break;
} while (CM_Get_Parent(&dnDevInst, dnDevInst, 0) == CR_SUCCESS);
}
也是由 DEVPKEY_Device_PDOName
返回的字符串我们可以在 NtOpenFile
中使用调用打开PDO设备。
关于windows - 启用存储空间时获取物理磁盘的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52146560/
这个问题已经有答案了: Add a property to a JavaScript object using a variable as the name? (14 个回答) 已关闭 6 年前。 目
每个 Azure 存储帐户的卷限制为 200 TB(200 TB)。这听起来确实很大,但如果您将文件存储在每个 25 MB 的 Blob 存储中,则可以存储大约 400 万个文件,这很好,但并非不可能
我在 Applestore 中发布了我的应用程序以供审核,但遭到拒绝,上面写着: ”在启动和内容下载时,您的应用程序会在用户的 iCloud 上存储 1.4 GB,这不符合 iOS 数据存储指南。"
我对 laravel 的 remember me 功能有点问题。通常,laravel 添加一个 session cookie、一个xsrf token 和具有随机哈希值的第三个 cookie。 (下图
我需要在 SQL 中存储十亿个直方图。这些直方图具有相同的桶,但它们的计数可能有很大的差异,但是,大多数桶在很多时候都是 0。 我最初的尝试是让每个直方图有一行,其中每一列代表一个桶。 我对我的数据类
我正在处理 70GB 的数据集 较早使用 df -BG命令 我被展示了 Filesystem 1G-blocks Used Available Use% Mounted on overlay
有些文件每天都会上传到 FTP 服务器,我需要将这些文件放在 Google Cloud Storage 下。我不想让上传文件的用户安装任何额外的软件,只是让他们继续使用他们的 FTP 客户端。有没有办
如何上传内容类型为 mutlipart/formdata ---boundaryString 的文件使用 signed url谷歌存储? 我面临的问题是,当我们使用浏览器上传文件时,浏览器将内容类型设
版本: 11.2.0.2.0 我想验证我在手册中再次阅读的以下断言: The PLS_INTEGER data type has these advantages over the NUMBER da
我只是在寻找澄清,因为文档指出一个空的、刚刚创建的 SQL 实例应该只占用大约 250Mb。 从文档中引用我可以在存储空间上找到的任何内容: MySQL Second Generation insta
我是一名优秀的程序员,十分优秀!