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
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
|
/*++
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:
toastapp.c
Abstract:
TOASTAPP is an application that provides an automatically updated list of
all currently available "toaster" devices (as enumerated by the toaster
sample in the Windows 2000 and Windows XP DDKs).
The toasters' friendly names, along with their pathnames (i.e., for use
with CreateFile) are displayed in the dialog box.
Notes:
For a complete description of device interfaces and PnP event notification,
please see the Microsoft Windows 2000/Windows XP DDK and SDK Documentation.
--*/
#include "precomp.h"
#pragma hdrstop
//
// Instantiate toaster device interface class GUID (from DDK toaster sample,
// src\general\toaster\bus\common.h)
//
// {781EF630-72B2-11d2-B852-00C04FAD5171}
//
#include <initguid.h>
DEFINE_GUID (GUID_TOASTER_INTERFACE, 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);
//
// Declare a global string buffer to be used when retrieving error text via
// FormatMessage.
//
TCHAR ErrorStringBuffer[1024];
//
// Define structure used to store device interface dialogbox data.
//
typedef struct _DIDLG_DATA {
HDEVINFO DeviceInfoSet;
HDEVNOTIFY hDevNotify;
GUID InterfaceClassGuid;
} DIDLG_DATA, *PDIDLG_DATA;
//
// Function prototypes
//
INT_PTR
CALLBACK
DeviceInterfaceDlgProc(
_In_ HWND hwnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
BOOL
FillInDeviceInterfaceListBox(
_In_ HWND hWnd,
_In_ HDEVINFO DeviceInfoSet,
_In_ CONST GUID *InterfaceClassGuid
);
BOOL
GetDeviceInterfaceFriendlyName(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
_Out_writes_all_(FriendlyNameSize) PTSTR FriendlyName,
_In_ DWORD FriendlyNameSize
);
//
// Implementation
//
int
__cdecl
_tmain(
_In_ ULONG argc,
_In_reads_(argc) PCHAR argv[]
)
{
INT_PTR DlgResult;
DIDLG_DATA DIDlgData;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
//
// Initialize our dialogbox data structure.
//
ZeroMemory(&DIDlgData, sizeof(DIDlgData));
CopyMemory(&(DIDlgData.InterfaceClassGuid),
&GUID_TOASTER_INTERFACE,
sizeof(GUID)
);
//
// Now fire off the dialog that will present the automatically-updated list
// of active device interfaces.
//
DlgResult = DialogBoxParam(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DEVICE_INTERFACES),
NULL,
DeviceInterfaceDlgProc,
(LPARAM)&DIDlgData
);
if(!DlgResult) {
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
0,
ErrorStringBuffer,
sizeof(ErrorStringBuffer) / sizeof(TCHAR),
NULL)) {
_tprintf(TEXT("%s"), ErrorStringBuffer);
}
return -1;
} else {
return 0;
}
}
INT_PTR
CALLBACK
DeviceInterfaceDlgProc(
_In_ HWND hWnd,
_In_ UINT msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
/*++
Routine Description:
This is the dialog procedure for the device interface dialog box that
presents an automatically-updated list of active device interfaces.
It expects to get an lParam during WM_INITDIALOG that is a pointer to a
DIDLGDATA structure where the InterfaceClassGuid field is initialized to
the interface class GUID for which the device interface list is to be
displayed. (The other fields in this structure are initialized, used, and
destroyed during the lifetime of the dialogbox.)
--*/
{
PDIDLG_DATA DIDlgData;
DWORD Err;
PDEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
if(msg == WM_INITDIALOG) {
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
HDEVINFO NewDeviceInfoSet;
DIDlgData = (PDIDLG_DATA)lParam;
//
// Create a device information set that will be the container for our
// device interfaces.
//
DIDlgData->DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
if(DIDlgData->DeviceInfoSet == INVALID_HANDLE_VALUE) {
Err = GetLastError();
_tprintf(TEXT("SetupDiCreateDeviceInfoList failed with %lx\n"), Err);
goto clean0;
}
//
// Now register to begin receiving notifications for the comings
// and goings of device interfaces which are members of the
// interface class whose GUID was passed in as the lParam to this
// dialog procedure.
//
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
CopyMemory(&(NotificationFilter.dbcc_classguid), &(DIDlgData->InterfaceClassGuid), sizeof(GUID));
DIDlgData->hDevNotify = RegisterDeviceNotification(hWnd,
&NotificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE
);
if(!DIDlgData->hDevNotify) {
Err = GetLastError();
_tprintf(TEXT("RegisterDeviceNotification failed with %lx\n"), Err);
goto clean1;
}
//
// OK, now we can retrieve the existing list of active device
// interfaces into the device information set we created above.
//
NewDeviceInfoSet = SetupDiGetClassDevsEx(&(DIDlgData->InterfaceClassGuid),
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,
DIDlgData->DeviceInfoSet,
NULL,
NULL
);
if(NewDeviceInfoSet == INVALID_HANDLE_VALUE) {
Err = GetLastError();
_tprintf(TEXT("SetupDiGetClassDevsEx failed with %lx\n"), Err);
goto clean2;
}
//
// If SetupDiGetClassDevsEx succeeds and it was passed in an
// existing device information set to be used, then the HDEVINFO
// it returns is the same as the one it was passed in. Thus, we
// can just use the original DeviceInfoSet handle from here on.
//
//
// Now fill in our listbox with the current device interface list.
//
if(!FillInDeviceInterfaceListBox(hWnd,
DIDlgData->DeviceInfoSet,
&(DIDlgData->InterfaceClassGuid))) {
Err = GetLastError();
goto clean2;
}
//
// Success! Store away a pointer to our device interface dialog data
// structure.
//
SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)DIDlgData);
return TRUE;
//
// Clean-up code for error path...
//
clean2:
UnregisterDeviceNotification(DIDlgData->hDevNotify);
clean1:
SetupDiDestroyDeviceInfoList(DIDlgData->DeviceInfoSet);
clean0:
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
HRESULT_FROM_SETUPAPI(Err),
0,
ErrorStringBuffer,
sizeof(ErrorStringBuffer) / sizeof(TCHAR),
NULL)) {
_tprintf(TEXT("%s"), ErrorStringBuffer);
}
EndDialog(hWnd, 0);
SetLastError(Err);
return TRUE;
} else {
//
// For the small set of messages that we get before WM_INITDIALOG, we
// won't have a devwizdata pointer!
//
DIDlgData = (PDIDLG_DATA)GetWindowLongPtr(hWnd, DWLP_USER);
if(DIDlgData == NULL) {
//
// If we haven't gotten a WM_INITDIALOG message yet, or if for some
// reason we weren't able to retrieve the DIDlgData pointer when we
// did, then we simply return FALSE.
//
return FALSE;
}
}
switch(msg) {
case WM_COMMAND:
if(LOWORD(wParam) == IDOK) {
//
// Clean up and return.
//
UnregisterDeviceNotification(DIDlgData->hDevNotify);
SetupDiDestroyDeviceInfoList(DIDlgData->DeviceInfoSet);
SetWindowLongPtr(hWnd, DWLP_USER, 0);
EndDialog(hWnd, 1);
return TRUE;
}
//
// All other WM_COMMAND messages unhandled.
//
break;
case WM_DEVICECHANGE:
//
// All the events we're interested in come with lParam pointing to
// a structure headed by a DEV_BROADCAST_HDR. This is denoted by
// bit 15 of wParam being set, and bit 14 being clear.
//
if((wParam & 0xC000) == 0x8000) {
//
// Make sure that this is a device interface notification...
//
if(((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DevBroadcastDeviceInterface = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
} else {
//
// This isn't a device interface notification. Instead,
// it's a broadcasted notification sent for backwards-
// compatibility (e.g., DBT_DEVTYP_VOLUME).
//
break;
}
if(wParam == DBT_DEVICEARRIVAL) {
_tprintf(TEXT("Received DBT_DEVICEARRIVAL for %s\n"), DevBroadcastDeviceInterface->dbcc_name);
} else if(wParam == DBT_DEVICEREMOVEPENDING) {
_tprintf(TEXT("Received DBT_DEVICEREMOVEPENDING for %s\n"), DevBroadcastDeviceInterface->dbcc_name);
} else if(wParam == DBT_DEVICEREMOVECOMPLETE) {
_tprintf(TEXT("Received DBT_DEVICEREMOVECOMPLETE for %s\n"), DevBroadcastDeviceInterface->dbcc_name);
} else {
//
// Presently, there are no other events that are sent for
// device interface notification, thus we should never get
// here.
//
break;
}
} else {
//
// We received some broadcasted system message we don't care
// about (e.g., DBT_QUERYCHANGECONFIG).
//
break;
}
if(wParam == DBT_DEVICEARRIVAL) {
//
// Open this new device interface into our device information
// set.
//
if(!SetupDiOpenDeviceInterface(DIDlgData->DeviceInfoSet,
DevBroadcastDeviceInterface->dbcc_name,
0,
NULL)) {
Err = GetLastError();
_tprintf(TEXT("SetupDiOpenDeviceInterface failed with %lx\n"), Err);
return TRUE;
}
} else {
//
// First, locate this device interface in our device information
// set.
//
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(SetupDiOpenDeviceInterface(DIDlgData->DeviceInfoSet,
DevBroadcastDeviceInterface->dbcc_name,
DIODI_NO_ADD,
&DeviceInterfaceData)) {
if(!SetupDiDeleteDeviceInterfaceData(DIDlgData->DeviceInfoSet,
&DeviceInterfaceData)) {
Err = GetLastError();
_tprintf(TEXT("SetupDiDeleteDeviceInterfaceData failed with %lx\n"), Err);
return TRUE;
}
}
}
//
// If we get to here, we've successfully added or deleted a
// device interface in our device information set. Now go update
// our listbox with the new list. (Ignore any errors.)
//
FillInDeviceInterfaceListBox(hWnd,
DIDlgData->DeviceInfoSet,
&(DIDlgData->InterfaceClassGuid)
);
return TRUE;
default:
break;
}
return FALSE;
}
BOOL
FillInDeviceInterfaceListBox(
_In_ HWND hWnd,
_In_ HDEVINFO DeviceInfoSet,
_In_ CONST GUID *InterfaceClassGuid
)
/*++
Routine Description:
This routine fills in the listbox of currently-active device interfaces
with their corresponding friendly names and pathnames.
Arguments:
hWnd - Supplies the window handle of the dialog box containing the device
interface listbox to be updated.
DeviceInfoSet - Supplies a handle to the device information set containing
device interfaces to be used in updating the listbox.
InterfaceClassGuid - Supplies the address of the interface class GUID for
the device interfaces to be placed into the listbox.
Return Value:
If the function succeeds, the return value is non-zero.
If the function fails, the return value is FALSE. To find out what the
cause of failure was, call GetLastError().
--*/
{
DWORD i, Err;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PTSTR FriendlyName;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
PBYTE Buffer;
DWORD BufferSize = 0;
DWORD RequiredSize;
LRESULT ListBoxReturn;
size_t FriendlyNameLen;
size_t devicePathLen;
//
// Reset the listbox in preparation for adding the current list of device
// interfaces.
//
SendDlgItemMessage(hWnd,
IDC_DEVICE_INTERFACE_LIST,
LB_RESETCONTENT,
0,
0
);
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
Err = NO_ERROR;
//
// Start out with a buffer that should be large enough to hold the friendly
// name plus the device interface detail data for a "reasonably-sized"
// device interface pathname. Note that device interface paths aren't
// confined to MAX_PATH length on Windows 2000, so we deal with the case
// where we may need a larger buffer.
//
// Note that we add a space and an open paren between the friendly name and
// the pathname. We have space for this (even in Unicode), because the
// device interface detail data buffer always begins with a DWORD cbSize
// field, that we can overwrite, without touching the character DevicePath
// buffer.
//
BufferSize = (LINE_LEN * sizeof(TCHAR)) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
+ (MAX_PATH * sizeof(TCHAR));
Buffer = malloc(BufferSize);
if(Buffer) {
//
// Leave the first LINE_LEN characters to retrieve the friendly name
// into...
//
FriendlyName = (PTSTR)Buffer;
DeviceInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(Buffer + (LINE_LEN * sizeof(TCHAR)));
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
} else {
//
// Failure!
//
_tprintf(TEXT("Couldn't allocate %d bytes for device interface detail buffer\n"),
BufferSize
);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
for(i = 0;
SetupDiEnumDeviceInterfaces(DeviceInfoSet,
NULL,
InterfaceClassGuid,
i,
&DeviceInterfaceData);
i++) {
//
// To retrieve the device interface name (e.g., that you can call
// CreateFile() on...
//
while(!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
&DeviceInterfaceData,
DeviceInterfaceDetailData,
BufferSize - (LINE_LEN * sizeof(TCHAR)),
&RequiredSize,
NULL)) {
//
// We failed to get the device interface detail data--was it because
// our buffer was too small? (Hopefully so!)
//
Err = GetLastError();
//
// We can get rid of our current buffer regardless of what the
// error was...
//
free(Buffer);
Buffer = NULL;
if(Err != ERROR_INSUFFICIENT_BUFFER) {
//
// Failure!
//
_tprintf(TEXT("SetupDiGetDeviceInterfaceDetail failed with %lx\n"), Err);
break;
}
//
// We failed due to insufficient buffer. Allocate one that's
// sufficiently large and try again.
//
BufferSize = RequiredSize + (LINE_LEN * sizeof(TCHAR));
Buffer = malloc(BufferSize);
if(Buffer) {
//
// Leave the first LINE_LEN characters to retrieve the friendly
// name into...
//
FriendlyName = (PTSTR)Buffer;
DeviceInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(Buffer + (LINE_LEN * sizeof(TCHAR)));
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Err = NO_ERROR;
} else {
//
// Failure!
//
Err = ERROR_NOT_ENOUGH_MEMORY;
_tprintf(TEXT("Couldn't allocate %d bytes for device interface detail buffer\n"), RequiredSize);
break;
}
}
if(!Buffer) {
//
// We encountered a failure above--abort.
//
break;
}
//
// Now that we've successfully retrieved the device interface pathname,
// we can retrieve the friendly name. We left enough space at the
// start of the buffer for this, so we'll now retrieve this string,
// then move the pathname down next to it for display (the pathname
// will be enclosed in parentheses).
//
if(!GetDeviceInterfaceFriendlyName(DeviceInfoSet,
&DeviceInterfaceData,
FriendlyName,
LINE_LEN)) {
//
// This generally won't happen, but it _is_ possible. We'll just
// use two double-quotes to indicate an empty string.
//
if(FAILED(StringCchCopy(FriendlyName, LINE_LEN, TEXT("\"\"")))) {
break;
}
}
//
// Add a space and the opening paren (see previous comment on why we're
// safe in doing this without fear of overwriting the DevicePath string.
//
if(FAILED(StringCchCat(FriendlyName, LINE_LEN, TEXT(" (")))) {
break;
}
if(FAILED(StringCchLength(FriendlyName, LINE_LEN, &FriendlyNameLen))) {
break;
}
//
// Now move the pathname down to the character immediately following
// the open paren. (Note: since source and destination blocks may
// overlap, we must use MoveMemory.)
//
if(FAILED(StringCbLength(DeviceInterfaceDetailData->DevicePath,
MAX_PATH,
&devicePathLen))) {
break;
}
devicePathLen += sizeof(TCHAR);
MoveMemory((PBYTE)(FriendlyName + FriendlyNameLen),
DeviceInterfaceDetailData->DevicePath,
devicePathLen
);
//
// Now add close paren
//
if (FAILED(StringCchCat(FriendlyName, LINE_LEN, TEXT(")")))) {
break;
}
//
// Add this device interface to our listbox.
//
ListBoxReturn = SendDlgItemMessage(hWnd,
IDC_DEVICE_INTERFACE_LIST,
LB_ADDSTRING,
0,
(LPARAM)FriendlyName
);
if((ListBoxReturn == LB_ERR) || (ListBoxReturn == LB_ERRSPACE)) {
//
// Set Err to some generic failure
//
Err = ERROR_INVALID_DATA;
_tprintf(TEXT("Failed to add %s to listbox (%s)\n"),
DeviceInterfaceDetailData->DevicePath,
(ListBoxReturn == LB_ERR) ? TEXT("LB_ERR") : TEXT("LB_ERRSPACE")
);
break;
}
//
// Since we may have overwritten the device interface detail data
// 'cbSize' field, restore it now.
//
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
}
if(Buffer) {
free(Buffer);
}
SetLastError(Err);
return (Err == NO_ERROR);
}
BOOL
GetDeviceInterfaceFriendlyName(
_In_ HDEVINFO DeviceInfoSet,
_In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
_Out_writes_all_(FriendlyNameSize) PTSTR FriendlyName,
_In_ DWORD FriendlyNameSize
)
/*++
Routine Description:
This routine retrieves the friendly name associated with the specified
device interface. It first looks for a "FriendlyName" value entry in the
device interface's registry key. If not found, it then tries to use the
"FriendlyName" property for the underlying devnode. If that isn't present,
it uses the devnode's device description (and if there isnt one of those,
it returns FALSE).
Arguments:
DeviceInfoSet - Supplies a handle to the device information set containing
the device interface whose friendly name is to be retrieved.
DeviceInterfaceData - Supplies a context structure indicating which device
interface we're retrieving a friendly name for.
FriendlyName - Supplies a character buffer that is filled in, upon
successful return, with the friendly name for the device interface.
FriendlyNameSize - Supplies the size, in characters, of the FriendlyName
buffer.
Return Value:
If the function succeeds, the return value is non-zero.
If no FriendlyName is found (or buffer is too small), the return value is
FALSE.
--*/
{
HKEY hkey;
DWORD Err;
SP_DEVINFO_DATA DeviceInfoData;
DWORD RegDataType, RegDataLength;
//
// First, open up the device interface registry key to see if the interface
// has its own friendly name.
//
hkey = SetupDiOpenDeviceInterfaceRegKey(DeviceInfoSet,
DeviceInterfaceData,
0,
KEY_READ
);
if(hkey != INVALID_HANDLE_VALUE) {
RegDataLength = FriendlyNameSize * sizeof(TCHAR);
Err = RegQueryValueEx(hkey,
TEXT("FriendlyName"),
NULL,
&RegDataType,
(PBYTE)FriendlyName,
&RegDataLength
);
RegCloseKey(hkey);
if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ)) {
return TRUE;
}
}
//
// Find out what device instance is exposing this interface.
//
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if(!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
DeviceInterfaceData,
NULL,
0,
NULL,
&DeviceInfoData)) {
//
// We should always get here (i.e., SetupDiGetDeviceInterfaceDetail
// should always fail) since we didn't pass in a buffer to retrieve
// the device interface detail data. Of course, all we really care
// about is getting at the underlying device info data.
//
//
// Now check the underlying device for a FriendlyName property.
//
if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&RegDataType,
(PBYTE)FriendlyName,
FriendlyNameSize * sizeof(TCHAR),
NULL)) {
if(RegDataType == REG_SZ) {
return TRUE;
}
}
//
// Fall back to device description
//
if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
&DeviceInfoData,
SPDRP_DEVICEDESC,
&RegDataType,
(PBYTE)FriendlyName,
FriendlyNameSize * sizeof(TCHAR),
NULL)) {
if(RegDataType == REG_SZ) {
return TRUE;
}
}
}
//
// Couldn't find anything usable as a friendly name--return failure.
//
return FALSE;
}
|