【PnP】 CodeCollections

概述: PnP 相关代码汇总

1. 弹出U盘

1.1. EjectVolume 弹出U盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
STDAPI_(BOOL) EjectVolume(DWORD dwVolLetter)
{
MYTRACE(L"Enter EjectVolume\n");

DWORD_PTR lrRet = 0;
HWND hWnd = FindWindow(WNDCLASS_CACHEWND, NULL);
LRESULT lr = 0;
if (NULL != hWnd)
{
lr = SendMessageTimeout(hWnd, WM_DEREGISTER_UDISK, dwVolLetter, 0, SMTO_BLOCK, 3000, &lrRet);
}

WCHAR wszVolShort[20] = {};
WCHAR szParentInstanceId[MAX_DEVICE_ID_LEN] = {};
VOLUMECOLLECTION VolCll = {};
BOOL bRet = FALSE;
BOOL bUsed = FALSE;
HANDLE hVolume = INVALID_HANDLE_VALUE;
CONFIGRET conRet = 0;
DEVINST dnDevInst = NULL;

EnableXXXPrivilege(SE_LOAD_DRIVER_NAME);
EnableXXXPrivilege(SE_UNDOCK_NAME);

bRet = GetVolumeCollection((BYTE)dwVolLetter, &VolCll, szParentInstanceId);
if (!bRet)
{
MYTRACE(L"Get volume instance id error!\n");
return FALSE;
}

StringCchPrintf(wszVolShort, ARRAYSIZE(wszVolShort), L"%c:\\", dwVolLetter);
if (!PathFileExists(wszVolShort))
{
MYTRACE(L"Not Find Volume:%c, Delete letter\n", dwVolLetter);
return TRUE;
}

// 不要直接尝试弹出
// 先判断是否占用
DWORD volumeFlags = GENERIC_READ | GENERIC_WRITE;
hVolume = CreateVolumeHandleFromDriveLetter((WCHAR)dwVolLetter,volumeFlags);
if (INVALID_HANDLE_VALUE == hVolume)
{
MYTRACE(L"ERROR! Can not open volume! Maybe it's locked\n");
return FALSE;
}
else
{
CloseHandle(hVolume);
hVolume = INVALID_HANDLE_VALUE;
}

PNP_VETO_TYPE VetoType;
bRet = CMRequestRemoveDev(dwVolLetter, szParentInstanceId, VetoType);

if (!bRet)
{
switch (VetoType)
{
case PNP_VetoTypeUnknown:
MYTRACE(L"[Eject] for unspecified reason");
break;

case PNP_VetoLegacyDevice:
MYTRACE(L"[Eject] due to legacy device");
break;

case PNP_VetoPendingClose:
MYTRACE(L"[Eject] due to pending close");
break;

case PNP_VetoWindowsApp:
MYTRACE(L"[Eject] due to windows application");
break;

case PNP_VetoWindowsService:
MYTRACE(L"[Eject] due to service");
break;

case PNP_VetoOutstandingOpen:
MYTRACE(L"[Eject] due to outstanding handles on device");
break;

case PNP_VetoDevice:
MYTRACE(L"[Eject] by device");
break;

case PNP_VetoDriver:
MYTRACE(L"[Eject] by driver");
break;

case PNP_VetoIllegalDeviceRequest:
{
MYTRACE(L"[Eject] as the request was invalid for the device");

if (EjectVolumeForce(dwVolLetter))
{
CMRequestRemoveDev(dwVolLetter, szParentInstanceId, VetoType);
bRet = TRUE;
}
}
break;

case PNP_VetoInsufficientPower:
MYTRACE(L"[Eject] because there would be insufficient system power to continue");
break;

case PNP_VetoNonDisableable:
MYTRACE(L"[Eject] due to non-disableable device");
break;

case PNP_VetoLegacyDriver:
MYTRACE(L"[Eject] due to legacy driver");
break;

case PNP_VetoInsufficientRights:
MYTRACE(L"[Eject] insufficient permissions");
break;

default:
MYTRACE(L"[Eject] due to uncoded reason");
break;
}
}
return bRet;
}

