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