Fix error handling in SETUP_CreateInterfaceList (memory/handles leak)
[reactos.git] / reactos / dll / win32 / setupapi / devinst.c
1 /*
2 * SetupAPI device installer
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "setupapi_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
25
26 /* Unicode constants */
27 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
28 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
29 static const WCHAR Class[] = {'C','l','a','s','s',0};
30 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
31 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
32 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
33 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
34 static const WCHAR DotHW[] = {'.','H','W',0};
35 static const WCHAR DotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
36 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
37 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
38 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
39 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
40 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
41
42 static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
43 static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
44 static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
45 static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
46 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[] = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
47
48 static const WCHAR INF_MANUFACTURER[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
49 static const WCHAR INF_PROVIDER[] = {'P','r','o','v','i','d','e','r',0};
50 static const WCHAR INF_DRIVER_VER[] = {'D','r','i','v','e','r','V','e','r',0};
51
52 typedef DWORD
53 (CALLBACK* CLASS_INSTALL_PROC) (
54 IN DI_FUNCTION InstallFunction,
55 IN HDEVINFO DeviceInfoSet,
56 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
57 typedef BOOL
58 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
59 IN HDEVINFO DeviceInfoSet,
60 IN OUT PSP_DEVINFO_DATA DeviceInfoData);
61 typedef DWORD
62 (CALLBACK* COINSTALLER_PROC) (
63 IN DI_FUNCTION InstallFunction,
64 IN HDEVINFO DeviceInfoSet,
65 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
66 IN OUT PCOINSTALLER_CONTEXT_DATA Context);
67 typedef BOOL
68 (WINAPI* PROPERTY_PAGE_PROVIDER) (
69 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest,
70 IN LPFNADDPROPSHEETPAGE fAddFunc,
71 IN LPARAM lParam);
72 typedef BOOL
73 (*UPDATE_CLASS_PARAM_HANDLER) (
74 IN HDEVINFO DeviceInfoSet,
75 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
76 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
77 IN DWORD ClassInstallParamsSize);
78
79 struct CoInstallerElement
80 {
81 LIST_ENTRY ListEntry;
82
83 HMODULE Module;
84 COINSTALLER_PROC Function;
85 BOOL DoPostProcessing;
86 PVOID PrivateData;
87 };
88
89 static BOOL
90 PropertyChangeHandler(
91 IN HDEVINFO DeviceInfoSet,
92 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
93 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
94 IN DWORD ClassInstallParamsSize);
95
96 static UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers[] = {
97 NULL, /* DIF_SELECTDEVICE */
98 NULL, /* DIF_INSTALLDEVICE */
99 NULL, /* DIF_ASSIGNRESOURCES */
100 NULL, /* DIF_PROPERTIES */
101 NULL, /* DIF_REMOVE */
102 NULL, /* DIF_FIRSTTIMESETUP */
103 NULL, /* DIF_FOUNDDEVICE */
104 NULL, /* DIF_SELECTCLASSDRIVERS */
105 NULL, /* DIF_VALIDATECLASSDRIVERS */
106 NULL, /* DIF_INSTALLCLASSDRIVERS */
107 NULL, /* DIF_CALCDISKSPACE */
108 NULL, /* DIF_DESTROYPRIVATEDATA */
109 NULL, /* DIF_VALIDATEDRIVER */
110 NULL, /* DIF_MOVEDEVICE */
111 NULL, /* DIF_DETECT */
112 NULL, /* DIF_INSTALLWIZARD */
113 NULL, /* DIF_DESTROYWIZARDDATA */
114 PropertyChangeHandler, /* DIF_PROPERTYCHANGE */
115 NULL, /* DIF_ENABLECLASS */
116 NULL, /* DIF_DETECTVERIFY */
117 NULL, /* DIF_INSTALLDEVICEFILES */
118 NULL, /* DIF_UNREMOVE */
119 NULL, /* DIF_SELECTBESTCOMPATDRV */
120 NULL, /* DIF_ALLOW_INSTALL */
121 NULL, /* DIF_REGISTERDEVICE */
122 NULL, /* DIF_NEWDEVICEWIZARD_PRESELECT */
123 NULL, /* DIF_NEWDEVICEWIZARD_SELECT */
124 NULL, /* DIF_NEWDEVICEWIZARD_PREANALYZE */
125 NULL, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */
126 NULL, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */
127 NULL, /* DIF_UNUSED1 */
128 NULL, /* DIF_INSTALLINTERFACES */
129 NULL, /* DIF_DETECTCANCEL */
130 NULL, /* DIF_REGISTER_COINSTALLERS */
131 NULL, /* DIF_ADDPROPERTYPAGE_ADVANCED */
132 NULL, /* DIF_ADDPROPERTYPAGE_BASIC */
133 NULL, /* DIF_RESERVED1 */
134 NULL, /* DIF_TROUBLESHOOTER */
135 NULL, /* DIF_POWERMESSAGEWAKE */
136 NULL, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */
137 NULL, /* DIF_UPDATEDRIVER_UI */
138 NULL /* DIF_RESERVED2 */
139 };
140
141 /***********************************************************************
142 * SetupDiBuildClassInfoList (SETUPAPI.@)
143 */
144 BOOL WINAPI SetupDiBuildClassInfoList(
145 DWORD Flags,
146 LPGUID ClassGuidList,
147 DWORD ClassGuidListSize,
148 PDWORD RequiredSize)
149 {
150 TRACE("\n");
151 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
152 ClassGuidListSize, RequiredSize,
153 NULL, NULL);
154 }
155
156 /***********************************************************************
157 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
158 */
159 BOOL WINAPI SetupDiBuildClassInfoListExA(
160 DWORD Flags,
161 LPGUID ClassGuidList,
162 DWORD ClassGuidListSize,
163 PDWORD RequiredSize,
164 LPCSTR MachineName,
165 PVOID Reserved)
166 {
167 LPWSTR MachineNameW = NULL;
168 BOOL bResult;
169
170 TRACE("\n");
171
172 if (MachineName)
173 {
174 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
175 if (MachineNameW == NULL) return FALSE;
176 }
177
178 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
179 ClassGuidListSize, RequiredSize,
180 MachineNameW, Reserved);
181
182 if (MachineNameW)
183 MyFree(MachineNameW);
184
185 return bResult;
186 }
187
188 /***********************************************************************
189 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
190 */
191 BOOL WINAPI SetupDiBuildClassInfoListExW(
192 DWORD Flags,
193 LPGUID ClassGuidList,
194 DWORD ClassGuidListSize,
195 PDWORD RequiredSize,
196 LPCWSTR MachineName,
197 PVOID Reserved)
198 {
199 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
200 HKEY hClassesKey;
201 HKEY hClassKey;
202 DWORD dwLength;
203 DWORD dwIndex;
204 LONG lError;
205 DWORD dwGuidListIndex = 0;
206
207 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
208 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
209
210 if (RequiredSize != NULL)
211 *RequiredSize = 0;
212
213 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
214 KEY_ENUMERATE_SUB_KEYS,
215 DIOCR_INSTALLER,
216 MachineName,
217 Reserved);
218 if (hClassesKey == INVALID_HANDLE_VALUE)
219 {
220 return FALSE;
221 }
222
223 for (dwIndex = 0; ; dwIndex++)
224 {
225 dwLength = MAX_GUID_STRING_LEN + 1;
226 lError = RegEnumKeyExW(hClassesKey,
227 dwIndex,
228 szKeyName,
229 &dwLength,
230 NULL,
231 NULL,
232 NULL,
233 NULL);
234 TRACE("RegEnumKeyExW() returns %ld\n", lError);
235 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
236 {
237 TRACE("Key name: %s\n", debugstr_w(szKeyName));
238
239 if (RegOpenKeyExW(hClassesKey,
240 szKeyName,
241 0,
242 KEY_QUERY_VALUE,
243 &hClassKey))
244 {
245 RegCloseKey(hClassesKey);
246 return FALSE;
247 }
248
249 if (!RegQueryValueExW(hClassKey,
250 REGSTR_VAL_NOUSECLASS,
251 NULL,
252 NULL,
253 NULL,
254 NULL))
255 {
256 TRACE("'NoUseClass' value found!\n");
257 RegCloseKey(hClassKey);
258 continue;
259 }
260
261 if ((Flags & DIBCI_NOINSTALLCLASS) &&
262 (!RegQueryValueExW(hClassKey,
263 REGSTR_VAL_NOINSTALLCLASS,
264 NULL,
265 NULL,
266 NULL,
267 NULL)))
268 {
269 TRACE("'NoInstallClass' value found!\n");
270 RegCloseKey(hClassKey);
271 continue;
272 }
273
274 if ((Flags & DIBCI_NODISPLAYCLASS) &&
275 (!RegQueryValueExW(hClassKey,
276 REGSTR_VAL_NODISPLAYCLASS,
277 NULL,
278 NULL,
279 NULL,
280 NULL)))
281 {
282 TRACE("'NoDisplayClass' value found!\n");
283 RegCloseKey(hClassKey);
284 continue;
285 }
286
287 RegCloseKey(hClassKey);
288
289 TRACE("Guid: %s\n", debugstr_w(szKeyName));
290 if (dwGuidListIndex < ClassGuidListSize)
291 {
292 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
293 {
294 szKeyName[37] = 0;
295 }
296 TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
297
298 UuidFromStringW(&szKeyName[1],
299 &ClassGuidList[dwGuidListIndex]);
300 }
301
302 dwGuidListIndex++;
303 }
304
305 if (lError != ERROR_SUCCESS)
306 break;
307 }
308
309 RegCloseKey(hClassesKey);
310
311 if (RequiredSize != NULL)
312 *RequiredSize = dwGuidListIndex;
313
314 if (ClassGuidListSize < dwGuidListIndex)
315 {
316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
317 return FALSE;
318 }
319
320 return TRUE;
321 }
322
323 /***********************************************************************
324 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
325 */
326 BOOL WINAPI SetupDiClassGuidsFromNameA(
327 LPCSTR ClassName,
328 LPGUID ClassGuidList,
329 DWORD ClassGuidListSize,
330 PDWORD RequiredSize)
331 {
332 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
333 ClassGuidListSize, RequiredSize,
334 NULL, NULL);
335 }
336
337 /***********************************************************************
338 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
339 */
340 BOOL WINAPI SetupDiClassGuidsFromNameW(
341 LPCWSTR ClassName,
342 LPGUID ClassGuidList,
343 DWORD ClassGuidListSize,
344 PDWORD RequiredSize)
345 {
346 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
347 ClassGuidListSize, RequiredSize,
348 NULL, NULL);
349 }
350
351 /***********************************************************************
352 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
353 */
354 BOOL WINAPI SetupDiClassGuidsFromNameExA(
355 LPCSTR ClassName,
356 LPGUID ClassGuidList,
357 DWORD ClassGuidListSize,
358 PDWORD RequiredSize,
359 LPCSTR MachineName,
360 PVOID Reserved)
361 {
362 LPWSTR ClassNameW = NULL;
363 LPWSTR MachineNameW = NULL;
364 BOOL bResult;
365
366 TRACE("\n");
367
368 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
369 if (ClassNameW == NULL)
370 return FALSE;
371
372 if (MachineNameW)
373 {
374 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
375 if (MachineNameW == NULL)
376 {
377 MyFree(ClassNameW);
378 return FALSE;
379 }
380 }
381
382 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
383 ClassGuidListSize, RequiredSize,
384 MachineNameW, Reserved);
385
386 if (MachineNameW)
387 MyFree(MachineNameW);
388
389 MyFree(ClassNameW);
390
391 return bResult;
392 }
393
394 /***********************************************************************
395 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
396 */
397 BOOL WINAPI SetupDiClassGuidsFromNameExW(
398 LPCWSTR ClassName,
399 LPGUID ClassGuidList,
400 DWORD ClassGuidListSize,
401 PDWORD RequiredSize,
402 LPCWSTR MachineName,
403 PVOID Reserved)
404 {
405 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
406 WCHAR szClassName[256];
407 HKEY hClassesKey;
408 HKEY hClassKey;
409 DWORD dwLength;
410 DWORD dwIndex;
411 LONG lError;
412 DWORD dwGuidListIndex = 0;
413
414 TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
415 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
416
417 if (RequiredSize != NULL)
418 *RequiredSize = 0;
419
420 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
421 KEY_ENUMERATE_SUB_KEYS,
422 DIOCR_INSTALLER,
423 MachineName,
424 Reserved);
425 if (hClassesKey == INVALID_HANDLE_VALUE)
426 {
427 return FALSE;
428 }
429
430 for (dwIndex = 0; ; dwIndex++)
431 {
432 dwLength = MAX_GUID_STRING_LEN + 1;
433 lError = RegEnumKeyExW(hClassesKey,
434 dwIndex,
435 szKeyName,
436 &dwLength,
437 NULL,
438 NULL,
439 NULL,
440 NULL);
441 TRACE("RegEnumKeyExW() returns %ld\n", lError);
442 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
443 {
444 TRACE("Key name: %s\n", debugstr_w(szKeyName));
445
446 if (RegOpenKeyExW(hClassesKey,
447 szKeyName,
448 0,
449 KEY_QUERY_VALUE,
450 &hClassKey))
451 {
452 RegCloseKey(hClassesKey);
453 return FALSE;
454 }
455
456 dwLength = 256 * sizeof(WCHAR);
457 if (!RegQueryValueExW(hClassKey,
458 Class,
459 NULL,
460 NULL,
461 (LPBYTE)szClassName,
462 &dwLength))
463 {
464 TRACE("Class name: %s\n", debugstr_w(szClassName));
465
466 if (strcmpiW(szClassName, ClassName) == 0)
467 {
468 TRACE("Found matching class name\n");
469
470 TRACE("Guid: %s\n", debugstr_w(szKeyName));
471 if (dwGuidListIndex < ClassGuidListSize)
472 {
473 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
474 {
475 szKeyName[37] = 0;
476 }
477 TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
478
479 UuidFromStringW(&szKeyName[1],
480 &ClassGuidList[dwGuidListIndex]);
481 }
482
483 dwGuidListIndex++;
484 }
485 }
486
487 RegCloseKey(hClassKey);
488 }
489
490 if (lError != ERROR_SUCCESS)
491 break;
492 }
493
494 RegCloseKey(hClassesKey);
495
496 if (RequiredSize != NULL)
497 *RequiredSize = dwGuidListIndex;
498
499 if (ClassGuidListSize < dwGuidListIndex)
500 {
501 SetLastError(ERROR_INSUFFICIENT_BUFFER);
502 return FALSE;
503 }
504
505 return TRUE;
506 }
507
508 /***********************************************************************
509 * SetupDiClassNameFromGuidA (SETUPAPI.@)
510 */
511 BOOL WINAPI SetupDiClassNameFromGuidA(
512 const GUID* ClassGuid,
513 PSTR ClassName,
514 DWORD ClassNameSize,
515 PDWORD RequiredSize)
516 {
517 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
518 ClassNameSize, RequiredSize,
519 NULL, NULL);
520 }
521
522 /***********************************************************************
523 * SetupDiClassNameFromGuidW (SETUPAPI.@)
524 */
525 BOOL WINAPI SetupDiClassNameFromGuidW(
526 const GUID* ClassGuid,
527 PWSTR ClassName,
528 DWORD ClassNameSize,
529 PDWORD RequiredSize)
530 {
531 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
532 ClassNameSize, RequiredSize,
533 NULL, NULL);
534 }
535
536 /***********************************************************************
537 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
538 */
539 BOOL WINAPI SetupDiClassNameFromGuidExA(
540 const GUID* ClassGuid,
541 PSTR ClassName,
542 DWORD ClassNameSize,
543 PDWORD RequiredSize,
544 PCSTR MachineName,
545 PVOID Reserved)
546 {
547 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
548 LPWSTR MachineNameW = NULL;
549 BOOL ret;
550
551 if (MachineName)
552 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
553 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
554 NULL, MachineNameW, Reserved);
555 if (ret)
556 {
557 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
558 ClassNameSize, NULL, NULL);
559
560 if (!ClassNameSize && RequiredSize)
561 *RequiredSize = len;
562 }
563 MyFree(MachineNameW);
564 return ret;
565 }
566
567 /***********************************************************************
568 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
569 */
570 BOOL WINAPI SetupDiClassNameFromGuidExW(
571 const GUID* ClassGuid,
572 PWSTR ClassName,
573 DWORD ClassNameSize,
574 PDWORD RequiredSize,
575 PCWSTR MachineName,
576 PVOID Reserved)
577 {
578 HKEY hKey;
579 DWORD dwLength;
580 LONG rc;
581
582 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
583 ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
584
585 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
586 KEY_QUERY_VALUE,
587 DIOCR_INSTALLER,
588 MachineName,
589 Reserved);
590 if (hKey == INVALID_HANDLE_VALUE)
591 {
592 return FALSE;
593 }
594
595 if (RequiredSize != NULL)
596 {
597 dwLength = 0;
598 rc = RegQueryValueExW(hKey,
599 Class,
600 NULL,
601 NULL,
602 NULL,
603 &dwLength);
604 if (rc != ERROR_SUCCESS)
605 {
606 SetLastError(rc);
607 RegCloseKey(hKey);
608 return FALSE;
609 }
610
611 *RequiredSize = dwLength / sizeof(WCHAR);
612 }
613
614 dwLength = ClassNameSize * sizeof(WCHAR);
615 rc = RegQueryValueExW(hKey,
616 Class,
617 NULL,
618 NULL,
619 (LPBYTE)ClassName,
620 &dwLength);
621 if (rc != ERROR_SUCCESS)
622 {
623 SetLastError(rc);
624 RegCloseKey(hKey);
625 return FALSE;
626 }
627
628 RegCloseKey(hKey);
629
630 return TRUE;
631 }
632
633 /***********************************************************************
634 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
635 */
636 HDEVINFO WINAPI
637 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
638 HWND hwndParent)
639 {
640 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
641 }
642
643 /***********************************************************************
644 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
645 */
646 HDEVINFO WINAPI
647 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
648 HWND hwndParent,
649 PCSTR MachineName,
650 PVOID Reserved)
651 {
652 LPWSTR MachineNameW = NULL;
653 HDEVINFO hDevInfo;
654
655 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
656 debugstr_a(MachineName), Reserved);
657
658 if (MachineName)
659 {
660 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
661 if (MachineNameW == NULL)
662 return (HDEVINFO)INVALID_HANDLE_VALUE;
663 }
664
665 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
666 MachineNameW, Reserved);
667
668 if (MachineNameW)
669 MyFree(MachineNameW);
670
671 return hDevInfo;
672 }
673
674 static DWORD
675 GetErrorCodeFromCrCode(const IN CONFIGRET cr)
676 {
677 switch (cr)
678 {
679 case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
680 case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER;
681 case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
682 case CR_FAILURE: return ERROR_GEN_FAILURE;
683 case CR_INVALID_DATA: return ERROR_INVALID_USER_BUFFER;
684 case CR_INVALID_DEVICE_ID: return ERROR_INVALID_PARAMETER;
685 case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
686 case CR_INVALID_DEVNODE: return ERROR_INVALID_PARAMETER;
687 case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS;
688 case CR_INVALID_POINTER: return ERROR_INVALID_PARAMETER;
689 case CR_INVALID_PROPERTY: return ERROR_INVALID_PARAMETER;
690 case CR_NO_SUCH_DEVNODE: return ERROR_FILE_NOT_FOUND;
691 case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
692 case CR_NO_SUCH_VALUE: return ERROR_FILE_NOT_FOUND;
693 case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
694 case CR_REGISTRY_ERROR: return ERROR_GEN_FAILURE;
695 case CR_SUCCESS: return ERROR_SUCCESS;
696 default: return ERROR_GEN_FAILURE;
697 }
698
699 /* Does not happen */
700 }
701
702 /***********************************************************************
703 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
704 */
705 HDEVINFO WINAPI
706 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
707 HWND hwndParent,
708 PCWSTR MachineName,
709 PVOID Reserved)
710 {
711 struct DeviceInfoSet *list;
712 LPWSTR UNCServerName = NULL;
713 DWORD size;
714 DWORD rc;
715 //CONFIGRET cr;
716 HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;;
717
718 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
719 debugstr_w(MachineName), Reserved);
720
721 size = FIELD_OFFSET(struct DeviceInfoSet, szData);
722 if (MachineName)
723 size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
724 list = HeapAlloc(GetProcessHeap(), 0, size);
725 if (!list)
726 {
727 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
728 goto cleanup;
729 }
730 memset(list, 0, sizeof(struct DeviceInfoSet));
731
732 list->magic = SETUP_DEV_INFO_SET_MAGIC;
733 memcpy(
734 &list->ClassGuid,
735 ClassGuid ? ClassGuid : &GUID_NULL,
736 sizeof(list->ClassGuid));
737 list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
738 list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
739 list->InstallParams.hwndParent = hwndParent;
740 if (MachineName)
741 {
742 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
743 if (rc != ERROR_SUCCESS)
744 {
745 SetLastError(rc);
746 goto cleanup;
747 }
748 UNCServerName = HeapAlloc(GetProcessHeap(), 0, (strlenW(MachineName) + 3) * sizeof(WCHAR));
749 if (!UNCServerName)
750 {
751 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
752 goto cleanup;
753 }
754
755 strcpyW(UNCServerName + 2, MachineName);
756 list->szData[0] = list->szData[1] = '\\';
757 strcpyW(list->szData + 2, MachineName);
758 list->MachineName = list->szData;
759 }
760 else
761 {
762 DWORD Size = MAX_PATH;
763 list->HKLM = HKEY_LOCAL_MACHINE;
764 UNCServerName = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 2) * sizeof(WCHAR));
765 if (!UNCServerName)
766 {
767 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
768 goto cleanup;
769 }
770 if (!GetComputerNameW(UNCServerName + 2, &Size))
771 goto cleanup;
772 list->MachineName = NULL;
773 }
774 #if 0
775 UNCServerName[0] = UNCServerName[1] = '\\';
776 cr = CM_Connect_MachineW(UNCServerName, &list->hMachine);
777 if (cr != CR_SUCCESS)
778 {
779 SetLastError(GetErrorCodeFromCrCode(cr));
780 goto cleanup;
781 }
782 #endif
783 InitializeListHead(&list->DriverListHead);
784 InitializeListHead(&list->ListHead);
785
786 ret = (HDEVINFO)list;
787
788 cleanup:
789 if (ret == INVALID_HANDLE_VALUE)
790 {
791 if (list && list->HKLM != 0 && list->HKLM != HKEY_LOCAL_MACHINE)
792 RegCloseKey(list->HKLM);
793 HeapFree(GetProcessHeap(), 0, list);
794 }
795 HeapFree(GetProcessHeap(), 0, UNCServerName);
796 return ret;
797 }
798
799 /***********************************************************************
800 * SetupDiEnumDeviceInfo (SETUPAPI.@)
801 */
802 BOOL WINAPI SetupDiEnumDeviceInfo(
803 HDEVINFO DeviceInfoSet,
804 DWORD MemberIndex,
805 PSP_DEVINFO_DATA DeviceInfoData)
806 {
807 BOOL ret = FALSE;
808
809 TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
810 if (!DeviceInfoData)
811 SetLastError(ERROR_INVALID_PARAMETER);
812 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
813 {
814 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
815
816 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
817 SetLastError(ERROR_INVALID_HANDLE);
818 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
819 SetLastError(ERROR_INVALID_USER_BUFFER);
820 else
821 {
822 PLIST_ENTRY ItemList = list->ListHead.Flink;
823 while (ItemList != &list->ListHead && MemberIndex-- > 0)
824 ItemList = ItemList->Flink;
825 if (ItemList == &list->ListHead)
826 SetLastError(ERROR_NO_MORE_ITEMS);
827 else
828 {
829 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
830 memcpy(&DeviceInfoData->ClassGuid,
831 &DevInfo->ClassGuid,
832 sizeof(GUID));
833 DeviceInfoData->DevInst = DevInfo->dnDevInst;
834 DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
835 ret = TRUE;
836 }
837 }
838 }
839 else
840 SetLastError(ERROR_INVALID_HANDLE);
841 return ret;
842 }
843
844 /***********************************************************************
845 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
846 */
847 BOOL WINAPI
848 SetupDiGetActualSectionToInstallA(
849 IN HINF InfHandle,
850 IN PCSTR InfSectionName,
851 OUT PSTR InfSectionWithExt OPTIONAL,
852 IN DWORD InfSectionWithExtSize,
853 OUT PDWORD RequiredSize OPTIONAL,
854 OUT PSTR *Extension OPTIONAL)
855 {
856 return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
857 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
858 Extension, NULL);
859 }
860
861 /***********************************************************************
862 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
863 */
864 BOOL WINAPI
865 SetupDiGetActualSectionToInstallW(
866 IN HINF InfHandle,
867 IN PCWSTR InfSectionName,
868 OUT PWSTR InfSectionWithExt OPTIONAL,
869 IN DWORD InfSectionWithExtSize,
870 OUT PDWORD RequiredSize OPTIONAL,
871 OUT PWSTR *Extension OPTIONAL)
872 {
873 return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
874 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
875 Extension, NULL);
876 }
877
878 /***********************************************************************
879 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
880 */
881 BOOL WINAPI
882 SetupDiGetActualSectionToInstallExA(
883 IN HINF InfHandle,
884 IN PCSTR InfSectionName,
885 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
886 OUT PSTR InfSectionWithExt OPTIONAL,
887 IN DWORD InfSectionWithExtSize,
888 OUT PDWORD RequiredSize OPTIONAL,
889 OUT PSTR* Extension OPTIONAL,
890 IN PVOID Reserved)
891 {
892 LPWSTR InfSectionNameW = NULL;
893 LPWSTR InfSectionWithExtW = NULL;
894 PWSTR ExtensionW;
895 BOOL bResult = FALSE;
896
897 TRACE("\n");
898
899 if (InfSectionName)
900 {
901 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
902 if (InfSectionNameW == NULL)
903 goto cleanup;
904 }
905 if (InfSectionWithExt)
906 {
907 InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
908 if (InfSectionWithExtW == NULL)
909 goto cleanup;
910 }
911
912 bResult = SetupDiGetActualSectionToInstallExW(
913 InfHandle, InfSectionNameW, AlternatePlatformInfo,
914 InfSectionWithExt ? InfSectionWithExtW : NULL,
915 InfSectionWithExtSize,
916 RequiredSize,
917 Extension ? &ExtensionW : NULL,
918 Reserved);
919
920 if (bResult && InfSectionWithExt)
921 {
922 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
923 InfSectionWithExtSize, NULL, NULL) != 0;
924 }
925 if (bResult && Extension)
926 {
927 if (ExtensionW == NULL)
928 *Extension = NULL;
929 else
930 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
931 }
932
933 cleanup:
934 MyFree(InfSectionNameW);
935 MyFree(InfSectionWithExtW);
936
937 return bResult;
938 }
939
940 /***********************************************************************
941 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
942 */
943 BOOL WINAPI
944 SetupDiGetActualSectionToInstallExW(
945 IN HINF InfHandle,
946 IN PCWSTR InfSectionName,
947 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
948 OUT PWSTR InfSectionWithExt OPTIONAL,
949 IN DWORD InfSectionWithExtSize,
950 OUT PDWORD RequiredSize OPTIONAL,
951 OUT PWSTR* Extension OPTIONAL,
952 IN PVOID Reserved)
953 {
954 BOOL ret = FALSE;
955
956 TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
957 AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
958 RequiredSize, Extension, Reserved);
959
960 if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
961 SetLastError(ERROR_INVALID_HANDLE);
962 else if (!InfSectionName)
963 SetLastError(ERROR_INVALID_PARAMETER);
964 else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
965 SetLastError(ERROR_INVALID_USER_BUFFER);
966 else if (Reserved != NULL)
967 SetLastError(ERROR_INVALID_PARAMETER);
968 else
969 {
970 static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
971 PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
972 LPCWSTR pExtensionPlatform, pExtensionArchitecture;
973 WCHAR SectionName[LINE_LEN + 1];
974 LONG lLineCount = -1;
975 DWORD dwFullLength;
976
977 /* Fill platform info if needed */
978 if (AlternatePlatformInfo)
979 pPlatformInfo = AlternatePlatformInfo;
980 else if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
981 {
982 /* That's the first time we go here. We need to fill in the structure */
983 OSVERSIONINFO VersionInfo;
984 SYSTEM_INFO SystemInfo;
985 VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
986 ret = GetVersionEx(&VersionInfo);
987 if (!ret)
988 goto done;
989 GetSystemInfo(&SystemInfo);
990 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
991 CurrentPlatform.Platform = VersionInfo.dwPlatformId;
992 CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
993 CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
994 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
995 CurrentPlatform.Reserved = 0;
996 }
997
998 static const WCHAR ExtensionPlatformNone[] = {'.',0};
999 static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
1000 static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
1001
1002 static const WCHAR ExtensionArchitectureNone[] = {0};
1003 static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
1004 static const WCHAR ExtensionArchitectureamd64[] = {'a','m','d','6','4',0};
1005 static const WCHAR ExtensionArchitectureia64[] = {'i','a','6','4',0};
1006 static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
1007 static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
1008 static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
1009
1010 /* Set various extensions values */
1011 switch (pPlatformInfo->Platform)
1012 {
1013 case VER_PLATFORM_WIN32_WINDOWS:
1014 pExtensionPlatform = ExtensionPlatformWindows;
1015 break;
1016 case VER_PLATFORM_WIN32_NT:
1017 pExtensionPlatform = ExtensionPlatformNT;
1018 break;
1019 default:
1020 ERR("Unkown platform 0x%lx\n", pPlatformInfo->Platform);
1021 pExtensionPlatform = ExtensionPlatformNone;
1022 break;
1023 }
1024 switch (pPlatformInfo->ProcessorArchitecture)
1025 {
1026 case PROCESSOR_ARCHITECTURE_ALPHA:
1027 pExtensionArchitecture = ExtensionArchitecturealpha;
1028 break;
1029 case PROCESSOR_ARCHITECTURE_AMD64:
1030 pExtensionArchitecture = ExtensionArchitectureamd64;
1031 break;
1032 case PROCESSOR_ARCHITECTURE_IA64:
1033 pExtensionArchitecture = ExtensionArchitectureia64;
1034 break;
1035 case PROCESSOR_ARCHITECTURE_INTEL:
1036 pExtensionArchitecture = ExtensionArchitecturex86;
1037 break;
1038 case PROCESSOR_ARCHITECTURE_MIPS:
1039 pExtensionArchitecture = ExtensionArchitecturemips;
1040 break;
1041 case PROCESSOR_ARCHITECTURE_PPC:
1042 pExtensionArchitecture = ExtensionArchitectureppc;
1043 break;
1044 default:
1045 ERR("Unknown processor architecture 0x%x\n", pPlatformInfo->ProcessorArchitecture);
1046 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1047 pExtensionArchitecture = ExtensionArchitectureNone;
1048 break;
1049 }
1050
1051 static const WCHAR FormatPlatformArchitectureMajorMinor[] = {'%','s','%','s','%','s','.','%','l','u','.','%','l','u',0};
1052 static const WCHAR FormatPlatformMajorMinor[] = {'%','s','%','s','.','%','l','u','.','%','l','u',0};
1053 static const WCHAR FormatPlatformArchitectureMajor[] = {'%','s','%','s','%','s','.','%','l','u',0};
1054 static const WCHAR FormatPlatformMajor[] = {'%','s','%','s','.','%','l','u',0};
1055 static const WCHAR FormatPlatformArchitecture[] = {'%','s','%','s','%','s',0};
1056 static const WCHAR FormatPlatform[] = {'%','s','%','s',0};
1057 static const WCHAR FormatNone[] = {'%','s',0};
1058
1059 SectionName[LINE_LEN] = UNICODE_NULL;
1060
1061 /* Test with platform.architecture.major.minor extension */
1062 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitectureMajorMinor, InfSectionName,
1063 pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
1064 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1065 if (lLineCount != -1) goto sectionfound;
1066
1067 /* Test with platform.major.minor extension */
1068 snprintfW(SectionName, LINE_LEN, FormatPlatformMajorMinor, InfSectionName,
1069 pExtensionPlatform, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
1070 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1071 if (lLineCount != -1) goto sectionfound;
1072
1073 /* Test with platform.architecture.major extension */
1074 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitectureMajor, InfSectionName,
1075 pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion);
1076 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1077 if (lLineCount != -1) goto sectionfound;
1078
1079 /* Test with platform.major extension */
1080 snprintfW(SectionName, LINE_LEN, FormatPlatformMajor, InfSectionName,
1081 pExtensionPlatform, pPlatformInfo->MajorVersion);
1082 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1083 if (lLineCount != -1) goto sectionfound;
1084
1085 /* Test with platform.architecture extension */
1086 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitecture, InfSectionName,
1087 pExtensionPlatform, pExtensionArchitecture);
1088 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1089 if (lLineCount != -1) goto sectionfound;
1090
1091 /* Test with platform extension */
1092 snprintfW(SectionName, LINE_LEN, FormatPlatform, InfSectionName,
1093 pExtensionPlatform);
1094 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1095 if (lLineCount != -1) goto sectionfound;
1096
1097 /* Test without extension */
1098 snprintfW(SectionName, LINE_LEN, FormatNone, InfSectionName);
1099 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1100 if (lLineCount != -1) goto sectionfound;
1101
1102 /* No appropriate section found */
1103 SetLastError(ERROR_INVALID_PARAMETER);
1104 goto done;
1105
1106 sectionfound:
1107 dwFullLength = lstrlenW(SectionName);
1108 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1109 {
1110 if (InfSectionWithExtSize < (dwFullLength + 1))
1111 {
1112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1113 goto done;
1114 }
1115
1116 lstrcpyW(InfSectionWithExt, SectionName);
1117 if (Extension != NULL)
1118 {
1119 DWORD dwLength = lstrlenW(SectionName);
1120 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1121 }
1122 }
1123
1124 if (RequiredSize != NULL)
1125 *RequiredSize = dwFullLength + 1;
1126
1127 ret = TRUE;
1128 }
1129
1130 done:
1131 TRACE("Returning %d\n", ret);
1132 return ret;
1133 }
1134
1135
1136 /***********************************************************************
1137 * SetupDiGetClassDescriptionA (SETUPAPI.@)
1138 */
1139 BOOL WINAPI SetupDiGetClassDescriptionA(
1140 const GUID* ClassGuid,
1141 PSTR ClassDescription,
1142 DWORD ClassDescriptionSize,
1143 PDWORD RequiredSize)
1144 {
1145 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1146 ClassDescriptionSize,
1147 RequiredSize, NULL, NULL);
1148 }
1149
1150 /***********************************************************************
1151 * SetupDiGetClassDescriptionW (SETUPAPI.@)
1152 */
1153 BOOL WINAPI SetupDiGetClassDescriptionW(
1154 const GUID* ClassGuid,
1155 PWSTR ClassDescription,
1156 DWORD ClassDescriptionSize,
1157 PDWORD RequiredSize)
1158 {
1159 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1160 ClassDescriptionSize,
1161 RequiredSize, NULL, NULL);
1162 }
1163
1164 /***********************************************************************
1165 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
1166 */
1167 BOOL WINAPI SetupDiGetClassDescriptionExA(
1168 const GUID* ClassGuid,
1169 PSTR ClassDescription,
1170 DWORD ClassDescriptionSize,
1171 PDWORD RequiredSize,
1172 PCSTR MachineName,
1173 PVOID Reserved)
1174 {
1175 PWCHAR ClassDescriptionW;
1176 LPWSTR MachineNameW = NULL;
1177 BOOL ret;
1178
1179 TRACE("\n");
1180 if (ClassDescriptionSize > 0)
1181 {
1182 ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
1183 if (!ClassDescriptionW)
1184 {
1185 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1186 ret = FALSE;
1187 goto end;
1188 }
1189 }
1190 else
1191 ClassDescriptionW = NULL;
1192
1193 if (MachineName)
1194 {
1195 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1196 if (!MachineNameW)
1197 {
1198 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1199 ret = FALSE;
1200 goto end;
1201 }
1202 }
1203
1204 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
1205 NULL, MachineNameW, Reserved);
1206 if (ret)
1207 {
1208 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
1209 ClassDescriptionSize, NULL, NULL);
1210
1211 if (!ClassDescriptionSize && RequiredSize)
1212 *RequiredSize = len;
1213 }
1214
1215 end:
1216 HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
1217 MyFree(MachineNameW);
1218 return ret;
1219 }
1220
1221 /***********************************************************************
1222 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1223 */
1224 BOOL WINAPI SetupDiGetClassDescriptionExW(
1225 const GUID* ClassGuid,
1226 PWSTR ClassDescription,
1227 DWORD ClassDescriptionSize,
1228 PDWORD RequiredSize,
1229 PCWSTR MachineName,
1230 PVOID Reserved)
1231 {
1232 HKEY hKey;
1233 DWORD dwLength;
1234
1235 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
1236 ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
1237
1238 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1239 KEY_QUERY_VALUE,
1240 DIOCR_INSTALLER,
1241 MachineName,
1242 Reserved);
1243 if (hKey == INVALID_HANDLE_VALUE)
1244 {
1245 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
1246 return FALSE;
1247 }
1248
1249 if (RequiredSize != NULL)
1250 {
1251 dwLength = 0;
1252 if (RegQueryValueExW(hKey,
1253 NULL,
1254 NULL,
1255 NULL,
1256 NULL,
1257 &dwLength))
1258 {
1259 RegCloseKey(hKey);
1260 return FALSE;
1261 }
1262
1263 *RequiredSize = dwLength / sizeof(WCHAR);
1264 }
1265
1266 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1267 if (RegQueryValueExW(hKey,
1268 NULL,
1269 NULL,
1270 NULL,
1271 (LPBYTE)ClassDescription,
1272 &dwLength))
1273 {
1274 RegCloseKey(hKey);
1275 return FALSE;
1276 }
1277
1278 RegCloseKey(hKey);
1279
1280 return TRUE;
1281 }
1282
1283 /***********************************************************************
1284 * SetupDiGetClassDevsA (SETUPAPI.@)
1285 */
1286 HDEVINFO WINAPI SetupDiGetClassDevsA(
1287 CONST GUID *class,
1288 LPCSTR enumstr,
1289 HWND parent,
1290 DWORD flags)
1291 {
1292 return SetupDiGetClassDevsExA(class, enumstr, parent,
1293 flags, NULL, NULL, NULL);
1294 }
1295
1296 /***********************************************************************
1297 * SetupDiGetClassDevsW (SETUPAPI.@)
1298 */
1299 HDEVINFO WINAPI SetupDiGetClassDevsW(
1300 CONST GUID *class,
1301 LPCWSTR enumstr,
1302 HWND parent,
1303 DWORD flags)
1304 {
1305 return SetupDiGetClassDevsExW(class, enumstr, parent,
1306 flags, NULL, NULL, NULL);
1307 }
1308
1309 /***********************************************************************
1310 * SetupDiGetClassDevsExA (SETUPAPI.@)
1311 */
1312 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1313 CONST GUID *class,
1314 LPCSTR enumstr,
1315 HWND parent,
1316 DWORD flags,
1317 HDEVINFO deviceset,
1318 LPCSTR machine,
1319 PVOID reserved)
1320 {
1321 HDEVINFO ret;
1322 LPWSTR enumstrW = NULL;
1323 LPWSTR machineW = NULL;
1324
1325 if (enumstr)
1326 {
1327 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1328 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1329 if (!enumstrW)
1330 {
1331 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1332 goto end;
1333 }
1334 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1335 }
1336 if (machine)
1337 {
1338 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1339 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1340 if (!machineW)
1341 {
1342 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1343 goto end;
1344 }
1345 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1346 }
1347 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
1348
1349 end:
1350 HeapFree(GetProcessHeap(), 0, enumstrW);
1351 HeapFree(GetProcessHeap(), 0, machineW);
1352 return ret;
1353 }
1354
1355 static BOOL
1356 CreateDeviceInfoElement(
1357 IN struct DeviceInfoSet *list,
1358 IN LPCWSTR InstancePath,
1359 IN LPCGUID pClassGuid,
1360 OUT struct DeviceInfoElement **pDeviceInfo)
1361 {
1362 DWORD size;
1363 CONFIGRET cr;
1364 struct DeviceInfoElement *deviceInfo;
1365
1366 *pDeviceInfo = NULL;
1367
1368 size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
1369 deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
1370 if (!deviceInfo)
1371 {
1372 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1373 return FALSE;
1374 }
1375 memset(deviceInfo, 0, size);
1376
1377 cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
1378 if (cr != CR_SUCCESS)
1379 {
1380 SetLastError(GetErrorCodeFromCrCode(cr));
1381 return FALSE;
1382 }
1383
1384 deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1385 strcpyW(deviceInfo->Data, InstancePath);
1386 deviceInfo->DeviceName = deviceInfo->Data;
1387 deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
1388 deviceInfo->DeviceDescription = NULL;
1389 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
1390 deviceInfo->CreationFlags = 0;
1391 InitializeListHead(&deviceInfo->DriverListHead);
1392 InitializeListHead(&deviceInfo->InterfaceListHead);
1393
1394 *pDeviceInfo = deviceInfo;
1395 return TRUE;
1396 }
1397
1398 static BOOL
1399 CreateDeviceInterface(
1400 IN struct DeviceInfoElement* deviceInfo,
1401 IN LPCWSTR SymbolicLink,
1402 IN LPCGUID pInterfaceGuid,
1403 OUT struct DeviceInterface **pDeviceInterface)
1404 {
1405 struct DeviceInterface *deviceInterface;
1406
1407 *pDeviceInterface = NULL;
1408
1409 deviceInterface = HeapAlloc(GetProcessHeap(), 0,
1410 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR));
1411 if (!deviceInterface)
1412 {
1413 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1414 return FALSE;
1415 }
1416 deviceInterface->DeviceInfo = deviceInfo;
1417 strcpyW(deviceInterface->SymbolicLink, SymbolicLink);
1418 deviceInterface->Flags = 0; /* Flags will be updated later */
1419 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
1420
1421 *pDeviceInterface = deviceInterface;
1422 return TRUE;
1423 }
1424
1425 static LONG SETUP_CreateDevListFromEnumerator(
1426 struct DeviceInfoSet *list,
1427 LPCGUID pClassGuid OPTIONAL,
1428 LPCWSTR Enumerator,
1429 HKEY hEnumeratorKey) /* handle to Enumerator registry key */
1430 {
1431 HKEY hDeviceIdKey, hInstanceIdKey;
1432 WCHAR KeyBuffer[MAX_PATH];
1433 WCHAR InstancePath[MAX_PATH];
1434 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
1435 struct DeviceInfoElement *deviceInfo;
1436 DWORD i = 0, j;
1437 DWORD dwLength, dwRegType;
1438 DWORD rc;
1439
1440 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
1441 while (TRUE)
1442 {
1443 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1444 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1445 if (rc == ERROR_NO_MORE_ITEMS)
1446 break;
1447 if (rc != ERROR_SUCCESS)
1448 return rc;
1449 i++;
1450
1451 /* Open device id sub key */
1452 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
1453 if (rc != ERROR_SUCCESS)
1454 return rc;
1455 strcpyW(InstancePath, Enumerator);
1456 strcatW(InstancePath, L"\\");
1457 strcatW(InstancePath, KeyBuffer);
1458 strcatW(InstancePath, L"\\");
1459 pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
1460
1461 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
1462 j = 0;
1463 while (TRUE)
1464 {
1465 GUID KeyGuid;
1466
1467 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1468 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1469 if (rc == ERROR_NO_MORE_ITEMS)
1470 break;
1471 if (rc != ERROR_SUCCESS)
1472 {
1473 RegCloseKey(hDeviceIdKey);
1474 return rc;
1475 }
1476 j++;
1477
1478 /* Open instance id sub key */
1479 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1480 if (rc != ERROR_SUCCESS)
1481 {
1482 RegCloseKey(hDeviceIdKey);
1483 return rc;
1484 }
1485 *pEndOfInstancePath = '\0';
1486 strcatW(InstancePath, KeyBuffer);
1487
1488 /* Read ClassGUID value */
1489 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1490 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1491 RegCloseKey(hInstanceIdKey);
1492 if (rc == ERROR_FILE_NOT_FOUND)
1493 {
1494 if (pClassGuid)
1495 /* Skip this bad entry as we can't verify it */
1496 continue;
1497 /* Set a default GUID for this device */
1498 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
1499 }
1500 else if (rc != ERROR_SUCCESS)
1501 {
1502 RegCloseKey(hDeviceIdKey);
1503 return rc;
1504 }
1505 else if (dwRegType != REG_SZ)
1506 {
1507 RegCloseKey(hDeviceIdKey);
1508 return ERROR_GEN_FAILURE;
1509 }
1510 else
1511 {
1512 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1513 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1514 /* Bad GUID, skip the entry */
1515 continue;
1516 }
1517
1518 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
1519 {
1520 /* Skip this entry as it is not the right device class */
1521 continue;
1522 }
1523
1524 /* Add the entry to the list */
1525 if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
1526 {
1527 RegCloseKey(hDeviceIdKey);
1528 return GetLastError();
1529 }
1530 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
1531 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1532 }
1533 RegCloseKey(hDeviceIdKey);
1534 }
1535
1536 return ERROR_SUCCESS;
1537 }
1538
1539 static LONG SETUP_CreateDevList(
1540 struct DeviceInfoSet *list,
1541 PCWSTR MachineName OPTIONAL,
1542 LPGUID class OPTIONAL,
1543 PCWSTR Enumerator OPTIONAL)
1544 {
1545 HKEY HKLM, hEnumKey, hEnumeratorKey;
1546 WCHAR KeyBuffer[MAX_PATH];
1547 DWORD i;
1548 DWORD dwLength;
1549 DWORD rc;
1550
1551 if (class && IsEqualIID(class, &GUID_NULL))
1552 class = NULL;
1553
1554 /* Open Enum key */
1555 if (MachineName != NULL)
1556 {
1557 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1558 if (rc != ERROR_SUCCESS)
1559 return rc;
1560 }
1561 else
1562 HKLM = HKEY_LOCAL_MACHINE;
1563
1564 rc = RegOpenKeyExW(HKLM,
1565 REGSTR_PATH_SYSTEMENUM,
1566 0,
1567 KEY_ENUMERATE_SUB_KEYS,
1568 &hEnumKey);
1569 if (MachineName != NULL) RegCloseKey(HKLM);
1570 if (rc != ERROR_SUCCESS)
1571 return rc;
1572
1573 /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
1574 * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
1575 * for each one.
1576 */
1577 if (Enumerator)
1578 {
1579 rc = RegOpenKeyExW(
1580 hEnumKey,
1581 Enumerator,
1582 0,
1583 KEY_ENUMERATE_SUB_KEYS,
1584 &hEnumeratorKey);
1585 RegCloseKey(hEnumKey);
1586 if (rc != ERROR_SUCCESS)
1587 return rc;
1588 rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
1589 RegCloseKey(hEnumeratorKey);
1590 return rc;
1591 }
1592 else
1593 {
1594 /* Enumerate enumerators */
1595 i = 0;
1596 while (TRUE)
1597 {
1598 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1599 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1600 if (rc == ERROR_NO_MORE_ITEMS)
1601 break;
1602 if (rc != ERROR_SUCCESS)
1603 {
1604 RegCloseKey(hEnumKey);
1605 return rc;
1606 }
1607 i++;
1608
1609 /* Open sub key */
1610 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1611 if (rc != ERROR_SUCCESS)
1612 {
1613 RegCloseKey(hEnumKey);
1614 return rc;
1615 }
1616
1617 /* Call SETUP_CreateDevListFromEnumerator */
1618 rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
1619 RegCloseKey(hEnumeratorKey);
1620 if (rc != ERROR_SUCCESS)
1621 {
1622 RegCloseKey(hEnumKey);
1623 return rc;
1624 }
1625 }
1626 RegCloseKey(hEnumKey);
1627 return ERROR_SUCCESS;
1628 }
1629 }
1630
1631 static BOOL DestroyDeviceInterface(struct DeviceInterface* deviceInterface)
1632 {
1633 HeapFree(GetProcessHeap(), 0, deviceInterface);
1634 return TRUE;
1635 }
1636
1637 static LONG SETUP_CreateInterfaceList(
1638 struct DeviceInfoSet *list,
1639 PCWSTR MachineName,
1640 LPGUID InterfaceGuid,
1641 PCWSTR DeviceInstanceW /* OPTIONAL */,
1642 BOOL OnlyPresentInterfaces
1643 )
1644 {
1645 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1646 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1647 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1648 HKEY hControlKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
1649 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1650 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1651 LONG rc;
1652 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
1653 PWSTR pSymbolicLink = NULL;
1654 PWSTR InstancePath = NULL;
1655 DWORD i, j;
1656 DWORD dwLength, dwInstancePathLength;
1657 DWORD dwRegType;
1658 DWORD LinkedValue;
1659 GUID ClassGuid;
1660 struct DeviceInfoElement *deviceInfo;
1661
1662 hInterfaceKey = INVALID_HANDLE_VALUE;
1663 hDeviceInstanceKey = INVALID_HANDLE_VALUE;
1664
1665 /* Open registry key related to this interface */
1666 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
1667 if (hInterfaceKey == INVALID_HANDLE_VALUE)
1668 {
1669 rc = GetLastError();
1670 goto cleanup;
1671 }
1672
1673 /* Enumerate sub keys of hInterfaceKey */
1674 i = 0;
1675 while (TRUE)
1676 {
1677 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1678 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1679 if (rc == ERROR_NO_MORE_ITEMS)
1680 break;
1681 if (rc != ERROR_SUCCESS)
1682 goto cleanup;
1683 i++;
1684
1685 /* Open sub key */
1686 if (hDeviceInstanceKey != INVALID_HANDLE_VALUE)
1687 RegCloseKey(hDeviceInstanceKey);
1688 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
1689 if (rc != ERROR_SUCCESS)
1690 goto cleanup;
1691
1692 /* Read DeviceInstance */
1693 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
1694 if (rc != ERROR_SUCCESS)
1695 goto cleanup;
1696 if (dwRegType != REG_SZ)
1697 {
1698 rc = ERROR_GEN_FAILURE;
1699 goto cleanup;
1700 }
1701 if (InstancePath != NULL)
1702 HeapFree(GetProcessHeap(), 0, InstancePath);
1703 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1704 if (!InstancePath)
1705 {
1706 rc = ERROR_NOT_ENOUGH_MEMORY;
1707 goto cleanup;
1708 }
1709 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1710 if (rc != ERROR_SUCCESS)
1711 goto cleanup;
1712 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1713 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1714
1715 if (DeviceInstanceW)
1716 {
1717 /* Check if device enumerator is not the right one */
1718 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
1719 continue;
1720 }
1721
1722 /* Find class GUID associated to the device instance */
1723 rc = RegOpenKeyExW(
1724 list->HKLM,
1725 REGSTR_PATH_SYSTEMENUM,
1726 0, /* Options */
1727 0,
1728 &hEnumKey);
1729 if (rc != ERROR_SUCCESS)
1730 goto cleanup;
1731 rc = RegOpenKeyExW(
1732 hEnumKey,
1733 InstancePath,
1734 0, /* Options */
1735 KEY_QUERY_VALUE,
1736 &hKey);
1737 RegCloseKey(hEnumKey);
1738 if (rc != ERROR_SUCCESS)
1739 goto cleanup;
1740 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1741 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1742 RegCloseKey(hKey);
1743 if (rc != ERROR_SUCCESS)
1744 goto cleanup;
1745 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1746 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1747 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1748 {
1749 rc = ERROR_GEN_FAILURE;
1750 goto cleanup;
1751 }
1752 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1753
1754 /* If current device doesn't match the list GUID (if any), skip this entry */
1755 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1756 continue;
1757
1758 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1759 j = 0;
1760 while (TRUE)
1761 {
1762 struct DeviceInterface *interfaceInfo;
1763
1764 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1765 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1766 if (rc == ERROR_NO_MORE_ITEMS)
1767 break;
1768 if (rc != ERROR_SUCCESS)
1769 goto cleanup;
1770 j++;
1771 if (KeyBuffer[0] != '#')
1772 /* This entry doesn't represent an interesting entry */
1773 continue;
1774
1775 /* Open sub key */
1776 if (hReferenceKey != INVALID_HANDLE_VALUE)
1777 RegCloseKey(hReferenceKey);
1778 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1779 if (rc != ERROR_SUCCESS)
1780 goto cleanup;
1781
1782 /* Read SymbolicLink value */
1783 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1784 if (rc != ERROR_SUCCESS )
1785 goto cleanup;
1786 if (dwRegType != REG_SZ)
1787 {
1788 rc = ERROR_GEN_FAILURE;
1789 goto cleanup;
1790 }
1791
1792 /* We have found a device */
1793 /* Step 1. Create a device info element */
1794 if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
1795 {
1796 rc = GetLastError();
1797 goto cleanup;
1798 }
1799 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1800 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1801
1802 /* Step 2. Create an interface list for this element */
1803 if (pSymbolicLink != NULL)
1804 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1805 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1806 if (!pSymbolicLink)
1807 {
1808 rc = ERROR_NOT_ENOUGH_MEMORY;
1809 goto cleanup;
1810 }
1811 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1812 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1813 RegCloseKey(hReferenceKey);
1814 if (rc != ERROR_SUCCESS)
1815 goto cleanup;
1816 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1817 {
1818 rc = GetLastError();
1819 goto cleanup;
1820 }
1821
1822 /* Step 3. Update flags */
1823 if (KeyBuffer[1] == '\0')
1824 interfaceInfo->Flags |= SPINT_DEFAULT;
1825 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
1826 if (rc != ERROR_SUCCESS)
1827 {
1828 if (OnlyPresentInterfaces)
1829 {
1830 DestroyDeviceInterface(interfaceInfo);
1831 continue;
1832 }
1833 else
1834 interfaceInfo->Flags |= SPINT_REMOVED;
1835 }
1836 else
1837 {
1838 dwLength = sizeof(DWORD);
1839 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength)
1840 && dwRegType == REG_DWORD && LinkedValue)
1841 interfaceInfo->Flags |= SPINT_ACTIVE;
1842 RegCloseKey(hControlKey);
1843 }
1844
1845 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1846 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1847 }
1848 }
1849 rc = ERROR_SUCCESS;
1850
1851 cleanup:
1852 if (hReferenceKey != INVALID_HANDLE_VALUE)
1853 RegCloseKey(hReferenceKey);
1854 if (hDeviceInstanceKey != INVALID_HANDLE_VALUE)
1855 RegCloseKey(hDeviceInstanceKey);
1856 if (hInterfaceKey != INVALID_HANDLE_VALUE)
1857 RegCloseKey(hInterfaceKey);
1858 if (InstancePath != NULL)
1859 HeapFree(GetProcessHeap(), 0, InstancePath);
1860 if (pSymbolicLink != NULL)
1861 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1862 return rc;
1863 }
1864
1865 /***********************************************************************
1866 * SetupDiGetClassDevsExW (SETUPAPI.@)
1867 */
1868 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1869 CONST GUID *class,
1870 LPCWSTR enumstr,
1871 HWND parent,
1872 DWORD flags,
1873 HDEVINFO deviceset,
1874 LPCWSTR machine,
1875 PVOID reserved)
1876 {
1877 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1878 struct DeviceInfoSet *list;
1879 LPGUID pClassGuid;
1880 LONG rc;
1881
1882 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
1883 parent, flags, deviceset, debugstr_w(machine), reserved);
1884
1885 /* Create the deviceset if not set */
1886 if (deviceset)
1887 {
1888 list = (struct DeviceInfoSet *)deviceset;
1889 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1890 {
1891 SetLastError(ERROR_INVALID_HANDLE);
1892 return INVALID_HANDLE_VALUE;
1893 }
1894 hDeviceInfo = deviceset;
1895 }
1896 else
1897 {
1898 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1899 flags & DIGCF_DEVICEINTERFACE ? NULL : class,
1900 NULL, machine, NULL);
1901 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1902 return INVALID_HANDLE_VALUE;
1903 list = (struct DeviceInfoSet *)hDeviceInfo;
1904 }
1905
1906 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1907 pClassGuid = NULL;
1908 else
1909 pClassGuid = &list->ClassGuid;
1910
1911 if (flags & DIGCF_PROFILE)
1912 FIXME(": flag DIGCF_PROFILE ignored\n");
1913
1914 if (flags & DIGCF_ALLCLASSES)
1915 {
1916 rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
1917 if (rc != ERROR_SUCCESS)
1918 {
1919 SetLastError(rc);
1920 if (!deviceset)
1921 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1922 return INVALID_HANDLE_VALUE;
1923 }
1924 return hDeviceInfo;
1925 }
1926 else if (flags & DIGCF_DEVICEINTERFACE)
1927 {
1928 if (class == NULL)
1929 {
1930 SetLastError(ERROR_INVALID_PARAMETER);
1931 if (!deviceset)
1932 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1933 return INVALID_HANDLE_VALUE;
1934 }
1935
1936 rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr, flags & DIGCF_PRESENT);
1937 if (rc != ERROR_SUCCESS)
1938 {
1939 SetLastError(rc);
1940 if (!deviceset)
1941 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1942 return INVALID_HANDLE_VALUE;
1943 }
1944 return hDeviceInfo;
1945 }
1946 else
1947 {
1948 rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
1949 if (rc != ERROR_SUCCESS)
1950 {
1951 SetLastError(rc);
1952 if (!deviceset)
1953 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1954 return INVALID_HANDLE_VALUE;
1955 }
1956 return hDeviceInfo;
1957 }
1958 }
1959
1960 /***********************************************************************
1961 * SetupDiGetClassImageIndex (SETUPAPI.@)
1962 */
1963
1964 static BOOL GetIconIndex(
1965 IN HKEY hClassKey,
1966 OUT PINT ImageIndex)
1967 {
1968 LPWSTR Buffer = NULL;
1969 DWORD dwRegType, dwLength;
1970 LONG rc;
1971 BOOL ret = FALSE;
1972
1973 /* Read icon registry key */
1974 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
1975 if (rc != ERROR_SUCCESS)
1976 {
1977 SetLastError(rc);
1978 goto cleanup;
1979 } else if (dwRegType != REG_SZ)
1980 {
1981 SetLastError(ERROR_INVALID_INDEX);
1982 goto cleanup;
1983 }
1984 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
1985 if (!Buffer)
1986 {
1987 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1988 goto cleanup;
1989 }
1990 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
1991 if (rc != ERROR_SUCCESS)
1992 {
1993 SetLastError(rc);
1994 goto cleanup;
1995 }
1996 /* make sure the returned buffer is NULL-terminated */
1997 Buffer[dwLength / sizeof(WCHAR)] = 0;
1998
1999 /* Transform icon value to a INT */
2000 *ImageIndex = atoiW(Buffer);
2001 ret = TRUE;
2002
2003 cleanup:
2004 MyFree(Buffer);
2005 return ret;
2006 }
2007
2008 BOOL WINAPI SetupDiGetClassImageIndex(
2009 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
2010 IN CONST GUID *ClassGuid,
2011 OUT PINT ImageIndex)
2012 {
2013 struct ClassImageList *list;
2014 BOOL ret = FALSE;
2015
2016 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
2017
2018 if (!ClassImageListData || !ClassGuid || !ImageIndex)
2019 SetLastError(ERROR_INVALID_PARAMETER);
2020 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2021 SetLastError(ERROR_INVALID_USER_BUFFER);
2022 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
2023 SetLastError(ERROR_INVALID_USER_BUFFER);
2024 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
2025 SetLastError(ERROR_INVALID_USER_BUFFER);
2026 else if (!ImageIndex)
2027 SetLastError(ERROR_INVALID_PARAMETER);
2028 else
2029 {
2030 HKEY hKey = INVALID_HANDLE_VALUE;
2031 INT iconIndex;
2032
2033 /* Read Icon registry entry into Buffer */
2034 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL);
2035 if (hKey == INVALID_HANDLE_VALUE)
2036 goto cleanup;
2037 if (!GetIconIndex(hKey, &iconIndex))
2038 goto cleanup;
2039
2040 if (iconIndex >= 0)
2041 {
2042 SetLastError(ERROR_INVALID_INDEX);
2043 goto cleanup;
2044 }
2045
2046 *ImageIndex = -iconIndex;
2047 ret = TRUE;
2048
2049 cleanup:
2050 if (hKey != INVALID_HANDLE_VALUE)
2051 RegCloseKey(hKey);
2052 }
2053
2054 TRACE("Returning %d\n", ret);
2055 return ret;
2056 }
2057
2058 /***********************************************************************
2059 * SetupDiGetClassImageList(SETUPAPI.@)
2060 */
2061 BOOL WINAPI SetupDiGetClassImageList(
2062 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
2063 {
2064 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
2065 }
2066
2067 /***********************************************************************
2068 * SetupDiGetClassImageListExA(SETUPAPI.@)
2069 */
2070 BOOL WINAPI SetupDiGetClassImageListExA(
2071 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2072 IN PCSTR MachineName OPTIONAL,
2073 IN PVOID Reserved)
2074 {
2075 PWSTR MachineNameW = NULL;
2076 BOOL ret;
2077
2078 if (MachineName)
2079 {
2080 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2081 if (MachineNameW == NULL)
2082 return FALSE;
2083 }
2084
2085 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
2086
2087 if (MachineNameW)
2088 MyFree(MachineNameW);
2089
2090 return ret;
2091 }
2092
2093 /***********************************************************************
2094 * SetupDiGetClassImageListExW(SETUPAPI.@)
2095 */
2096 BOOL WINAPI SetupDiGetClassImageListExW(
2097 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2098 IN PCWSTR MachineName OPTIONAL,
2099 IN PVOID Reserved)
2100 {
2101 BOOL ret = FALSE;
2102
2103 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
2104
2105 if (!ClassImageListData)
2106 SetLastError(ERROR_INVALID_PARAMETER);
2107 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2108 SetLastError(ERROR_INVALID_USER_BUFFER);
2109 else if (Reserved)
2110 SetLastError(ERROR_INVALID_PARAMETER);
2111 else
2112 {
2113 struct ClassImageList *list = NULL;
2114 DWORD size;
2115
2116 size = FIELD_OFFSET(struct ClassImageList, szData);
2117 if (MachineName)
2118 size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
2119 list = HeapAlloc(GetProcessHeap(), 0, size);
2120 if (!list)
2121 {
2122 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2123 goto cleanup;
2124 }
2125 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
2126 if (MachineName)
2127 {
2128 list->szData[0] = list->szData[1] = '\\';
2129 strcpyW(list->szData + 2, MachineName);
2130 list->MachineName = list->szData;
2131 }
2132 else
2133 {
2134 list->MachineName = NULL;
2135 }
2136
2137 ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */
2138 ret = TRUE;
2139
2140 cleanup:
2141 if (!ret)
2142 MyFree(list);
2143 }
2144
2145 TRACE("Returning %d\n", ret);
2146 return ret;
2147 }
2148
2149 /***********************************************************************
2150 * SetupDiLoadClassIcon(SETUPAPI.@)
2151 */
2152 BOOL WINAPI SetupDiLoadClassIcon(
2153 IN CONST GUID *ClassGuid,
2154 OUT HICON *LargeIcon OPTIONAL,
2155 OUT PINT MiniIconIndex OPTIONAL)
2156 {
2157 BOOL ret = FALSE;
2158
2159 if (!ClassGuid)
2160 SetLastError(ERROR_INVALID_PARAMETER);
2161 else
2162 {
2163 LPWSTR Buffer = NULL;
2164 LPCWSTR DllName;
2165 INT iconIndex;
2166 HKEY hKey = INVALID_HANDLE_VALUE;
2167
2168 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
2169 if (hKey == INVALID_HANDLE_VALUE)
2170 goto cleanup;
2171
2172 if (!GetIconIndex(hKey, &iconIndex))
2173 goto cleanup;
2174
2175 if (iconIndex > 0)
2176 {
2177 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
2178 PWCHAR Comma;
2179 LONG rc;
2180 DWORD dwRegType, dwLength;
2181 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
2182 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2183 {
2184 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2185 if (Buffer == NULL)
2186 {
2187 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2188 goto cleanup;
2189 }
2190 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2191 if (rc != ERROR_SUCCESS)
2192 {
2193 SetLastError(rc);
2194 goto cleanup;
2195 }
2196 /* make sure the returned buffer is NULL-terminated */
2197 Buffer[dwLength / sizeof(WCHAR)] = 0;
2198 }
2199 else if
2200 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
2201 && dwRegType == REG_SZ)
2202 {
2203 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2204 if (Buffer == NULL)
2205 {
2206 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2207 goto cleanup;
2208 }
2209 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2210 if (rc != ERROR_SUCCESS)
2211 {
2212 SetLastError(rc);
2213 goto cleanup;
2214 }
2215 /* make sure the returned buffer is NULL-terminated */
2216 Buffer[dwLength / sizeof(WCHAR)] = 0;
2217 }
2218 else
2219 {
2220 /* Unable to find where to load the icon */
2221 SetLastError(ERROR_FILE_NOT_FOUND);
2222 goto cleanup;
2223 }
2224 Comma = strchrW(Buffer, ',');
2225 if (!Comma)
2226 {
2227 SetLastError(ERROR_GEN_FAILURE);
2228 goto cleanup;
2229 }
2230 *Comma = '\0';
2231 DllName = Buffer;
2232 }
2233 else
2234 {
2235 /* Look up icon in setupapi.dll */
2236 DllName = L"setupapi.dll";
2237 iconIndex = -iconIndex;
2238 }
2239
2240 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
2241 if (LargeIcon)
2242 {
2243 if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
2244 {
2245 SetLastError(ERROR_INVALID_INDEX);
2246 goto cleanup;
2247 }
2248 }
2249 if (MiniIconIndex)
2250 *MiniIconIndex = iconIndex;
2251 ret = TRUE;
2252
2253 cleanup:
2254 if (hKey != INVALID_HANDLE_VALUE)
2255 RegCloseKey(hKey);
2256 MyFree(Buffer);
2257 }
2258
2259 TRACE("Returning %d\n", ret);
2260 return ret;
2261 }
2262
2263 /***********************************************************************
2264 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2265 */
2266 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2267 HDEVINFO DeviceInfoSet,
2268 PSP_DEVINFO_DATA DeviceInfoData,
2269 CONST GUID * InterfaceClassGuid,
2270 DWORD MemberIndex,
2271 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2272 {
2273 BOOL ret = FALSE;
2274
2275 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
2276 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2277
2278 if (!DeviceInterfaceData)
2279 SetLastError(ERROR_INVALID_PARAMETER);
2280 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2281 SetLastError(ERROR_INVALID_USER_BUFFER);
2282 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
2283 {
2284 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2285
2286 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2287 {
2288 PLIST_ENTRY ItemList = list->ListHead.Flink;
2289 BOOL Found = FALSE;
2290 while (ItemList != &list->ListHead && !Found)
2291 {
2292 PLIST_ENTRY InterfaceListEntry;
2293 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
2294 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
2295 {
2296 /* We are not searching for this element */
2297 ItemList = ItemList->Flink;
2298 continue;
2299 }
2300 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
2301 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
2302 {
2303 struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
2304 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2305 {
2306 InterfaceListEntry = InterfaceListEntry->Flink;
2307 continue;
2308 }
2309 if (MemberIndex-- == 0)
2310 {
2311 /* return this item */
2312 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2313 &DevItf->InterfaceClassGuid,
2314 sizeof(GUID));
2315 DeviceInterfaceData->Flags = DevItf->Flags;
2316 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2317 Found = TRUE;
2318 }
2319 InterfaceListEntry = InterfaceListEntry->Flink;
2320 }
2321 ItemList = ItemList->Flink;
2322 }
2323 if (!Found)
2324 SetLastError(ERROR_NO_MORE_ITEMS);
2325 else
2326 ret = TRUE;
2327 }
2328 else
2329 SetLastError(ERROR_INVALID_HANDLE);
2330 }
2331 else
2332 SetLastError(ERROR_INVALID_HANDLE);
2333 return ret;
2334 }
2335
2336 static VOID ReferenceInfFile(struct InfFileDetails* infFile)
2337 {
2338 InterlockedIncrement(&infFile->References);
2339 }
2340
2341 static VOID DereferenceInfFile(struct InfFileDetails* infFile)
2342 {
2343 if (InterlockedDecrement(&infFile->References) == 0)
2344 {
2345 SetupCloseInfFile(infFile->hInf);
2346 HeapFree(GetProcessHeap(), 0, infFile);
2347 }
2348 }
2349
2350 static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
2351 {
2352 DereferenceInfFile(driverInfo->InfFileDetails);
2353 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
2354 HeapFree(GetProcessHeap(), 0, driverInfo);
2355 return TRUE;
2356 }
2357
2358 static BOOL DestroyClassInstallParams(struct ClassInstallParams* installParams)
2359 {
2360 HeapFree(GetProcessHeap(), 0, installParams->PropChange);
2361 return TRUE;
2362 }
2363
2364 static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
2365 {
2366 PLIST_ENTRY ListEntry;
2367 struct DriverInfoElement *driverInfo;
2368 struct DeviceInterface *deviceInterface;
2369
2370 while (!IsListEmpty(&deviceInfo->DriverListHead))
2371 {
2372 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
2373 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
2374 if (!DestroyDriverInfoElement(driverInfo))
2375 return FALSE;
2376 }
2377 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
2378 {
2379 ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
2380 deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
2381 if (!DestroyDeviceInterface(deviceInterface))
2382 return FALSE;
2383 }
2384 DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
2385 HeapFree(GetProcessHeap(), 0, deviceInfo);
2386 return TRUE;
2387 }
2388
2389 static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
2390 {
2391 PLIST_ENTRY ListEntry;
2392 struct DeviceInfoElement *deviceInfo;
2393
2394 while (!IsListEmpty(&list->ListHead))
2395 {
2396 ListEntry = RemoveHeadList(&list->ListHead);
2397 deviceInfo = (struct DeviceInfoElement *)ListEntry;
2398 if (!DestroyDeviceInfoElement(deviceInfo))
2399 return FALSE;
2400 }
2401 if (list->HKLM != HKEY_LOCAL_MACHINE)
2402 RegCloseKey(list->HKLM);
2403 CM_Disconnect_Machine(list->hMachine);
2404 DestroyClassInstallParams(&list->ClassInstallParams);
2405 HeapFree(GetProcessHeap(), 0, list);
2406 return TRUE;
2407 }
2408
2409 /***********************************************************************
2410 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2411 */
2412 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2413 {
2414 BOOL ret = FALSE;
2415
2416 TRACE("%p\n", devinfo);
2417 if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
2418 {
2419 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2420
2421 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2422 ret = DestroyDeviceInfoSet(list);
2423 else
2424 SetLastError(ERROR_INVALID_HANDLE);
2425 }
2426 else
2427 SetLastError(ERROR_INVALID_HANDLE);
2428
2429 TRACE("Returning %d\n", ret);
2430 return ret;
2431 }
2432
2433 /***********************************************************************
2434 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2435 */
2436 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2437 HDEVINFO DeviceInfoSet,
2438 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2439 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2440 DWORD DeviceInterfaceDetailDataSize,
2441 PDWORD RequiredSize,
2442 PSP_DEVINFO_DATA DeviceInfoData)
2443 {
2444 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2445 DWORD sizeW = 0, sizeA;
2446 BOOL ret = FALSE;
2447
2448 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2449 DeviceInterfaceData, DeviceInterfaceDetailData,
2450 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2451
2452 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2453 SetLastError(ERROR_INVALID_USER_BUFFER);
2454 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2455 SetLastError(ERROR_INVALID_PARAMETER);
2456 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2457 SetLastError(ERROR_INVALID_PARAMETER);
2458 else
2459 {
2460 if (DeviceInterfaceDetailData != NULL)
2461 {
2462 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2463 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2464 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2465 if (!DeviceInterfaceDetailDataW)
2466 {
2467 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2468 }
2469 }
2470 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2471 {
2472 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2473 ret = SetupDiGetDeviceInterfaceDetailW(
2474 DeviceInfoSet,
2475 DeviceInterfaceData,
2476 DeviceInterfaceDetailDataW,
2477 sizeW,
2478 &sizeW,
2479 DeviceInfoData);
2480 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2481 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2482 if (RequiredSize)
2483 *RequiredSize = sizeA;
2484 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2485 {
2486 if (!WideCharToMultiByte(
2487 CP_ACP, 0,
2488 DeviceInterfaceDetailDataW->DevicePath, -1,
2489 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2490 NULL, NULL))
2491 {
2492 ret = FALSE;
2493 }
2494 }
2495 }
2496 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2497 }
2498
2499 TRACE("Returning %d\n", ret);
2500 return ret;
2501 }
2502
2503 /***********************************************************************
2504 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2505 */
2506 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2507 HDEVINFO DeviceInfoSet,
2508 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2509 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2510 DWORD DeviceInterfaceDetailDataSize,
2511 PDWORD RequiredSize,
2512 PSP_DEVINFO_DATA DeviceInfoData)
2513 {
2514 BOOL ret = FALSE;
2515
2516 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2517 DeviceInterfaceData, DeviceInterfaceDetailData,
2518 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2519
2520 if (!DeviceInfoSet || !DeviceInterfaceData)
2521 SetLastError(ERROR_INVALID_PARAMETER);
2522 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2523 SetLastError(ERROR_INVALID_HANDLE);
2524 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2525 SetLastError(ERROR_INVALID_HANDLE);
2526 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2527 SetLastError(ERROR_INVALID_USER_BUFFER);
2528 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2529 SetLastError(ERROR_INVALID_USER_BUFFER);
2530 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2531 SetLastError(ERROR_INVALID_USER_BUFFER);
2532 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2533 SetLastError(ERROR_INVALID_PARAMETER);
2534 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2535 SetLastError(ERROR_INVALID_PARAMETER);
2536 else
2537 {
2538 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2539 LPCWSTR devName = deviceInterface->SymbolicLink;
2540 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2541 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2542
2543 if (sizeRequired > DeviceInterfaceDetailDataSize)
2544 {
2545 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2546 if (RequiredSize)
2547 *RequiredSize = sizeRequired;
2548 }
2549 else
2550 {
2551 strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
2552 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2553 if (DeviceInfoData)
2554 {
2555 memcpy(&DeviceInfoData->ClassGuid,
2556 &deviceInterface->DeviceInfo->ClassGuid,
2557 sizeof(GUID));
2558 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
2559 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2560 }
2561 ret = TRUE;
2562 }
2563 }
2564
2565 TRACE("Returning %d\n", ret);
2566 return ret;
2567 }
2568
2569 /***********************************************************************
2570 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2571 */
2572 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2573 HDEVINFO devinfo,
2574 PSP_DEVINFO_DATA DeviceInfoData,
2575 DWORD Property,
2576 PDWORD PropertyRegDataType,
2577 PBYTE PropertyBuffer,
2578 DWORD PropertyBufferSize,
2579 PDWORD RequiredSize)
2580 {
2581 BOOL bResult;
2582 BOOL bIsStringProperty;
2583 DWORD RegType;
2584 DWORD RequiredSizeA, RequiredSizeW;
2585 DWORD PropertyBufferSizeW;
2586 PBYTE PropertyBufferW;
2587
2588 TRACE("%p %p %ld %p %p %ld %p\n", devinfo, DeviceInfoData,
2589 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2590 RequiredSize);
2591
2592 PropertyBufferSizeW = PropertyBufferSize * 2;
2593 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2594
2595 bResult = SetupDiGetDeviceRegistryPropertyW(
2596 devinfo,
2597 DeviceInfoData,
2598 Property,
2599 &RegType,
2600 PropertyBufferW,
2601 PropertyBufferSizeW,
2602 &RequiredSizeW);
2603
2604 if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2605 {
2606 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2607
2608 if (bIsStringProperty)
2609 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2610 else
2611 RequiredSizeA = RequiredSizeW;
2612 if (RequiredSize)
2613 *RequiredSize = RequiredSizeA;
2614 if (PropertyRegDataType)
2615 *PropertyRegDataType = RegType;
2616 }
2617
2618 if (!bResult)
2619 {
2620 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2621 return bResult;
2622 }
2623
2624 if (RequiredSizeA <= PropertyBufferSize)
2625 {
2626 if (bIsStringProperty && PropertyBufferSize > 0)
2627 {
2628 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2629 {
2630 /* Last error is already set by WideCharToMultiByte */
2631 bResult = FALSE;
2632 }
2633 }
2634 else
2635 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2636 }
2637 else
2638 {
2639 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2640 bResult = FALSE;
2641 }
2642
2643 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2644 return bResult;
2645 }
2646
2647 /***********************************************************************
2648 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2649 */
2650 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2651 HDEVINFO DeviceInfoSet,
2652 PSP_DEVINFO_DATA DeviceInfoData,
2653 DWORD Property,
2654 PDWORD PropertyRegDataType,
2655 PBYTE PropertyBuffer,
2656 DWORD PropertyBufferSize,
2657 PDWORD RequiredSize)
2658 {
2659 HKEY hEnumKey, hKey;
2660 DWORD rc;
2661 BOOL ret = FALSE;
2662
2663 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2664 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2665 RequiredSize);
2666
2667 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2668 SetLastError(ERROR_INVALID_HANDLE);
2669 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2670 SetLastError(ERROR_INVALID_HANDLE);
2671 else if (!DeviceInfoData)
2672 SetLastError(ERROR_INVALID_PARAMETER);
2673 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2674 SetLastError(ERROR_INVALID_USER_BUFFER);
2675 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2676 SetLastError(ERROR_INVALID_PARAMETER);
2677 else
2678 {
2679 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2680 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2681
2682 switch (Property)
2683 {
2684 case SPDRP_CAPABILITIES:
2685 case SPDRP_CLASS:
2686 case SPDRP_CLASSGUID:
2687 case SPDRP_COMPATIBLEIDS:
2688 case SPDRP_CONFIGFLAGS:
2689 case SPDRP_DEVICEDESC:
2690 case SPDRP_DRIVER:
2691 case SPDRP_FRIENDLYNAME:
2692 case SPDRP_HARDWAREID:
2693 case SPDRP_LOCATION_INFORMATION:
2694 case SPDRP_LOWERFILTERS:
2695 case SPDRP_MFG:
2696 case SPDRP_SECURITY:
2697 case SPDRP_SERVICE:
2698 case SPDRP_UI_NUMBER:
2699 case SPDRP_UI_NUMBER_DESC_FORMAT:
2700 case SPDRP_UPPERFILTERS:
2701 {
2702 LPCWSTR RegistryPropertyName;
2703 DWORD BufferSize;
2704
2705 switch (Property)
2706 {
2707 case SPDRP_CAPABILITIES:
2708 RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
2709 case SPDRP_CLASS:
2710 RegistryPropertyName = REGSTR_VAL_CLASS; break;
2711 case SPDRP_CLASSGUID:
2712 RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
2713 case SPDRP_COMPATIBLEIDS:
2714 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
2715 case SPDRP_CONFIGFLAGS:
2716 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
2717 case SPDRP_DEVICEDESC:
2718 RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
2719 case SPDRP_DRIVER:
2720 RegistryPropertyName = REGSTR_VAL_DRIVER; break;
2721 case SPDRP_FRIENDLYNAME:
2722 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
2723 case SPDRP_HARDWAREID:
2724 RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
2725 case SPDRP_LOCATION_INFORMATION:
2726 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
2727 case SPDRP_LOWERFILTERS:
2728 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
2729 case SPDRP_MFG:
2730 RegistryPropertyName = REGSTR_VAL_MFG; break;
2731 case SPDRP_SECURITY:
2732 RegistryPropertyName = REGSTR_SECURITY; break;
2733 case SPDRP_SERVICE:
2734 RegistryPropertyName = REGSTR_VAL_SERVICE; break;
2735 case SPDRP_UI_NUMBER:
2736 RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
2737 case SPDRP_UI_NUMBER_DESC_FORMAT:
2738 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
2739 case SPDRP_UPPERFILTERS:
2740 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
2741 default:
2742 /* Should not happen */
2743 RegistryPropertyName = NULL; break;
2744 }
2745
2746 /* Open registry key name */
2747 rc = RegOpenKeyExW(
2748 list->HKLM,
2749 REGSTR_PATH_SYSTEMENUM,
2750 0, /* Options */
2751 0,
2752 &hEnumKey);
2753 if (rc != ERROR_SUCCESS)
2754 {
2755 SetLastError(rc);
2756 break;
2757 }
2758 rc = RegOpenKeyExW(
2759 hEnumKey,
2760 DevInfo->Data,
2761 0, /* Options */
2762 KEY_QUERY_VALUE,
2763 &hKey);
2764 RegCloseKey(hEnumKey);
2765 if (rc != ERROR_SUCCESS)
2766 {
2767 SetLastError(rc);
2768 break;
2769 }
2770 /* Read registry entry */
2771 BufferSize = PropertyBufferSize;
2772 rc = RegQueryValueExW(
2773 hKey,
2774 RegistryPropertyName,
2775 NULL, /* Reserved */
2776 PropertyRegDataType,
2777 PropertyBuffer,
2778 &BufferSize);
2779 if (RequiredSize)
2780 *RequiredSize = BufferSize;
2781 switch(rc) {
2782 case ERROR_SUCCESS:
2783 if (PropertyBuffer != NULL || BufferSize == 0)
2784 ret = TRUE;
2785 else
2786 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2787 break;
2788 case ERROR_MORE_DATA:
2789 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2790 break;
2791 default:
2792 SetLastError(rc);
2793 }
2794 RegCloseKey(hKey);
2795 break;
2796 }
2797
2798 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2799 {
2800 DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
2801
2802 if (PropertyRegDataType)
2803 *PropertyRegDataType = REG_SZ;
2804 if (RequiredSize)
2805 *RequiredSize = required;
2806 if (PropertyBufferSize >= required)
2807 {
2808 strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
2809 ret = TRUE;
2810 }
2811 else
2812 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2813 break;
2814 }
2815
2816 /*case SPDRP_BUSTYPEGUID:
2817 case SPDRP_LEGACYBUSTYPE:
2818 case SPDRP_BUSNUMBER:
2819 case SPDRP_ENUMERATOR_NAME:
2820 case SPDRP_SECURITY_SDS:
2821 case SPDRP_DEVTYPE:
2822 case SPDRP_EXCLUSIVE:
2823 case SPDRP_CHARACTERISTICS:
2824 case SPDRP_ADDRESS:
2825 case SPDRP_DEVICE_POWER_DATA:*/
2826 #if (WINVER >= 0x501)
2827 /*case SPDRP_REMOVAL_POLICY:
2828 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2829 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2830 case SPDRP_INSTALL_STATE:*/
2831 #endif
2832
2833 default:
2834 {
2835 ERR("Property 0x%lx not implemented\n", Property);
2836 SetLastError(ERROR_NOT_SUPPORTED);
2837 }
2838 }
2839 }
2840
2841 TRACE("Returning %d\n", ret);
2842 return ret;
2843 }
2844
2845 /***********************************************************************
2846 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2847 */
2848 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
2849 IN HDEVINFO DeviceInfoSet,
2850 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2851 IN DWORD Property,
2852 IN CONST BYTE *PropertyBuffer,
2853 IN DWORD PropertyBufferSize)
2854 {
2855 FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2856 Property, PropertyBuffer, PropertyBufferSize);
2857 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2858 return FALSE;
2859 }
2860
2861 /***********************************************************************
2862 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2863 */
2864 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
2865 IN HDEVINFO DeviceInfoSet,
2866 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2867 IN DWORD Property,
2868 IN const BYTE *PropertyBuffer,
2869 IN DWORD PropertyBufferSize)
2870 {
2871 struct DeviceInfoSet *list;
2872 BOOL ret = FALSE;
2873
2874 TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2875 Property, PropertyBuffer, PropertyBufferSize);
2876
2877 if (!DeviceInfoSet)
2878 SetLastError(ERROR_INVALID_HANDLE);
2879 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2880 SetLastError(ERROR_INVALID_HANDLE);
2881 else if (!DeviceInfoData)
2882 SetLastError(ERROR_INVALID_HANDLE);
2883 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2884 SetLastError(ERROR_INVALID_USER_BUFFER);
2885 else
2886 {
2887 switch (Property)
2888 {
2889 case SPDRP_COMPATIBLEIDS:
2890 case SPDRP_CONFIGFLAGS:
2891 case SPDRP_FRIENDLYNAME:
2892 case SPDRP_HARDWAREID:
2893 case SPDRP_LOCATION_INFORMATION:
2894 case SPDRP_LOWERFILTERS:
2895 case SPDRP_SECURITY:
2896 case SPDRP_SERVICE:
2897 case SPDRP_UI_NUMBER_DESC_FORMAT:
2898 case SPDRP_UPPERFILTERS:
2899 {
2900 LPCWSTR RegistryPropertyName;
2901 DWORD RegistryDataType;
2902 HKEY hKey;
2903 LONG rc;
2904
2905 switch (Property)
2906 {
2907 case SPDRP_COMPATIBLEIDS:
2908 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
2909 RegistryDataType = REG_MULTI_SZ;
2910 break;
2911 case SPDRP_CONFIGFLAGS:
2912 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
2913 RegistryDataType = REG_DWORD;
2914 break;
2915 case SPDRP_FRIENDLYNAME:
2916 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
2917 RegistryDataType = REG_SZ;
2918 break;
2919 case SPDRP_HARDWAREID:
2920 RegistryPropertyName = REGSTR_VAL_HARDWAREID;
2921 RegistryDataType = REG_MULTI_SZ;
2922 break;
2923 case SPDRP_LOCATION_INFORMATION:
2924 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
2925 RegistryDataType = REG_SZ;
2926 break;
2927 case SPDRP_LOWERFILTERS:
2928 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
2929 RegistryDataType = REG_MULTI_SZ;
2930 break;
2931 case SPDRP_SECURITY:
2932 RegistryPropertyName = REGSTR_SECURITY;
2933 RegistryDataType = REG_BINARY;
2934 break;
2935 case SPDRP_SERVICE:
2936 RegistryPropertyName = REGSTR_VAL_SERVICE;
2937 RegistryDataType = REG_SZ;
2938 break;
2939 case SPDRP_UI_NUMBER_DESC_FORMAT:
2940 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
2941 RegistryDataType = REG_SZ;
2942 break;
2943 case SPDRP_UPPERFILTERS:
2944 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
2945 RegistryDataType = REG_MULTI_SZ;
2946 break;
2947 default:
2948 /* Should not happen */
2949 RegistryPropertyName = NULL;
2950 RegistryDataType = REG_BINARY;
2951 break;
2952 }
2953 /* Open device registry key */
2954 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
2955 if (hKey != INVALID_HANDLE_VALUE)
2956 {
2957 /* Write new data */
2958 rc = RegSetValueExW(
2959 hKey,
2960 RegistryPropertyName,
2961 0, /* Reserved */
2962 RegistryDataType,
2963 PropertyBuffer,
2964 PropertyBufferSize);
2965 if (rc == ERROR_SUCCESS)
2966 ret = TRUE;
2967 else
2968 SetLastError(rc);
2969 RegCloseKey(hKey);
2970 }
2971 break;
2972 }
2973
2974 /*case SPDRP_CHARACTERISTICS:
2975 case SPDRP_DEVTYPE:
2976 case SPDRP_EXCLUSIVE:*/
2977 #if (WINVER >= 0x501)
2978 //case SPDRP_REMOVAL_POLICY_OVERRIDE:
2979 #endif
2980 //case SPDRP_SECURITY_SDS:
2981
2982 default:
2983 {
2984 ERR("Property 0x%lx not implemented\n", Property);
2985 SetLastError(ERROR_NOT_SUPPORTED);
2986 }
2987 }
2988 }
2989
2990 TRACE("Returning %d\n", ret);
2991 return ret;
2992 }
2993
2994
2995 /***********************************************************************
2996 * SetupDiInstallClassA (SETUPAPI.@)
2997 */
2998 BOOL WINAPI SetupDiInstallClassA(
2999 IN HWND hwndParent OPTIONAL,
3000 IN PCSTR InfFileName,
3001 IN DWORD Flags,
3002 IN HSPFILEQ FileQueue OPTIONAL)
3003 {
3004 return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3005 }
3006
3007
3008 /***********************************************************************
3009 * SetupDiInstallClassW (SETUPAPI.@)
3010 */
3011 BOOL WINAPI SetupDiInstallClassW(
3012 IN HWND hwndParent OPTIONAL,
3013 IN PCWSTR InfFileName,
3014 IN DWORD Flags,
3015 IN HSPFILEQ FileQueue OPTIONAL)
3016 {
3017 return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3018 }
3019
3020
3021 /***********************************************************************
3022 * SetupDiInstallClassExA (SETUPAPI.@)
3023 */
3024 BOOL WINAPI SetupDiInstallClassExA(
3025 IN HWND hwndParent OPTIONAL,
3026 IN PCSTR InfFileName OPTIONAL,
3027 IN DWORD Flags,
3028 IN HSPFILEQ FileQueue OPTIONAL,
3029 IN const GUID* InterfaceClassGuid OPTIONAL,
3030 IN PVOID Reserved1,
3031 IN PVOID Reserved2)
3032 {
3033 PWSTR InfFileNameW = NULL;
3034 BOOL Result;
3035
3036 if (InfFileName)
3037 {
3038 InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
3039 if (InfFileNameW == NULL)
3040 {
3041 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3042 return FALSE;
3043 }
3044 }
3045
3046 Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3047 FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3048
3049 MyFree(InfFileNameW);
3050
3051 return Result;
3052 }
3053
3054
3055 static HKEY CreateClassKey(HINF hInf)
3056 {
3057 WCHAR FullBuffer[MAX_PATH];
3058 WCHAR Buffer[MAX_PATH];
3059 DWORD RequiredSize;
3060 HKEY hClassKey;
3061
3062 Buffer[0] = '\\';
3063 if (!SetupGetLineTextW(NULL,
3064 hInf,
3065 Version,
3066 ClassGUID,
3067 &Buffer[1],
3068 MAX_PATH - 1,
3069 &RequiredSize))
3070 {
3071 return INVALID_HANDLE_VALUE;
3072 }
3073
3074 lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3075 lstrcatW(FullBuffer, Buffer);
3076
3077
3078 if (!SetupGetLineTextW(NULL,
3079 hInf,
3080 Version,
3081 Class,
3082 Buffer,
3083 MAX_PATH,
3084 &RequiredSize))
3085 {
3086 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3087 return INVALID_HANDLE_VALUE;
3088 }
3089
3090 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3091 FullBuffer,
3092 0,
3093 NULL,
3094 REG_OPTION_NON_VOLATILE,
3095 KEY_SET_VALUE,
3096 NULL,
3097 &hClassKey,
3098 NULL))
3099 {
3100 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3101 return INVALID_HANDLE_VALUE;
3102 }
3103
3104 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
3105 Class,
3106 0,
3107 REG_SZ,
3108 (LPBYTE)Buffer,
3109 RequiredSize * sizeof(WCHAR)))
3110 {
3111 RegCloseKey(hClassKey);
3112 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3113 return INVALID_HANDLE_VALUE;
3114 }
3115
3116 return hClassKey;
3117 }
3118
3119
3120 /***********************************************************************
3121 * SetupDiInstallClassExW (SETUPAPI.@)
3122 */
3123 BOOL WINAPI SetupDiInstallClassExW(
3124 IN HWND hwndParent OPTIONAL,
3125 IN PCWSTR InfFileName OPTIONAL,
3126 IN DWORD Flags,
3127 IN HSPFILEQ FileQueue OPTIONAL,
3128 IN const GUID* InterfaceClassGuid OPTIONAL,
3129 IN PVOID Reserved1,
3130 IN PVOID Reserved2)
3131 {
3132 BOOL ret = FALSE;
3133
3134 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
3135 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
3136
3137 if (!InfFileName)
3138 {
3139 FIXME("Case not implemented: InfFileName NULL\n");
3140 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3141 }
3142 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
3143 {
3144 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
3145 SetLastError(ERROR_INVALID_FLAGS);
3146 }
3147 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
3148 SetLastError(ERROR_INVALID_PARAMETER);
3149 else if (Reserved1 != NULL)
3150 SetLastError(ERROR_INVALID_PARAMETER);
3151 else if (Reserved2 != NULL)
3152 SetLastError(ERROR_INVALID_PARAMETER);
3153 else
3154 {