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