1.2. GetVolumeCollection 获取设备ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
STDAPI_(BOOL) GetVolumeCollection(BYTE byVolLetter, PVOLUMECOLLECTION pVolCll, LPWSTR pParentInstId)
{
WCHAR szParentInstanceId[MAX_DEVICE_ID_LEN] = {};
WCHAR szTmpInstanceId[MAX_DEVICE_ID_LEN] ={};
WCHAR szDriveLetters[26*2*4] ={};
BOOL bRet;
DWORD cbBytesReturned;
LPWSTR pszDriveRoot = NULL;
size_t uStrlen;

pVolCll->dwCount = 0;

bRet = GetParentInstanceId(byVolLetter, szParentInstanceId, NULL, 0);
if (!bRet)
return FALSE; pszLogicalDrives);

cbBytesReturned = GetLogicalDriveStrings (ARRAYSIZE(szDriveLetters)*sizeof(WCHAR),
szDriveLetters);

for (pszDriveRoot = szDriveLetters; *pszDriveRoot != TEXT('\0');
pszDriveRoot += uStrlen + 1)
{
StringCchLength(pszDriveRoot, 26*2*4, &uStrlen);
if (((BYTE)(*pszDriveRoot) == 'A') || ((BYTE)(*pszDriveRoot) == 'a')
|| ((BYTE)(*pszDriveRoot) == 'B') || ((BYTE)(*pszDriveRoot) == 'b')) //skip floppy and the target volume
continue;

bRet = GetParentInstanceId((BYTE)(*pszDriveRoot), szTmpInstanceId, NULL, 0);
if (bRet && (StrCmpI(szParentInstanceId,szTmpInstanceId) == 0))
{
pVolCll->byVolume[pVolCll->dwCount] = (BYTE)(*pszDriveRoot);
pVolCll->dwCount++;
}

}

if (pParentInstId)
StringCchCopy(pParentInstId, MAX_DEVICE_ID_LEN, szParentInstanceId);

return TRUE;
}

BOOL GetParentInstanceId(BYTE byVolLetter,LPWSTR pParentInstId, LPWSTR pParentDevName,DWORD dwBufSize)
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
WCHAR szDeviceName[8];
STORAGE_PROPERTY_QUERY spq;
STORAGE_DEVICE_NUMBER sdn;
STORAGE_DEVICE_NUMBER sdnTmp;
BOOL bSuccess;
DWORD cbBytesReturned;
BYTE byBuffer[4096];
BOOL bRet = FALSE;
GUID *pGuidInferface = NULL;
// GUID *pGuidClass = NULL;
HDEVINFO hIntDevInfo = INVALID_HANDLE_VALUE;
DWORD dwIndex;
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA deviceInfoData;
CONFIGRET configret;
DEVINST dnDevInstParent;
WCHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN]={};
HANDLE hDev = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;

StringCchPrintf(szDeviceName, ARRAYSIZE(szDeviceName), L"\\\\.\\%c:", byVolLetter);
hDevice = CreateFile (szDeviceName,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
return FALSE;
}

