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