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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
util.c
Abstract:
Utility routines used by the TOASTVA sample.
--*/
#include "precomp.h"
#pragma hdrstop
/*++
Here's the description for the CMP_WaitNoPendingInstallEvents API used to
suppress execution of this app (e.g., via autorun upon CD insertion) while
device installation is underway...
DWORD
CMP_WaitNoPendingInstallEvents(
_In_ DWORD dwTimeout
);
Routine Description:
This routine waits until there are no pending device install events.
If a timeout value is specified then it will return either when no
install events are pending or when the timeout period has expired,
whichever comes first. This routine is intended to be called after
user-logon, only.
NOTE: New install events can occur at anytime, this routine just
indicates that there are no install events at this moment.
Parameters:
dwTimeout - Specifies the time-out interval, in milliseconds. The
function returns if the interval elapses, even if there are still
pending install events. If dwTimeout is zero, the function just
tests whether there are pending install events and returns
immediately. If dwTimeout is INFINITE, the function's time-out
interval never elapses.
Return Value:
If the function succeeds, the return value indicates the event that
caused the function to return. If the function fails, the return value
is WAIT_FAILED. To get extended error information, call GetLastError.
The return value on success is one of the following values:
WAIT_ABANDONED The specified object is a mutex object that was not
released by the thread that owned the mutex object
before the owning thread terminated. Ownership of the
mutex object is granted to the calling thread, and the
mutex is set to nonsignaled.
WAIT_OBJECT_0 The state of the specified object is signaled.
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is
nonsignaled.
--*/
typedef DWORD (WINAPI *CMP_WAITNOPENDINGINSTALLEVENTS_PROC)(
_In_ DWORD dwTimeout
);
BOOL
IsDeviceInstallInProgress(VOID)
/*++
Routine Description:
This routine dynamically retrieves the entrypoint to a Windows 2000 (and
later) Configuration Manager (CM) API that can be used to detect whether
there are presently any device installations in-progress. If this API is
not available (it may be obsoleted on future releases of the OS), then the
API assumes there are no device installations in progress. This is OK,
because future versions of the OS will suppress auto-run when "Found New
Hardware" wizard is up, thus eliminating the need for apps to do their own
checking.
Arguments:
none
Return Value:
If there is presently a device installation in progress, the return value
is TRUE.
If there is not presently a device installation in progress, or we were
unsuccessful in retrieving the necessary Configuration Manager API, then
the return value is FALSE.
--*/
{
HMODULE hModule;
CMP_WAITNOPENDINGINSTALLEVENTS_PROC pCMP_WaitNoPendingInstallEvents;
hModule = GetModuleHandle(L"setupapi.dll");
if(!hModule) {
//
// Should never happen since we're linked to setupapi, but...
//
return FALSE;
}
pCMP_WaitNoPendingInstallEvents =
(CMP_WAITNOPENDINGINSTALLEVENTS_PROC)GetProcAddress(
hModule,
"CMP_WaitNoPendingInstallEvents"
);
if(!pCMP_WaitNoPendingInstallEvents) {
//
// We're running on a release of the OS that doesn't supply this API.
// Trust the OS to suppress autorun when appropriate.
//
return FALSE;
}
return (pCMP_WaitNoPendingInstallEvents(0) == WAIT_TIMEOUT);
}
VOID
MarkDevicesAsNeedReinstall(
_In_ HDEVINFO DeviceInfoSet
)
/*++
Routine Description:
This routine enumerates every device information element in the specified
list and sets the CONFIGFLAG_REINSTALL registry flag for each one.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set whose
members are to be marked as need-reinstall.
Return Value:
none
--*/
{
SP_DEVINFO_DATA DeviceInfoData;
DWORD i, ConfigFlags;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(i = 0;
SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DeviceInfoData);
i++)
{
ConfigFlags = GetDeviceConfigFlags(DeviceInfoSet, &DeviceInfoData);
ConfigFlags |= CONFIGFLAG_REINSTALL;
SetDeviceConfigFlags(DeviceInfoSet, &DeviceInfoData, ConfigFlags);
}
}
DWORD
GetDeviceConfigFlags(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVINFO_DATA DeviceInfoData
)
/*++
Routine Description:
This routine retrieves the ConfigFlags registry property for the specified
device info element, or zero if the property cannot be retrieved (e.g.,
because ConfigFlags haven't yet been set by Found New Hardware process).
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
the device of interest.
DeviceInfoData - Supplies context of a device info element for which
ConfigFlags is to be retrieved.
Return Value:
If device's REG_DWORD ConfigFlags property can be retrieved, it is returned.
Otherwise, zero is returned.
--*/
{
DWORD ConfigFlags, RegDataType;
if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
DeviceInfoData,
SPDRP_CONFIGFLAGS,
&RegDataType,
(PBYTE)&ConfigFlags,
sizeof(ConfigFlags),
NULL)
|| (RegDataType != REG_DWORD))
{
//
// It's possible that this property isn't there, although we should
// never enounter other problems like wrong datatype or data length
// longer than sizeof(DWORD). In any event, just return zero.
//
ConfigFlags = 0;
}
return ConfigFlags;
}
VOID
SetDeviceConfigFlags(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVINFO_DATA DeviceInfoData,
_In_ DWORD ConfigFlags
)
/*++
Routine Description:
This routine sets a device's ConfigFlags property to the specified value.
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
the device of interest.
DeviceInfoData - Supplies context of a device info element for which
ConfigFlags is to be set.
ConfigFlags - Specifies the value to be stored to the device's ConfigFlags
property.
Return Value:
none
--*/
{
SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
DeviceInfoData,
SPDRP_CONFIGFLAGS,
(PBYTE)&ConfigFlags,
sizeof(ConfigFlags)
);
}
HDEVINFO
GetNonPresentDevices(
_In_ LPCWSTR Enumerator OPTIONAL,
_In_ LPCWSTR HardwareID
)
/*++
Routine Description:
This routine retrieves any non-present devices matching the specified
criteria, and returns them in a device information set.
Arguments:
Enumerator - Optionally, supplies the name of the Enumerator under which
this device may be found. If the device may show up under more than
one enumerator, the routine can be called with Enumerator specified as
NULL, in which case all device instances in the registry are examined.
HardwareID - Supplies the hardware ID to be searched for. This will be
compared against each of the hardware IDs for all device instances in
the system (potentially filtered based on Enumerator), present or not.
Return Value:
If any non-present devices are discovered, this routine returns a device
information set containing those devices. This set must be freed via
SetupDiDestroyDeviceInfoList by the caller.
If no such devices are encountered (or if an error occurs), the return
value is INVALID_HANDLE_VALUE. GetLastError will indicate the cause of
failure.
--*/
{
HDEVINFO AllDevs, ExistingNonPresentDevices;
DWORD i, Err;
SP_DEVINFO_DATA DeviceInfoData;
LPWSTR HwIdBuffer, CurId;
DWORD HwIdBufferLen, RegDataType, RequiredSize;
BOOL bRet;
ULONG Status, Problem;
TCHAR DeviceInstanceId[MAX_DEVNODE_ID_LEN];
ExistingNonPresentDevices = INVALID_HANDLE_VALUE;
AllDevs = SetupDiGetClassDevs(NULL,
Enumerator,
NULL,
DIGCF_ALLCLASSES
);
if(AllDevs == INVALID_HANDLE_VALUE) {
//
// last error has already been set during the above call.
//
return INVALID_HANDLE_VALUE;
}
//
// Iterate through each device we found, comparing its hardware ID(s)
// against the one we were passed in.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
HwIdBuffer = NULL;
HwIdBufferLen = 0;
Err = NO_ERROR;
bRet = FALSE;
i = 0;
while(SetupDiEnumDeviceInfo(AllDevs, i, &DeviceInfoData)) {
//
// Retrieve the HardwareID property for this device info element
//
if(!SetupDiGetDeviceRegistryProperty(AllDevs,
&DeviceInfoData,
SPDRP_HARDWAREID,
&RegDataType,
(PBYTE)HwIdBuffer,
HwIdBufferLen,
&RequiredSize)) {
//
// If the failure was due to buffer-too-small, we can resize and
// try again.
//
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
if(HwIdBuffer) {
GlobalFree(HwIdBuffer);
}
HwIdBuffer = GlobalAlloc(0, RequiredSize);
if(HwIdBuffer) {
HwIdBufferLen = RequiredSize;
//
// try again
//
continue;
} else {
//
// We failed to allocate the buffer we needed. This is
// considered a critical failure that should cause us to
// bail.
//
Err = ERROR_NOT_ENOUGH_MEMORY;
break;
}
} else {
//
// We failed to retrieve the property for some other reason.
// Skip this device and move on to the next.
//
i++;
continue;
}
}
if((RegDataType != REG_MULTI_SZ) || (RequiredSize < sizeof(TCHAR))) {
//
// Data is invalid--this should never happen, but we'll skip the
// device in this case...
//
i++;
continue;
}
//
// If we get to here, then we successfully retrieved the multi-sz
// hardware id list for this device. Compare each of those IDs with
// the caller-supplied one.
//
for(CurId = HwIdBuffer; CurId && *CurId; CurId += (lstrlen(CurId) + 1)) {
if(!lstrcmpi(CurId, HardwareID)) {
//
// We found a match!
//
bRet = TRUE;
//
// If the device isn't currently present (as indicated by
// failure to retrieve its status), then add it to the list of
// such devices to be returned to the caller.
//
if(CR_SUCCESS != CM_Get_DevNode_Status(&Status,
&Problem,
(DEVNODE)DeviceInfoData.DevInst,
0))
{
if(ExistingNonPresentDevices == INVALID_HANDLE_VALUE) {
//
// This is the first non-present device we've
// encountered--we need to create the HDEVINFO set.
//
ExistingNonPresentDevices =
SetupDiCreateDeviceInfoList(NULL, NULL);
if(ExistingNonPresentDevices == INVALID_HANDLE_VALUE) {
//
// Failure to create this set is a critical error!
//
Err = GetLastError();
bRet = FALSE;
break;
}
}
//
// We need to get the device instance's name so we can
// open it up into our "non-present devices" list
//
if(!SetupDiGetDeviceInstanceId(AllDevs,
&DeviceInfoData,
DeviceInstanceId,
sizeof(DeviceInstanceId) / sizeof(TCHAR),
NULL)) {
//
// Should never fail, but considered critical if it
// does...
//
Err = GetLastError();
bRet = FALSE;
break;
}
//
// Now open up the non-present device into our list.
//
if(!SetupDiOpenDeviceInfo(ExistingNonPresentDevices,
DeviceInstanceId,
NULL,
0,
NULL)) {
//
// This failure is also considered critical!
//
Err = GetLastError();
bRet = FALSE;
}
break;
}
}
}
if(Err != NO_ERROR) {
//
// Critical error encountered--bail!
//
break;
}
//
// Move onto the next device instance
//
i++;
}
if(HwIdBuffer) {
GlobalFree(HwIdBuffer);
}
//
// We can now destroy our temporary list of all devices under consideration
//
SetupDiDestroyDeviceInfoList(AllDevs);
if((Err != NO_ERROR) &&
(ExistingNonPresentDevices != INVALID_HANDLE_VALUE)) {
//
// We encountered a critical error, so we need to destroy the (partial)
// list of non-present devices we'd built.
//
SetupDiDestroyDeviceInfoList(ExistingNonPresentDevices);
ExistingNonPresentDevices = INVALID_HANDLE_VALUE;
}
SetLastError(Err);
return ExistingNonPresentDevices;
}
|