spq.PropertyId = StorageDeviceProperty;
spq.QueryType = PropertyStandardQuery;
spq.AdditionalParameters[0] = 0;
bSuccess = DeviceIoControl (hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&spq, sizeof(spq),
&byBuffer, sizeof(byBuffer),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
STORAGE_DEVICE_DESCRIPTOR *psdp = (STORAGE_DEVICE_DESCRIPTOR *)byBuffer;
if (!bSuccess || psdp->BusType != BusTypeUsb) //Not USB device, just return
{
CloseHandle (hDevice);
return FALSE;
}

bSuccess = DeviceIoControl (hDevice,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
(LPVOID)&sdn, sizeof(sdn),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
// GetLastError of ERROR_MORE_DATA indicates to the caller that the buffer was not large enough to accommodate the data requested
if (!bSuccess)
{
CloseHandle (hDevice);
return FALSE;
}

if (sdn.DeviceType == FILE_DEVICE_CD_ROM || sdn.DeviceType == FILE_DEVICE_DVD)
{
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_CDROM;
// pGuidClass = (GUID*)&GUID_DEVCLASS_CDROM;
}
else //if (sdn.DeviceType == FILE_DEVICE_DISK)
{
pGuidInferface = (GUID*)&GUID_DEVINTERFACE_DISK;
// pGuidClass = (GUID*)&GUID_DEVCLASS_DISKDRIVE;
}

CloseHandle (hDevice);
hDevice = INVALID_HANDLE_VALUE;

hIntDevInfo = SetupDiGetClassDevs (pGuidInferface, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (INVALID_HANDLE_VALUE == hIntDevInfo)
return FALSE;

for (dwIndex = 0; ;dwIndex ++)
{
ZeroMemory(&interfaceData, sizeof(interfaceData));
interfaceData.cbSize = sizeof(interfaceData);
bSuccess = SetupDiEnumDeviceInterfaces (hIntDevInfo, NULL, pGuidInferface, dwIndex, &interfaceData);
if (!bSuccess) {
DWORD dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_NO_MORE_ITEMS)
break;
//else
// break; // ERROR!!!
}

cbBytesReturned = 0;
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData, NULL, 0, &cbBytesReturned, NULL);
if ((!bSuccess && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|| cbBytesReturned == 0)
continue; // ERROR!!!

if (pInterfaceDetailData)
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalFree (pInterfaceDetailData);

pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc (LPTR, cbBytesReturned);
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ZeroMemory (&deviceInfoData, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(deviceInfoData);
bSuccess = SetupDiGetDeviceInterfaceDetail (hIntDevInfo, &interfaceData,
pInterfaceDetailData, cbBytesReturned, &cbBytesReturned, &deviceInfoData);
if (!bSuccess)
continue;

hDev = CreateFile (pInterfaceDetailData->DevicePath,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hDev == INVALID_HANDLE_VALUE)
continue; //ERROR

bSuccess = DeviceIoControl (hDev,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0,
(LPVOID)&sdnTmp, sizeof(sdnTmp),
&cbBytesReturned,
(LPOVERLAPPED) NULL);
CloseHandle(hDev);
if (!bSuccess)
continue;

if ((sdn.DeviceType != sdnTmp.DeviceType) || (sdn.DeviceNumber != sdnTmp.DeviceNumber))
{
continue;
}

//found the device

// MYTRACE(L"pInterfaceDetailData->DevicePath: %s", pInterfaceDetailData->DevicePath);

configret = CM_Get_Parent (&dnDevInstParent, deviceInfoData.DevInst, 0);
if (CR_SUCCESS != configret)
break;
configret = CM_Get_Device_ID (dnDevInstParent, szDeviceInstanceID, ARRAYSIZE(szDeviceInstanceID), 0);
if (CR_SUCCESS != configret)
break;

if (pParentInstId)
StringCchCopy(pParentInstId, MAX_DEVICE_ID_LEN, szDeviceInstanceID);
if (pParentDevName && dwBufSize > 8)
{
LPWSTR pDevName = pInterfaceDetailData->DevicePath;
LPWSTR pfind = StrStrI(pDevName, L"ven_");
if (pfind)
{
pDevName = pfind + 4;
pfind = StrChr(pDevName, '&');
StringCbCopyN(pParentDevName, dwBufSize, pDevName, (pfind-pDevName)*sizeof(WCHAR));
StringCbCat(pParentDevName, dwBufSize, L" ");
pDevName = pInterfaceDetailData->DevicePath;
}
pfind = StrStrI(pDevName, L"prod_");
if (pfind)
{
pDevName = pfind + 5;
pfind = StrChr(pDevName, '&');
StringCbCatN(pParentDevName, dwBufSize, pDevName, (pfind-pDevName)*sizeof(WCHAR));
}
//replace '_' with ' '
pDevName = pParentDevName;
do
{
pfind = StrChr(pDevName, '_');
if (!pfind)
break;
*pfind = ' ';
pDevName = pfind +1;
}while(1);

wcsupr(pParentDevName);
//_wcsupr_s(pParentDevName, wcslen());
}

bRet = TRUE; //Success
break;
}

if (pInterfaceDetailData)
LocalFree( pInterfaceDetailData);
if (hIntDevInfo )
SetupDiDestroyDeviceInfoList(hIntDevInfo);

return bRet;
}

1.3. CMRequestRemoveDev 移除设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
BOOL CMRequestRemoveDev(DWORD dwVolLetter, WCHAR* szParentInstanceId, PNP_VETO_TYPE& VetoType)
{
DEVINST dnDevInst = NULL;
DEVINST parentDevInst = NULL;
VOLUMECOLLECTION VolCll = {};
CONFIGRET conRet = 0;

conRet = CM_Locate_DevNode(&dnDevInst, szParentInstanceId, NULL);

if (conRet == CR_SUCCESS)
{
WCHAR szVetoName[MAX_PATH] = { 0 };

MYTRACE(L"CM_Request_Device_Eject_Ex");
conRet = CM_Request_Device_Eject_Ex(dnDevInst, &VetoType, szVetoName, MAX_PATH, 0, NULL);

MYTRACE(L"CM_Request_Device_Eject_Ex ! rt:%d, VetoType:%d, info:%s", conRet, VetoType, szVetoName);
if (conRet == CR_SUCCESS)
{
MYTRACE(L"CM_Request_Device_Eject_Ex SUCCESS!\n");
return TRUE;
}
else
{
if (conRet == CR_REMOVE_VETOED && VetoType == PNP_VetoIllegalDeviceRequest)
{
conRet = CM_Query_And_Remove_SubTree(dnDevInst,
&VetoType,
szVetoName,
MAX_PATH,

// We have to add the `CM_REMOVE_NO_RESTART` flag because
// otherwise the just-removed device may be immediately
// redetected, which might happen on XP and Vista.
// See https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal

CM_REMOVE_NO_RESTART);
if (conRet == CR_SUCCESS)
{
return TRUE;
}
}

MYTRACE(L"CM_Request_Device_Eject_Ex FAILED! rt:%d, VetoType:%d, info:%s", conRet, VetoType, szVetoName);
}
}

MYTRACE(L"CM_Locate_DevNode eject %d volume(s) error!\n", VolCll.dwCount);

return FALSE;
}

2. 强制弹出U盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
BOOL LockVolume(HANDLE volume) 
{
DWORD bytesReturned;

for (size_t tries = 0; tries < 20; tries++)
{
if (DeviceIoControl(volume,
FSCTL_LOCK_VOLUME,
NULL, 0,
NULL, 0,
&bytesReturned,
NULL)) {
return TRUE;
}

Sleep(500);
}

return FALSE;
}

BOOL UnlockVolume(HANDLE volume)
{
DWORD bytesReturned;

return DeviceIoControl(volume,
FSCTL_UNLOCK_VOLUME,
NULL, 0,
NULL, 0,
&bytesReturned,
NULL);
}

STDAPI_(BOOL) EjectVolumeForce(DWORD dwVolLetter)
{
BOOL bRet = FALSE;
WCHAR wszVolShort[20] = {};
DWORD dwReturn = 0;
HANDLE hVolume = INVALID_HANDLE_VALUE;

StringCchPrintf(wszVolShort, ARRAYSIZE(wszVolShort), L"%c:\\", dwVolLetter);

DWORD volumeFlags = GENERIC_READ | GENERIC_WRITE;
hVolume = CreateVolumeHandleFromDriveLetter(dwVolLetter, volumeFlags);
if (hVolume == INVALID_HANDLE_VALUE)
{
MYTRACE(L"ERROR! Can not open volume!\n");
return FALSE;
}

do
{
if (DRIVE_FIXED == GetDriveType(wszVolShort))
{
MYTRACE(L"DRIVE_FIXED == GetDriveType");

ULONG deviceNumber = GetDeviceNumberFromVolumeHandle(hVolume);
if (!deviceNumber)
{
MYTRACE(L"Couldn't get device number from volume handle");
bRet = FALSE;
break;
}

if (!CloseHandle(hVolume))
{
MYTRACE(L"Couldn't close volume handle");
break;
}

MYTRACE(L"Ejecting fixed drive");
bRet = EjectFixedDriveByDeviceNumber(deviceNumber);

break;
}

if (!LockVolume(hVolume))
{
MYTRACE(L"LockVolume Failed");
break;
}

// 开始暴力弹出
if (DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwReturn, NULL))
{
DWORD dwTmp = 0;
MYTRACE(L"IOCTL_STORAGE_MEDIA_REMOVAL");
bRet = DeviceIoControl(hVolume, IOCTL_STORAGE_MEDIA_REMOVAL, &dwTmp, sizeof(dwTmp), NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_STORAGE_MEDIA_REMOVAL, bRet==%d", bRet);
bRet = DeviceIoControl(hVolume, IOCTL_DISK_EJECT_MEDIA, NULL, 0, NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_DISK_EJECT_MEDIA bRet==%d", bRet);
bRet = DeviceIoControl(hVolume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwReturn, NULL);
MYTRACE(L"IOCTL_STORAGE_EJECT_MEDIA bRet==%d", bRet);

}

if (!UnlockVolume(hVolume))
{
MYTRACE(L"UnlockVolume Failed");
break;
}

// 弹出是否成功
if (!PathFileExists(wszVolShort))
{
DeleteJunctionPoint(dwVolLetter);
bRet = TRUE;
break;
}
else
{
bRet = FALSE;
break;
}
} while (0);

if (INVALID_HANDLE_VALUE != hVolume)
{
CloseHandle(hVolume);
hVolume = INVALID_HANDLE_VALUE;
}

// 避免不生效,多调用几个
// RefreshFolderViews(CSIDL_DESKTOP, SHCNE_UPDATEDIR);
NotifyDeviceRemoval(dwVolLetter);
SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATH, wszVolShort, NULL);
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, wszVolShort, NULL);

return bRet;
}

3. 弹出硬盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Adapted from https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal
// which is licensed under "The Code Project Open License (CPOL) 1.02"
// https://www.codeproject.com/info/cpol10.aspx
DEVINST GetDeviceInstanceFromDeviceNumber(ULONG deviceNumber)
{
const GUID* guid = reinterpret_cast<const GUID*>(&GUID_DEVINTERFACE_DISK);

// Get device interface info set handle for all devices attached to system
DWORD deviceInformationFlags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
HDEVINFO deviceInformation = SetupDiGetClassDevs(guid,
NULL, NULL,
deviceInformationFlags);

if (deviceInformation == INVALID_HANDLE_VALUE)
{
return 0;
}

DWORD memberIndex = 0;
BYTE buffer[1024];

PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)buffer;

SP_DEVINFO_DATA deviceInformationData;
DWORD requiredSize;

SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

while (true)
{
if (!SetupDiEnumDeviceInterfaces(deviceInformation,
NULL,
guid,
memberIndex,
&deviceInterfaceData))
{
break;
}

requiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInformation,
&deviceInterfaceData,
NULL, 0,
&requiredSize, NULL);

if (requiredSize == 0 || requiredSize > sizeof(buffer))
{
memberIndex++;
continue;
}

deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

ZeroMemory((PVOID)&deviceInformationData, sizeof(SP_DEVINFO_DATA));
deviceInformationData.cbSize = sizeof(SP_DEVINFO_DATA);

BOOL result = SetupDiGetDeviceInterfaceDetail(deviceInformation,
&deviceInterfaceData,
deviceInterfaceDetailData,
sizeof(buffer),
&requiredSize,
&deviceInformationData);

if (!result) {
memberIndex++;
continue;
}

LPCTSTR devicePath = deviceInterfaceDetailData->DevicePath;
HANDLE driveHandle = CreateVolumeHandleFromDevicePath(devicePath, 0);

if (driveHandle == INVALID_HANDLE_VALUE) {
memberIndex++;
continue;
}

ULONG currentDriveDeviceNumber =
GetDeviceNumberFromVolumeHandle(driveHandle);

CloseHandle(driveHandle);

if (!currentDriveDeviceNumber) {
memberIndex++;
continue;
}

if (deviceNumber == currentDriveDeviceNumber) {
SetupDiDestroyDeviceInfoList(deviceInformation);
return deviceInformationData.DevInst;
}

memberIndex++;
}

SetupDiDestroyDeviceInfoList(deviceInformation);

return 0;
}

BOOL EjectFixedDriveByDeviceNumber(ULONG deviceNumber)
{
DEVINST deviceInstance = GetDeviceInstanceFromDeviceNumber(deviceNumber);
if (!deviceInstance)
{
MYTRACE(L"Couldn't get instance from device number");
return FALSE;
}

CONFIGRET status;
PNP_VETO_TYPE vetoType = PNP_VetoTypeUnknown;
WCHAR szVetoName[MAX_PATH];

// It's often seen that the removal fails on the first
// attempt but works on the second attempt.
// See https://www.codeproject.com/articles/13839/how-to-prepare-a-usb-drive-for-safe-removal
for (size_t tries = 0; tries < 3; tries++)
{
if (tries != 0) {
MYTRACE(L"Retrying");
Sleep(500);
}
MYTRACE(L"Ejecting device instance");
status = CM_Request_Device_Eject(deviceInstance,
&vetoType,
szVetoName,
MAX_PATH,
0);

if (status == CR_SUCCESS)
{
MYTRACE(L"Ejected device instance successfully");
return TRUE;
}

MYTRACE(L"Ejecting was vetoed");

// We use this as an indicator that the device driver
// is not setting the `SurpriseRemovalOK` capability.
// See https://msdn.microsoft.com/en-us/library/windows/hardware/ff539722(v=vs.85).aspx
if (status == CR_REMOVE_VETOED &&
vetoType == PNP_VetoIllegalDeviceRequest)
{
MYTRACE(L"Removing subtree");
status = CM_Query_And_Remove_SubTree(deviceInstance,
&vetoType,
szVetoName,
MAX_PATH,
CM_REMOVE_NO_RESTART);

if (status == CR_ACCESS_DENIED) {
return FALSE;
}

if (status == CR_SUCCESS) {
return TRUE;
}

MYTRACE(L"Couldn't eject device instance");
return FALSE;
}
}

return FALSE;
}

4. 获取设备数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool GetDeviceNumber(HANDLE deviceHandle, STORAGE_DEVICE_NUMBER& deviceNumber) {
DWORD bytesReturned = 0;
BOOL result = DeviceIoControl(
deviceHandle,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL,
0,
&deviceNumber,
sizeof(STORAGE_DEVICE_NUMBER),
&bytesReturned,
NULL
);

return result != 0;
}

5. 获取设备ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

bool GetDeviceInstanceId(HDEVINFO deviceInfoSet, SP_DEVINFO_DATA& deviceInfoData, std::wstring& deviceInstanceId) {
WCHAR buffer[1024];
DWORD requiredSize = 0;

BOOL result = SetupDiGetDeviceInstanceIdW(
deviceInfoSet,
&deviceInfoData,
buffer,
sizeof(buffer) / sizeof(buffer[0]),
&requiredSize
);

if (result) {
deviceInstanceId = buffer;
}

return result != 0;
}

【PnP】 CodeCollections
https://hodlyounger.github.io/A_OS/Windows/PnP/【PnP】CodeCollect/
作者
mingming
发布于
2024年8月9日
许可协议