af44c34c23c0e7ee8ade429657c050e4ca0003aa
[reactos.git] / reactos / lib / setupapi / devinst.c
1 /*
2 * SetupAPI device installer
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005 Hervé Poussineau (hpoussin@reactos.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #define INITGUID
23 #include "setupapi_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
26
27 /* Unicode constants */
28 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
29 static const WCHAR Class[] = {'C','l','a','s','s',0};
30 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
31 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
32 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
33 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
34 static const WCHAR NtExtension[] = {'.','N','T',0};
35 static const WCHAR NtPlatformExtension[] = {'.','N','T','x','8','6',0};
36 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
37 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
38 static const WCHAR WinExtension[] = {'.','W','i','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 SetupDiGetActualSectionToInstallA(
827 HINF InfHandle,
828 PCSTR InfSectionName,
829 PSTR InfSectionWithExt,
830 DWORD InfSectionWithExtSize,
831 PDWORD RequiredSize,
832 PSTR *Extension)
833 {
834 LPWSTR InfSectionNameW = NULL;
835 PWSTR InfSectionWithExtW = NULL;
836 PWSTR ExtensionW;
837 BOOL bResult = FALSE;
838
839 TRACE("\n");
840
841 if (InfSectionName)
842 {
843 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
844 if (InfSectionNameW == NULL) goto end;
845 }
846 if (InfSectionWithExt)
847 {
848 InfSectionWithExtW = HeapAlloc(GetProcessHeap(), 0, InfSectionWithExtSize * sizeof(WCHAR));
849 if (InfSectionWithExtW == NULL) goto end;
850 }
851
852 bResult = SetupDiGetActualSectionToInstallW(InfHandle, InfSectionNameW,
853 InfSectionWithExt ? InfSectionNameW : NULL,
854 InfSectionWithExtSize, RequiredSize,
855 Extension ? &ExtensionW : NULL);
856
857 if (bResult && InfSectionWithExt)
858 {
859 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
860 InfSectionWithExtSize, NULL, NULL) != 0;
861 }
862 if (bResult && Extension)
863 {
864 if (ExtensionW == NULL)
865 *Extension = NULL;
866 else
867 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
868 }
869
870 end:
871 if (InfSectionNameW) MyFree(InfSectionNameW);
872 if (InfSectionWithExtW) HeapFree(GetProcessHeap(), 0, InfSectionWithExtW);
873
874 return bResult;
875 }
876
877 /***********************************************************************
878 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
879 */
880 BOOL WINAPI SetupDiGetActualSectionToInstallW(
881 HINF InfHandle,
882 PCWSTR InfSectionName,
883 PWSTR InfSectionWithExt,
884 DWORD InfSectionWithExtSize,
885 PDWORD RequiredSize,
886 PWSTR *Extension)
887 {
888 WCHAR szBuffer[MAX_PATH];
889 DWORD dwLength;
890 DWORD dwFullLength;
891 LONG lLineCount = -1;
892
893 TRACE("%p %s %p %lu %p %p\n", InfHandle, debugstr_w(InfSectionName),
894 InfSectionWithExt, InfSectionWithExtSize, RequiredSize, Extension);
895
896 lstrcpyW(szBuffer, InfSectionName);
897 dwLength = lstrlenW(szBuffer);
898
899 if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
900 {
901 /* Test section name with '.NTx86' extension */
902 lstrcpyW(&szBuffer[dwLength], NtPlatformExtension);
903 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
904
905 if (lLineCount == -1)
906 {
907 /* Test section name with '.NT' extension */
908 lstrcpyW(&szBuffer[dwLength], NtExtension);
909 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
910 }
911 }
912 else
913 {
914 /* Test section name with '.Win' extension */
915 lstrcpyW(&szBuffer[dwLength], WinExtension);
916 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
917 }
918
919 if (lLineCount == -1)
920 {
921 /* Test section name without extension */
922 szBuffer[dwLength] = 0;
923 lLineCount = SetupGetLineCountW(InfHandle, szBuffer);
924 }
925
926 if (lLineCount == -1)
927 {
928 SetLastError(ERROR_INVALID_PARAMETER);
929 return FALSE;
930 }
931
932 dwFullLength = lstrlenW(szBuffer);
933
934 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
935 {
936 if (InfSectionWithExtSize < (dwFullLength + 1))
937 {
938 SetLastError(ERROR_INSUFFICIENT_BUFFER);
939 return FALSE;
940 }
941
942 lstrcpyW(InfSectionWithExt, szBuffer);
943 if (Extension != NULL)
944 {
945 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
946 }
947 }
948
949 if (RequiredSize != NULL)
950 {
951 *RequiredSize = dwFullLength + 1;
952 }
953
954 return TRUE;
955 }
956
957 /***********************************************************************
958 * SetupDiGetClassDescriptionA (SETUPAPI.@)
959 */
960 BOOL WINAPI SetupDiGetClassDescriptionA(
961 const GUID* ClassGuid,
962 PSTR ClassDescription,
963 DWORD ClassDescriptionSize,
964 PDWORD RequiredSize)
965 {
966 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
967 ClassDescriptionSize,
968 RequiredSize, NULL, NULL);
969 }
970
971 /***********************************************************************
972 * SetupDiGetClassDescriptionW (SETUPAPI.@)
973 */
974 BOOL WINAPI SetupDiGetClassDescriptionW(
975 const GUID* ClassGuid,
976 PWSTR ClassDescription,
977 DWORD ClassDescriptionSize,
978 PDWORD RequiredSize)
979 {
980 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
981 ClassDescriptionSize,
982 RequiredSize, NULL, NULL);
983 }
984
985 /***********************************************************************
986 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
987 */
988 BOOL WINAPI SetupDiGetClassDescriptionExA(
989 const GUID* ClassGuid,
990 PSTR ClassDescription,
991 DWORD ClassDescriptionSize,
992 PDWORD RequiredSize,
993 PCSTR MachineName,
994 PVOID Reserved)
995 {
996 PWCHAR ClassDescriptionW;
997 LPWSTR MachineNameW = NULL;
998 BOOL ret;
999
1000 TRACE("\n");
1001 if (ClassDescriptionSize > 0)
1002 {
1003 ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
1004 if (!ClassDescriptionW)
1005 {
1006 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1007 ret = FALSE;
1008 goto end;
1009 }
1010 }
1011 else
1012 ClassDescriptionW = NULL;
1013
1014 if (MachineName)
1015 {
1016 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1017 if (!MachineNameW)
1018 {
1019 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1020 ret = FALSE;
1021 goto end;
1022 }
1023 }
1024
1025 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
1026 NULL, MachineNameW, Reserved);
1027 if (ret)
1028 {
1029 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
1030 ClassDescriptionSize, NULL, NULL);
1031
1032 if (!ClassDescriptionSize && RequiredSize)
1033 *RequiredSize = len;
1034 }
1035
1036 end:
1037 HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
1038 MyFree(MachineNameW);
1039 return ret;
1040 }
1041
1042 /***********************************************************************
1043 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1044 */
1045 BOOL WINAPI SetupDiGetClassDescriptionExW(
1046 const GUID* ClassGuid,
1047 PWSTR ClassDescription,
1048 DWORD ClassDescriptionSize,
1049 PDWORD RequiredSize,
1050 PCWSTR MachineName,
1051 PVOID Reserved)
1052 {
1053 HKEY hKey;
1054 DWORD dwLength;
1055
1056 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
1057 ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
1058
1059 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1060 KEY_QUERY_VALUE,
1061 DIOCR_INSTALLER,
1062 MachineName,
1063 Reserved);
1064 if (hKey == INVALID_HANDLE_VALUE)
1065 {
1066 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
1067 return FALSE;
1068 }
1069
1070 if (RequiredSize != NULL)
1071 {
1072 dwLength = 0;
1073 if (RegQueryValueExW(hKey,
1074 NULL,
1075 NULL,
1076 NULL,
1077 NULL,
1078 &dwLength))
1079 {
1080 RegCloseKey(hKey);
1081 return FALSE;
1082 }
1083
1084 *RequiredSize = dwLength / sizeof(WCHAR);
1085 }
1086
1087 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1088 if (RegQueryValueExW(hKey,
1089 NULL,
1090 NULL,
1091 NULL,
1092 (LPBYTE)ClassDescription,
1093 &dwLength))
1094 {
1095 RegCloseKey(hKey);
1096 return FALSE;
1097 }
1098
1099 RegCloseKey(hKey);
1100
1101 return TRUE;
1102 }
1103
1104 /***********************************************************************
1105 * SetupDiGetClassDevsA (SETUPAPI.@)
1106 */
1107 HDEVINFO WINAPI SetupDiGetClassDevsA(
1108 CONST GUID *class,
1109 LPCSTR enumstr,
1110 HWND parent,
1111 DWORD flags)
1112 {
1113 return SetupDiGetClassDevsExA(class, enumstr, parent,
1114 flags, NULL, NULL, NULL);
1115 }
1116
1117 /***********************************************************************
1118 * SetupDiGetClassDevsW (SETUPAPI.@)
1119 */
1120 HDEVINFO WINAPI SetupDiGetClassDevsW(
1121 CONST GUID *class,
1122 LPCWSTR enumstr,
1123 HWND parent,
1124 DWORD flags)
1125 {
1126 return SetupDiGetClassDevsExW(class, enumstr, parent,
1127 flags, NULL, NULL, NULL);
1128 }
1129
1130 /***********************************************************************
1131 * SetupDiGetClassDevsExA (SETUPAPI.@)
1132 */
1133 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1134 CONST GUID *class,
1135 LPCSTR enumstr,
1136 HWND parent,
1137 DWORD flags,
1138 HDEVINFO deviceset,
1139 LPCSTR machine,
1140 PVOID reserved)
1141 {
1142 HDEVINFO ret;
1143 LPWSTR enumstrW = NULL;
1144 LPWSTR machineW = NULL;
1145
1146 if (enumstr)
1147 {
1148 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1149 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1150 if (!enumstrW)
1151 {
1152 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1153 goto end;
1154 }
1155 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1156 }
1157 if (machine)
1158 {
1159 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1160 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1161 if (!machineW)
1162 {
1163 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1164 goto end;
1165 }
1166 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1167 }
1168 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
1169
1170 end:
1171 HeapFree(GetProcessHeap(), 0, enumstrW);
1172 HeapFree(GetProcessHeap(), 0, machineW);
1173 return ret;
1174 }
1175
1176 static BOOL
1177 CreateDeviceInfoElement(
1178 IN struct DeviceInfoSet *list,
1179 IN LPCWSTR InstancePath,
1180 IN LPCGUID pClassGuid,
1181 OUT struct DeviceInfoElement **pDeviceInfo)
1182 {
1183 DWORD size;
1184 CONFIGRET cr;
1185 struct DeviceInfoElement *deviceInfo;
1186
1187 *pDeviceInfo = NULL;
1188
1189 size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (wcslen(InstancePath) + 1) * sizeof(WCHAR);
1190 deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
1191 if (!deviceInfo)
1192 {
1193 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1194 return FALSE;
1195 }
1196 memset(deviceInfo, 0, size);
1197
1198 cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
1199 if (cr != CR_SUCCESS)
1200 {
1201 SetLastError(GetErrorCodeFromCrCode(cr));
1202 return FALSE;
1203 }
1204
1205 deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1206 wcscpy(deviceInfo->Data, InstancePath);
1207 deviceInfo->DeviceName = deviceInfo->Data;
1208 deviceInfo->UniqueId = wcsrchr(deviceInfo->Data, '\\');
1209 deviceInfo->DeviceDescription = NULL;
1210 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
1211 deviceInfo->CreationFlags = 0;
1212 InitializeListHead(&deviceInfo->DriverListHead);
1213 InitializeListHead(&deviceInfo->InterfaceListHead);
1214
1215 *pDeviceInfo = deviceInfo;
1216 return TRUE;
1217 }
1218
1219 static BOOL
1220 CreateDeviceInterface(
1221 IN struct DeviceInfoElement* deviceInfo,
1222 IN LPCWSTR SymbolicLink,
1223 IN LPCGUID pInterfaceGuid,
1224 OUT struct DeviceInterface **pDeviceInterface)
1225 {
1226 struct DeviceInterface *deviceInterface;
1227
1228 *pDeviceInterface = NULL;
1229
1230 deviceInterface = HeapAlloc(GetProcessHeap(), 0,
1231 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (wcslen(SymbolicLink) + 1) * sizeof(WCHAR));
1232 if (!deviceInterface)
1233 {
1234 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1235 return FALSE;
1236 }
1237 deviceInterface->DeviceInfo = deviceInfo;
1238 wcscpy(deviceInterface->SymbolicLink, SymbolicLink);
1239 deviceInterface->Flags = 0; /* FIXME */
1240 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
1241
1242 *pDeviceInterface = deviceInterface;
1243 return TRUE;
1244 }
1245
1246 static LONG SETUP_CreateDevListFromEnumerator(
1247 struct DeviceInfoSet *list,
1248 LPCGUID pClassGuid OPTIONAL,
1249 LPCWSTR Enumerator,
1250 HKEY hEnumeratorKey) /* handle to Enumerator registry key */
1251 {
1252 HKEY hDeviceIdKey, hInstanceIdKey;
1253 WCHAR KeyBuffer[MAX_PATH];
1254 WCHAR InstancePath[MAX_PATH];
1255 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
1256 struct DeviceInfoElement *deviceInfo;
1257 DWORD i = 0, j;
1258 DWORD dwLength, dwRegType;
1259 DWORD rc;
1260
1261 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
1262 while (TRUE)
1263 {
1264 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1265 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1266 if (rc == ERROR_NO_MORE_ITEMS)
1267 break;
1268 if (rc != ERROR_SUCCESS)
1269 return rc;
1270 i++;
1271
1272 /* Open device id sub key */
1273 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
1274 if (rc != ERROR_SUCCESS)
1275 return rc;
1276 wcscpy(InstancePath, Enumerator);
1277 wcscat(InstancePath, L"\\");
1278 wcscat(InstancePath, KeyBuffer);
1279 wcscat(InstancePath, L"\\");
1280 pEndOfInstancePath = &InstancePath[wcslen(InstancePath)];
1281
1282 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
1283 j = 0;
1284 while (TRUE)
1285 {
1286 GUID KeyGuid;
1287
1288 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1289 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1290 if (rc == ERROR_NO_MORE_ITEMS)
1291 break;
1292 if (rc != ERROR_SUCCESS)
1293 {
1294 RegCloseKey(hDeviceIdKey);
1295 return rc;
1296 }
1297 j++;
1298
1299 /* Open instance id sub key */
1300 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1301 if (rc != ERROR_SUCCESS)
1302 {
1303 RegCloseKey(hDeviceIdKey);
1304 return rc;
1305 }
1306 *pEndOfInstancePath = '\0';
1307 wcscat(InstancePath, KeyBuffer);
1308
1309 /* Read ClassGUID value */
1310 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1311 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1312 RegCloseKey(hInstanceIdKey);
1313 if (rc == ERROR_FILE_NOT_FOUND)
1314 {
1315 if (pClassGuid)
1316 /* Skip this bad entry as we can't verify it */
1317 continue;
1318 /* Set a default GUID for this device */
1319 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
1320 }
1321 else if (rc != ERROR_SUCCESS)
1322 {
1323 RegCloseKey(hDeviceIdKey);
1324 return rc;
1325 }
1326 else if (dwRegType != REG_SZ)
1327 {
1328 RegCloseKey(hDeviceIdKey);
1329 return ERROR_GEN_FAILURE;
1330 }
1331 else
1332 {
1333 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1334 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1335 /* Bad GUID, skip the entry */
1336 continue;
1337 }
1338
1339 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
1340 {
1341 /* Skip this entry as it is not the right device class */
1342 continue;
1343 }
1344
1345 /* Add the entry to the list */
1346 if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
1347 {
1348 RegCloseKey(hDeviceIdKey);
1349 return GetLastError();
1350 }
1351 TRACE("Adding '%S' to device info set %p\n", InstancePath, list);
1352 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1353 }
1354 RegCloseKey(hDeviceIdKey);
1355 }
1356
1357 return ERROR_SUCCESS;
1358 }
1359
1360 static LONG SETUP_CreateDevList(
1361 struct DeviceInfoSet *list,
1362 PCWSTR MachineName OPTIONAL,
1363 LPGUID class OPTIONAL,
1364 PCWSTR Enumerator OPTIONAL)
1365 {
1366 HKEY HKLM, hEnumKey, hEnumeratorKey;
1367 WCHAR KeyBuffer[MAX_PATH];
1368 DWORD i;
1369 DWORD dwLength;
1370 DWORD rc;
1371
1372 if (class && IsEqualIID(class, &GUID_NULL))
1373 class = NULL;
1374
1375 /* Open Enum key */
1376 if (MachineName != NULL)
1377 {
1378 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1379 if (rc != ERROR_SUCCESS)
1380 return rc;
1381 }
1382 else
1383 HKLM = HKEY_LOCAL_MACHINE;
1384
1385 rc = RegOpenKeyExW(HKLM,
1386 REGSTR_PATH_SYSTEMENUM,
1387 0,
1388 KEY_ENUMERATE_SUB_KEYS,
1389 &hEnumKey);
1390 if (MachineName != NULL) RegCloseKey(HKLM);
1391 if (rc != ERROR_SUCCESS)
1392 return rc;
1393
1394 /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
1395 * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
1396 * for each one.
1397 */
1398 if (Enumerator)
1399 {
1400 rc = RegOpenKeyExW(
1401 hEnumKey,
1402 Enumerator,
1403 0,
1404 KEY_ENUMERATE_SUB_KEYS,
1405 &hEnumeratorKey);
1406 RegCloseKey(hEnumKey);
1407 if (rc != ERROR_SUCCESS)
1408 return rc;
1409 rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
1410 RegCloseKey(hEnumeratorKey);
1411 return rc;
1412 }
1413 else
1414 {
1415 /* Enumerate enumerators */
1416 i = 0;
1417 while (TRUE)
1418 {
1419 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1420 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1421 if (rc == ERROR_NO_MORE_ITEMS)
1422 break;
1423 if (rc != ERROR_SUCCESS)
1424 {
1425 RegCloseKey(hEnumKey);
1426 return rc;
1427 }
1428 i++;
1429
1430 /* Open sub key */
1431 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1432 if (rc != ERROR_SUCCESS)
1433 {
1434 RegCloseKey(hEnumKey);
1435 return rc;
1436 }
1437
1438 /* Call SETUP_CreateDevListFromEnumerator */
1439 rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
1440 RegCloseKey(hEnumeratorKey);
1441 if (rc != ERROR_SUCCESS)
1442 {
1443 RegCloseKey(hEnumKey);
1444 return rc;
1445 }
1446 }
1447 RegCloseKey(hEnumKey);
1448 return ERROR_SUCCESS;
1449 }
1450 }
1451
1452 #ifndef __REACTOS__
1453 static LONG SETUP_CreateSerialDeviceList(
1454 struct DeviceInfoSet *list,
1455 PCWSTR MachineName,
1456 LPGUID InterfaceGuid,
1457 PCWSTR DeviceInstanceW)
1458 {
1459 static const size_t initialSize = 100;
1460 size_t size;
1461 WCHAR buf[initialSize];
1462 LPWSTR devices;
1463 static const WCHAR devicePrefixW[] = { 'C','O','M',0 };
1464 LPWSTR ptr;
1465 struct DeviceInfoElement *deviceInfo;
1466
1467 if (MachineName)
1468 WARN("'MachineName' is ignored on Wine!\n");
1469 if (DeviceInstanceW)
1470 WARN("'DeviceInstanceW' can't be set on Wine!\n");
1471
1472 devices = buf;
1473 size = initialSize;
1474 while (TRUE)
1475 {
1476 if (QueryDosDeviceW(NULL, devices, size) != 0)
1477 break;
1478 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1479 {
1480 size *= 2;
1481 if (devices != buf)
1482 HeapFree(GetProcessHeap(), 0, devices);
1483 devices = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
1484 if (!devices)
1485 return ERROR_NOT_ENOUGH_MEMORY;
1486 *devices = '\0';
1487 }
1488 else
1489 {
1490 if (devices != buf)
1491 HeapFree(GetProcessHeap(), 0, devices);
1492 return GetLastError();
1493 }
1494 }
1495
1496 /* 'devices' is a MULTI_SZ string */
1497 for (ptr = devices; *ptr; ptr += strlenW(ptr) + 1)
1498 {
1499 if (strncmpW(devicePrefixW, ptr, sizeof(devicePrefixW) / sizeof(devicePrefixW[0]) - 1) == 0)
1500 {
1501 /* We have found a device */
1502 struct DeviceInterface *interfaceInfo;
1503 TRACE("Adding %s to list\n", debugstr_w(ptr));
1504 /* Step 1. Create a device info element */
1505 if (!CreateDeviceInfoElement(list, ptr, &GUID_SERENUM_BUS_ENUMERATOR, &deviceInfo))
1506 {
1507 if (devices != buf)
1508 HeapFree(GetProcessHeap(), 0, devices);
1509 return GetLastError();
1510 }
1511 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1512
1513 /* Step 2. Create an interface list for this element */
1514 if (!CreateDeviceInterface(deviceInfo, ptr, InterfaceGuid, &interfaceInfo))
1515 {
1516 if (devices != buf)
1517 HeapFree(GetProcessHeap(), 0, devices);
1518 return GetLastError();
1519 }
1520 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1521 }
1522 }
1523 if (devices != buf)
1524 HeapFree(GetProcessHeap(), 0, devices);
1525 return ERROR_SUCCESS;
1526 }
1527
1528 #else /* __REACTOS__ */
1529
1530 static LONG SETUP_CreateInterfaceList(
1531 struct DeviceInfoSet *list,
1532 PCWSTR MachineName,
1533 LPGUID InterfaceGuid,
1534 PCWSTR DeviceInstanceW /* OPTIONAL */)
1535 {
1536 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1537 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1538 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1539 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1540 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1541 LONG rc;
1542 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
1543 PWSTR InstancePath;
1544 DWORD i, j;
1545 DWORD dwLength, dwInstancePathLength;
1546 DWORD dwRegType;
1547 GUID ClassGuid;
1548 struct DeviceInfoElement *deviceInfo;
1549
1550 /* Open registry key related to this interface */
1551 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
1552 if (hInterfaceKey == INVALID_HANDLE_VALUE)
1553 return GetLastError();
1554
1555 /* Enumerate sub keys of hInterfaceKey */
1556 i = 0;
1557 while (TRUE)
1558 {
1559 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1560 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1561 if (rc == ERROR_NO_MORE_ITEMS)
1562 break;
1563 if (rc != ERROR_SUCCESS)
1564 {
1565 RegCloseKey(hInterfaceKey);
1566 return rc;
1567 }
1568 i++;
1569
1570 /* Open sub key */
1571 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
1572 if (rc != ERROR_SUCCESS)
1573 {
1574 RegCloseKey(hInterfaceKey);
1575 return rc;
1576 }
1577
1578 /* Read DeviceInstance */
1579 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
1580 if (rc != ERROR_SUCCESS )
1581 {
1582 RegCloseKey(hDeviceInstanceKey);
1583 RegCloseKey(hInterfaceKey);
1584 return rc;
1585 }
1586 if (dwRegType != REG_SZ)
1587 {
1588 RegCloseKey(hDeviceInstanceKey);
1589 RegCloseKey(hInterfaceKey);
1590 return ERROR_GEN_FAILURE;
1591 }
1592 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1593 if (!InstancePath)
1594 {
1595 RegCloseKey(hDeviceInstanceKey);
1596 RegCloseKey(hInterfaceKey);
1597 return ERROR_NOT_ENOUGH_MEMORY;
1598 }
1599 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1600 if (rc != ERROR_SUCCESS)
1601 {
1602 HeapFree(GetProcessHeap(), 0, InstancePath);
1603 RegCloseKey(hDeviceInstanceKey);
1604 RegCloseKey(hInterfaceKey);
1605 return rc;
1606 }
1607 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1608 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1609
1610 if (DeviceInstanceW)
1611 {
1612 /* Check if device enumerator is not the right one */
1613 if (wcscmp(DeviceInstanceW, InstancePath) != 0)
1614 {
1615 HeapFree(GetProcessHeap(), 0, InstancePath);
1616 RegCloseKey(hDeviceInstanceKey);
1617 continue;
1618 }
1619 }
1620
1621 /* Find class GUID associated to the device instance */
1622 rc = RegOpenKeyExW(
1623 list->HKLM,
1624 REGSTR_PATH_SYSTEMENUM,
1625 0, /* Options */
1626 0,
1627 &hEnumKey);
1628 if (rc != ERROR_SUCCESS)
1629 {
1630 HeapFree(GetProcessHeap(), 0, InstancePath);
1631 RegCloseKey(hDeviceInstanceKey);
1632 RegCloseKey(hInterfaceKey);
1633 return rc;
1634 }
1635 rc = RegOpenKeyExW(
1636 hEnumKey,
1637 InstancePath,
1638 0, /* Options */
1639 KEY_QUERY_VALUE,
1640 &hKey);
1641 RegCloseKey(hEnumKey);
1642 if (rc != ERROR_SUCCESS)
1643 {
1644 HeapFree(GetProcessHeap(), 0, InstancePath);
1645 RegCloseKey(hDeviceInstanceKey);
1646 RegCloseKey(hInterfaceKey);
1647 return rc;
1648 }
1649 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1650 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1651 RegCloseKey(hKey);
1652 if (rc != ERROR_SUCCESS)
1653 {
1654 HeapFree(GetProcessHeap(), 0, InstancePath);
1655 RegCloseKey(hDeviceInstanceKey);
1656 RegCloseKey(hInterfaceKey);
1657 return rc;
1658 }
1659 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1660 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1661 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1662 {
1663 HeapFree(GetProcessHeap(), 0, InstancePath);
1664 RegCloseKey(hDeviceInstanceKey);
1665 RegCloseKey(hInterfaceKey);
1666 return ERROR_GEN_FAILURE;
1667 }
1668 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1669
1670 /* If current device doesn't match the list GUID (if any), skip this entry */
1671 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1672 {
1673 HeapFree(GetProcessHeap(), 0, InstancePath);
1674 RegCloseKey(hDeviceInstanceKey);
1675 continue;
1676 }
1677
1678 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1679 j = 0;
1680 while (TRUE)
1681 {
1682 LPWSTR pSymbolicLink;
1683 struct DeviceInterface *interfaceInfo;
1684
1685 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1686 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1687 if (rc == ERROR_NO_MORE_ITEMS)
1688 break;
1689 if (rc != ERROR_SUCCESS)
1690 {
1691 HeapFree(GetProcessHeap(), 0, InstancePath);
1692 RegCloseKey(hDeviceInstanceKey);
1693 RegCloseKey(hInterfaceKey);
1694 return rc;
1695 }
1696 j++;
1697 if (KeyBuffer[0] != '#')
1698 /* This entry doesn't represent an interesting entry */
1699 continue;
1700
1701 /* Open sub key */
1702 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1703 if (rc != ERROR_SUCCESS)
1704 {
1705 RegCloseKey(hDeviceInstanceKey);
1706 RegCloseKey(hInterfaceKey);
1707 return rc;
1708 }
1709
1710 /* Read SymbolicLink value */
1711 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1712 if (rc != ERROR_SUCCESS )
1713 {
1714 RegCloseKey(hReferenceKey);
1715 RegCloseKey(hDeviceInstanceKey);
1716 RegCloseKey(hInterfaceKey);
1717 return rc;
1718 }
1719 if (dwRegType != REG_SZ)
1720 {
1721 RegCloseKey(hReferenceKey);
1722 RegCloseKey(hDeviceInstanceKey);
1723 RegCloseKey(hInterfaceKey);
1724 return ERROR_GEN_FAILURE;
1725 }
1726
1727 /* We have found a device */
1728 /* Step 1. Create a device info element */
1729 if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
1730 {
1731 RegCloseKey(hReferenceKey);
1732 RegCloseKey(hDeviceInstanceKey);
1733 RegCloseKey(hInterfaceKey);
1734 return GetLastError();
1735 }
1736 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1737 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1738
1739 /* Step 2. Create an interface list for this element */
1740 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1741 if (!pSymbolicLink)
1742 {
1743 RegCloseKey(hReferenceKey);
1744 RegCloseKey(hDeviceInstanceKey);
1745 RegCloseKey(hInterfaceKey);
1746 return ERROR_NOT_ENOUGH_MEMORY;
1747 }
1748 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1749 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1750 RegCloseKey(hReferenceKey);
1751 if (rc != ERROR_SUCCESS)
1752 {
1753 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1754 RegCloseKey(hDeviceInstanceKey);
1755 RegCloseKey(hInterfaceKey);
1756 return rc;
1757 }
1758 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1759 {
1760 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1761 RegCloseKey(hDeviceInstanceKey);
1762 RegCloseKey(hInterfaceKey);
1763 return GetLastError();
1764 }
1765 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1766 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1767 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1768 }
1769 RegCloseKey(hDeviceInstanceKey);
1770 }
1771 RegCloseKey(hInterfaceKey);
1772 return ERROR_SUCCESS;
1773 }
1774 #endif /* __REACTOS__ */
1775
1776 /***********************************************************************
1777 * SetupDiGetClassDevsExW (SETUPAPI.@)
1778 */
1779 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1780 CONST GUID *class,
1781 LPCWSTR enumstr,
1782 HWND parent,
1783 DWORD flags,
1784 HDEVINFO deviceset,
1785 LPCWSTR machine,
1786 PVOID reserved)
1787 {
1788 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1789 struct DeviceInfoSet *list;
1790 LPGUID pClassGuid;
1791 LONG rc;
1792
1793 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
1794 parent, flags, deviceset, debugstr_w(machine), reserved);
1795
1796 /* Create the deviceset if not set */
1797 if (deviceset)
1798 {
1799 list = (struct DeviceInfoSet *)deviceset;
1800 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1801 {
1802 SetLastError(ERROR_INVALID_HANDLE);
1803 return INVALID_HANDLE_VALUE;
1804 }
1805 hDeviceInfo = deviceset;
1806 }
1807 else
1808 {
1809 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1810 flags & DIGCF_DEVICEINTERFACE ? NULL : class,
1811 NULL, machine, NULL);
1812 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1813 return INVALID_HANDLE_VALUE;
1814 list = (struct DeviceInfoSet *)hDeviceInfo;
1815 }
1816
1817 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1818 pClassGuid = NULL;
1819 else
1820 pClassGuid = &list->ClassGuid;
1821
1822 if (flags & DIGCF_PRESENT)
1823 FIXME(": flag DIGCF_PRESENT ignored\n");
1824 if (flags & DIGCF_PROFILE)
1825 FIXME(": flag DIGCF_PROFILE ignored\n");
1826
1827 if (flags & DIGCF_ALLCLASSES)
1828 {
1829 rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
1830 if (rc != ERROR_SUCCESS)
1831 {
1832 SetLastError(rc);
1833 if (!deviceset)
1834 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1835 return INVALID_HANDLE_VALUE;
1836 }
1837 return hDeviceInfo;
1838 }
1839 else if (flags & DIGCF_DEVICEINTERFACE)
1840 {
1841 if (class == NULL)
1842 {
1843 SetLastError(ERROR_INVALID_PARAMETER);
1844 if (!deviceset)
1845 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1846 return INVALID_HANDLE_VALUE;
1847 }
1848
1849 #ifndef __REACTOS__
1850 /* Special case: find serial ports by calling QueryDosDevice */
1851 if (IsEqualIID(class, &GUID_DEVINTERFACE_COMPORT))
1852 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1853 if (IsEqualIID(class, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR))
1854 rc = SETUP_CreateSerialDeviceList(list, machine, (LPGUID)class, enumstr);
1855 else
1856 {
1857 ERR("Wine can only enumerate serial devices at the moment!\n");
1858 rc = ERROR_INVALID_PARAMETER;
1859 }
1860 #else /* __REACTOS__ */
1861 rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
1862 #endif /* __REACTOS__ */
1863 if (rc != ERROR_SUCCESS)
1864 {
1865 SetLastError(rc);
1866 if (!deviceset)
1867 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1868 return INVALID_HANDLE_VALUE;
1869 }
1870 return hDeviceInfo;
1871 }
1872 else
1873 {
1874 rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
1875 if (rc != ERROR_SUCCESS)
1876 {
1877 SetLastError(rc);
1878 if (!deviceset)
1879 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1880 return INVALID_HANDLE_VALUE;
1881 }
1882 return hDeviceInfo;
1883 }
1884 }
1885
1886 /***********************************************************************
1887 * SetupDiGetClassImageIndex (SETUPAPI.@)
1888 */
1889
1890 static BOOL GetIconIndex(
1891 IN HKEY hClassKey,
1892 OUT PINT ImageIndex)
1893 {
1894 LPWSTR Buffer = NULL;
1895 DWORD dwRegType, dwLength;
1896 LONG rc;
1897 BOOL ret = FALSE;
1898
1899 /* Read icon registry key */
1900 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
1901 if (rc != ERROR_SUCCESS)
1902 {
1903 SetLastError(rc);
1904 goto cleanup;
1905 } else if (dwRegType != REG_SZ)
1906 {
1907 SetLastError(ERROR_INVALID_INDEX);
1908 goto cleanup;
1909 }
1910 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
1911 if (!Buffer)
1912 {
1913 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1914 goto cleanup;
1915 }
1916 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
1917 if (rc != ERROR_SUCCESS)
1918 {
1919 SetLastError(rc);
1920 goto cleanup;
1921 }
1922 /* make sure the returned buffer is NULL-terminated */
1923 Buffer[dwLength / sizeof(WCHAR)] = 0;
1924
1925 /* Transform icon value to a INT */
1926 *ImageIndex = atoiW(Buffer);
1927 ret = TRUE;
1928
1929 cleanup:
1930 MyFree(Buffer);
1931 return ret;
1932 }
1933
1934 BOOL WINAPI SetupDiGetClassImageIndex(
1935 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
1936 IN CONST GUID *ClassGuid,
1937 OUT PINT ImageIndex)
1938 {
1939 struct ClassImageList *list;
1940 BOOL ret = FALSE;
1941
1942 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
1943
1944 if (!ClassImageListData || !ClassGuid || !ImageIndex)
1945 SetLastError(ERROR_INVALID_PARAMETER);
1946 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
1947 SetLastError(ERROR_INVALID_USER_BUFFER);
1948 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
1949 SetLastError(ERROR_INVALID_USER_BUFFER);
1950 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
1951 SetLastError(ERROR_INVALID_USER_BUFFER);
1952 else if (!ImageIndex)
1953 SetLastError(ERROR_INVALID_PARAMETER);
1954 else
1955 {
1956 HKEY hKey = INVALID_HANDLE_VALUE;
1957 INT iconIndex;
1958
1959 /* Read Icon registry entry into Buffer */
1960 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL);
1961 if (hKey == INVALID_HANDLE_VALUE)
1962 goto cleanup;
1963 if (!GetIconIndex(hKey, &iconIndex))
1964 goto cleanup;
1965
1966 if (iconIndex >= 0)
1967 {
1968 SetLastError(ERROR_INVALID_INDEX);
1969 goto cleanup;
1970 }
1971
1972 *ImageIndex = -iconIndex;
1973 ret = TRUE;
1974
1975 cleanup:
1976 if (hKey != INVALID_HANDLE_VALUE)
1977 RegCloseKey(hKey);
1978 }
1979
1980 TRACE("Returning %d\n", ret);
1981 return ret;
1982 }
1983
1984 /***********************************************************************
1985 * SetupDiGetClassImageList(SETUPAPI.@)
1986 */
1987 BOOL WINAPI SetupDiGetClassImageList(
1988 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
1989 {
1990 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
1991 }
1992
1993 /***********************************************************************
1994 * SetupDiGetClassImageListExA(SETUPAPI.@)
1995 */
1996 BOOL WINAPI SetupDiGetClassImageListExA(
1997 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
1998 IN PCSTR MachineName OPTIONAL,
1999 IN PVOID Reserved)
2000 {
2001 PWSTR MachineNameW = NULL;
2002 BOOL ret;
2003
2004 if (MachineName)
2005 {
2006 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2007 if (MachineNameW == NULL)
2008 return FALSE;
2009 }
2010
2011 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
2012
2013 if (MachineNameW)
2014 MyFree(MachineNameW);
2015
2016 return ret;
2017 }
2018
2019 /***********************************************************************
2020 * SetupDiGetClassImageListExW(SETUPAPI.@)
2021 */
2022 BOOL WINAPI SetupDiGetClassImageListExW(
2023 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2024 IN PCWSTR MachineName OPTIONAL,
2025 IN PVOID Reserved)
2026 {
2027 BOOL ret = FALSE;
2028
2029 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
2030
2031 if (!ClassImageListData)
2032 SetLastError(ERROR_INVALID_PARAMETER);
2033 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2034 SetLastError(ERROR_INVALID_USER_BUFFER);
2035 else if (Reserved)
2036 SetLastError(ERROR_INVALID_PARAMETER);
2037 else
2038 {
2039 struct ClassImageList *list = NULL;
2040 DWORD size;
2041
2042 size = FIELD_OFFSET(struct ClassImageList, szData);
2043 if (MachineName)
2044 size += (wcslen(MachineName) + 3) * sizeof(WCHAR);
2045 list = HeapAlloc(GetProcessHeap(), 0, size);
2046 if (!list)
2047 {
2048 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2049 goto cleanup;
2050 }
2051 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
2052 if (MachineName)
2053 {
2054 list->szData[0] = list->szData[1] = '\\';
2055 strcpyW(list->szData + 2, MachineName);
2056 list->MachineName = list->szData;
2057 }
2058 else
2059 {
2060 list->MachineName = NULL;
2061 }
2062
2063 ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */
2064 ret = TRUE;
2065
2066 cleanup:
2067 if (!ret)
2068 MyFree(list);
2069 }
2070
2071 TRACE("Returning %d\n", ret);
2072 return ret;
2073 }
2074
2075 /***********************************************************************
2076 * SetupDiLoadClassIcon(SETUPAPI.@)
2077 */
2078 BOOL WINAPI SetupDiLoadClassIcon(
2079 IN CONST GUID *ClassGuid,
2080 OUT HICON *LargeIcon OPTIONAL,
2081 OUT PINT MiniIconIndex OPTIONAL)
2082 {
2083 BOOL ret = FALSE;
2084
2085 if (!ClassGuid)
2086 SetLastError(ERROR_INVALID_PARAMETER);
2087 else
2088 {
2089 LPWSTR Buffer = NULL;
2090 LPCWSTR DllName;
2091 INT iconIndex;
2092 HKEY hKey = INVALID_HANDLE_VALUE;
2093
2094 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
2095 if (hKey == INVALID_HANDLE_VALUE)
2096 goto cleanup;
2097
2098 if (!GetIconIndex(hKey, &iconIndex))
2099 goto cleanup;
2100
2101 if (iconIndex > 0)
2102 {
2103 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
2104 PWCHAR Comma;
2105 LONG rc;
2106 DWORD dwRegType, dwLength;
2107 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
2108 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2109 {
2110 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2111 if (Buffer == NULL)
2112 {
2113 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2114 goto cleanup;
2115 }
2116 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2117 if (rc != ERROR_SUCCESS)
2118 {
2119 SetLastError(rc);
2120 goto cleanup;
2121 }
2122 /* make sure the returned buffer is NULL-terminated */
2123 Buffer[dwLength / sizeof(WCHAR)] = 0;
2124 }
2125 else if
2126 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
2127 && dwRegType == REG_SZ)
2128 {
2129 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2130 if (Buffer == NULL)
2131 {
2132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2133 goto cleanup;
2134 }
2135 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2136 if (rc != ERROR_SUCCESS)
2137 {
2138 SetLastError(rc);
2139 goto cleanup;
2140 }
2141 /* make sure the returned buffer is NULL-terminated */
2142 Buffer[dwLength / sizeof(WCHAR)] = 0;
2143 }
2144 else
2145 {
2146 /* Unable to find where to load the icon */
2147 SetLastError(ERROR_FILE_NOT_FOUND);
2148 goto cleanup;
2149 }
2150 Comma = strchrW(Buffer, ',');
2151 if (!Comma)
2152 {
2153 SetLastError(ERROR_GEN_FAILURE);
2154 goto cleanup;
2155 }
2156 *Comma = '\0';
2157 DllName = Buffer;
2158 }
2159 else
2160 {
2161 /* Look up icon in setupapi.dll */
2162 DllName = L"setupapi.dll";
2163 iconIndex = -iconIndex;
2164 }
2165
2166 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
2167 if (LargeIcon)
2168 {
2169 if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
2170 {
2171 SetLastError(ERROR_INVALID_INDEX);
2172 goto cleanup;
2173 }
2174 }
2175 if (MiniIconIndex)
2176 *MiniIconIndex = iconIndex;
2177 ret = TRUE;
2178
2179 cleanup:
2180 if (hKey != INVALID_HANDLE_VALUE)
2181 RegCloseKey(hKey);
2182 MyFree(Buffer);
2183 }
2184
2185 TRACE("Returning %d\n", ret);
2186 return ret;
2187 }
2188
2189 /***********************************************************************
2190 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2191 */
2192 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2193 HDEVINFO DeviceInfoSet,
2194 PSP_DEVINFO_DATA DeviceInfoData,
2195 CONST GUID * InterfaceClassGuid,
2196 DWORD MemberIndex,
2197 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2198 {
2199 BOOL ret = FALSE;
2200
2201 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
2202 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2203
2204 if (!DeviceInterfaceData)
2205 SetLastError(ERROR_INVALID_PARAMETER);
2206 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2207 SetLastError(ERROR_INVALID_USER_BUFFER);
2208 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
2209 {
2210 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2211
2212 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2213 {
2214 PLIST_ENTRY ItemList = list->ListHead.Flink;
2215 BOOL Found = FALSE;
2216 while (ItemList != &list->ListHead && !Found)
2217 {
2218 PLIST_ENTRY InterfaceListEntry;
2219 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
2220 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
2221 {
2222 /* We are not searching for this element */
2223 ItemList = ItemList->Flink;
2224 continue;
2225 }
2226 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
2227 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
2228 {
2229 struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
2230 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2231 {
2232 InterfaceListEntry = InterfaceListEntry->Flink;
2233 continue;
2234 }
2235 if (MemberIndex-- == 0)
2236 {
2237 /* return this item */
2238 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2239 &DevItf->InterfaceClassGuid,
2240 sizeof(GUID));
2241 DeviceInterfaceData->Flags = 0; /* FIXME */
2242 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2243 Found = TRUE;
2244 }
2245 InterfaceListEntry = InterfaceListEntry->Flink;
2246 }
2247 ItemList = ItemList->Flink;
2248 }
2249 if (!Found)
2250 SetLastError(ERROR_NO_MORE_ITEMS);
2251 else
2252 ret = TRUE;
2253 }
2254 else
2255 SetLastError(ERROR_INVALID_HANDLE);
2256 }
2257 else
2258 SetLastError(ERROR_INVALID_HANDLE);
2259 return ret;
2260 }
2261
2262 static VOID ReferenceInfFile(struct InfFileDetails* infFile)
2263 {
2264 InterlockedIncrement(&infFile->References);
2265 }
2266
2267 static VOID DereferenceInfFile(struct InfFileDetails* infFile)
2268 {
2269 if (InterlockedDecrement(&infFile->References) == 0)
2270 {
2271 SetupCloseInfFile(infFile->hInf);
2272 HeapFree(GetProcessHeap(), 0, infFile);
2273 }
2274 }
2275
2276 static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
2277 {
2278 DereferenceInfFile(driverInfo->InfFileDetails);
2279 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
2280 HeapFree(GetProcessHeap(), 0, driverInfo);
2281 return TRUE;
2282 }
2283
2284 static BOOL DestroyClassInstallParams(struct ClassInstallParams* installParams)
2285 {
2286 HeapFree(GetProcessHeap(), 0, installParams->PropChange);
2287 return TRUE;
2288 }
2289
2290 static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
2291 {
2292 PLIST_ENTRY ListEntry;
2293 struct DriverInfoElement *driverInfo;
2294
2295 while (!IsListEmpty(&deviceInfo->DriverListHead))
2296 {
2297 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
2298 driverInfo = (struct DriverInfoElement *)ListEntry;
2299 if (!DestroyDriverInfoElement(driverInfo))
2300 return FALSE;
2301 }
2302 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
2303 {
2304 ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
2305 HeapFree(GetProcessHeap(), 0, ListEntry);
2306 }
2307 DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
2308 HeapFree(GetProcessHeap(), 0, deviceInfo);
2309 return TRUE;
2310 }
2311
2312 static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
2313 {
2314 PLIST_ENTRY ListEntry;
2315 struct DeviceInfoElement *deviceInfo;
2316
2317 while (!IsListEmpty(&list->ListHead))
2318 {
2319 ListEntry = RemoveHeadList(&list->ListHead);
2320 deviceInfo = (struct DeviceInfoElement *)ListEntry;
2321 if (!DestroyDeviceInfoElement(deviceInfo))
2322 return FALSE;
2323 }
2324 if (list->HKLM != HKEY_LOCAL_MACHINE)
2325 RegCloseKey(list->HKLM);
2326 CM_Disconnect_Machine(list->hMachine);
2327 DestroyClassInstallParams(&list->ClassInstallParams);
2328 HeapFree(GetProcessHeap(), 0, list);
2329 return TRUE;
2330 }
2331
2332 /***********************************************************************
2333 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2334 */
2335 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2336 {
2337 BOOL ret = FALSE;
2338
2339 TRACE("%p\n", devinfo);
2340 if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
2341 {
2342 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2343
2344 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2345 ret = DestroyDeviceInfoSet(list);
2346 else
2347 SetLastError(ERROR_INVALID_HANDLE);
2348 }
2349 else
2350 SetLastError(ERROR_INVALID_HANDLE);
2351
2352 TRACE("Returning %d\n", ret);
2353 return ret;
2354 }
2355
2356 /***********************************************************************
2357 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2358 */
2359 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2360 HDEVINFO DeviceInfoSet,
2361 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2362 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2363 DWORD DeviceInterfaceDetailDataSize,
2364 PDWORD RequiredSize,
2365 PSP_DEVINFO_DATA DeviceInfoData)
2366 {
2367 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2368 DWORD sizeW = 0, sizeA;
2369 BOOL ret = FALSE;
2370
2371 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2372 DeviceInterfaceData, DeviceInterfaceDetailData,
2373 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2374
2375 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2376 SetLastError(ERROR_INVALID_USER_BUFFER);
2377 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2378 SetLastError(ERROR_INVALID_PARAMETER);
2379 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2380 SetLastError(ERROR_INVALID_PARAMETER);
2381 else
2382 {
2383 if (DeviceInterfaceDetailData != NULL)
2384 {
2385 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2386 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2387 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2388 if (!DeviceInterfaceDetailDataW)
2389 {
2390 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2391 }
2392 }
2393 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2394 {
2395 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2396 ret = SetupDiGetDeviceInterfaceDetailW(
2397 DeviceInfoSet,
2398 DeviceInterfaceData,
2399 DeviceInterfaceDetailDataW,
2400 sizeW,
2401 &sizeW,
2402 DeviceInfoData);
2403 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2404 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2405 if (RequiredSize)
2406 *RequiredSize = sizeA;
2407 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2408 {
2409 if (!WideCharToMultiByte(
2410 CP_ACP, 0,
2411 DeviceInterfaceDetailDataW->DevicePath, -1,
2412 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2413 NULL, NULL))
2414 {
2415 ret = FALSE;
2416 }
2417 }
2418 }
2419 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2420 }
2421
2422 TRACE("Returning %d\n", ret);
2423 return ret;
2424 }
2425
2426 /***********************************************************************
2427 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2428 */
2429 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2430 HDEVINFO DeviceInfoSet,
2431 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2432 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2433 DWORD DeviceInterfaceDetailDataSize,
2434 PDWORD RequiredSize,
2435 PSP_DEVINFO_DATA DeviceInfoData)
2436 {
2437 BOOL ret = FALSE;
2438
2439 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2440 DeviceInterfaceData, DeviceInterfaceDetailData,
2441 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2442
2443 if (!DeviceInfoSet || !DeviceInterfaceData)
2444 SetLastError(ERROR_INVALID_PARAMETER);
2445 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2446 SetLastError(ERROR_INVALID_HANDLE);
2447 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2448 SetLastError(ERROR_INVALID_HANDLE);
2449 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2450 SetLastError(ERROR_INVALID_USER_BUFFER);
2451 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2452 SetLastError(ERROR_INVALID_USER_BUFFER);
2453 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2454 SetLastError(ERROR_INVALID_USER_BUFFER);
2455 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2456 SetLastError(ERROR_INVALID_PARAMETER);
2457 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2458 SetLastError(ERROR_INVALID_PARAMETER);
2459 else
2460 {
2461 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2462 LPCWSTR devName = deviceInterface->SymbolicLink;
2463 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2464 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2465
2466 if (sizeRequired > DeviceInterfaceDetailDataSize)
2467 {
2468 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2469 if (RequiredSize)
2470 *RequiredSize = sizeRequired;
2471 }
2472 else
2473 {
2474 wcscpy(DeviceInterfaceDetailData->DevicePath, devName);
2475 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2476 if (DeviceInfoData)
2477 {
2478 memcpy(&DeviceInfoData->ClassGuid,
2479 &deviceInterface->DeviceInfo->ClassGuid,
2480 sizeof(GUID));
2481 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
2482 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2483 }
2484 ret = TRUE;
2485 }
2486 }
2487
2488 TRACE("Returning %d\n", ret);
2489 return ret;
2490 }
2491
2492 /***********************************************************************
2493 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2494 */
2495 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2496 HDEVINFO devinfo,
2497 PSP_DEVINFO_DATA DeviceInfoData,
2498 DWORD Property,
2499 PDWORD PropertyRegDataType,
2500 PBYTE PropertyBuffer,
2501 DWORD PropertyBufferSize,
2502 PDWORD RequiredSize)
2503 {
2504 BOOL bResult;
2505 BOOL bIsStringProperty;
2506 DWORD RegType;
2507 DWORD RequiredSizeA, RequiredSizeW;
2508 DWORD PropertyBufferSizeW;
2509 PBYTE PropertyBufferW;
2510
2511 TRACE("%p %p %ld %p %p %ld %p\n", devinfo, DeviceInfoData,
2512 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2513 RequiredSize);
2514
2515 PropertyBufferSizeW = PropertyBufferSize * 2;
2516 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2517
2518 bResult = SetupDiGetDeviceRegistryPropertyW(
2519 devinfo,
2520 DeviceInfoData,
2521 Property,
2522 &RegType,
2523 PropertyBufferW,
2524 PropertyBufferSizeW,
2525 &RequiredSizeW);
2526
2527 if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2528 {
2529 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2530
2531 if (bIsStringProperty)
2532 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2533 else
2534 RequiredSizeA = RequiredSizeW;
2535 if (RequiredSize)
2536 *RequiredSize = RequiredSizeA;
2537 if (PropertyRegDataType)
2538 *PropertyRegDataType = RegType;
2539 }
2540
2541 if (!bResult)
2542 {
2543 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2544 return bResult;
2545 }
2546
2547 if (RequiredSizeA <= PropertyBufferSize)
2548 {
2549 if (bIsStringProperty && PropertyBufferSize > 0)
2550 {
2551 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2552 {
2553 /* Last error is already set by WideCharToMultiByte */
2554 bResult = FALSE;
2555 }
2556 }
2557 else
2558 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2559 }
2560 else
2561 {
2562 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2563 bResult = FALSE;
2564 }
2565
2566 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2567 return bResult;
2568 }
2569
2570 /***********************************************************************
2571 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2572 */
2573 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2574 HDEVINFO DeviceInfoSet,
2575 PSP_DEVINFO_DATA DeviceInfoData,
2576 DWORD Property,
2577 PDWORD PropertyRegDataType,
2578 PBYTE PropertyBuffer,
2579 DWORD PropertyBufferSize,
2580 PDWORD RequiredSize)
2581 {
2582 HKEY hEnumKey, hKey;
2583 DWORD rc;
2584 BOOL ret = FALSE;
2585
2586 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2587 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2588 RequiredSize);
2589
2590 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2591 SetLastError(ERROR_INVALID_HANDLE);
2592 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2593 SetLastError(ERROR_INVALID_HANDLE);
2594 else if (!DeviceInfoData)
2595 SetLastError(ERROR_INVALID_PARAMETER);
2596 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2597 SetLastError(ERROR_INVALID_USER_BUFFER);
2598 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2599 SetLastError(ERROR_INVALID_PARAMETER);
2600 else
2601 {
2602 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2603 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2604
2605 switch (Property)
2606 {
2607 case SPDRP_CAPABILITIES:
2608 case SPDRP_CLASS:
2609 case SPDRP_CLASSGUID:
2610 case SPDRP_COMPATIBLEIDS:
2611 case SPDRP_CONFIGFLAGS:
2612 case SPDRP_DEVICEDESC:
2613 case SPDRP_DRIVER:
2614 case SPDRP_FRIENDLYNAME:
2615 case SPDRP_HARDWAREID:
2616 case SPDRP_LOCATION_INFORMATION:
2617 case SPDRP_LOWERFILTERS:
2618 case SPDRP_MFG:
2619 case SPDRP_SECURITY:
2620 case SPDRP_SERVICE:
2621 case SPDRP_UI_NUMBER:
2622 case SPDRP_UI_NUMBER_DESC_FORMAT:
2623 case SPDRP_UPPERFILTERS:
2624 {
2625 LPCWSTR RegistryPropertyName;
2626 DWORD BufferSize;
2627
2628 switch (Property)
2629 {
2630 case SPDRP_CAPABILITIES:
2631 RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
2632 case SPDRP_CLASS:
2633 RegistryPropertyName = REGSTR_VAL_CLASS; break;
2634 case SPDRP_CLASSGUID:
2635 RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
2636 case SPDRP_COMPATIBLEIDS:
2637 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
2638 case SPDRP_CONFIGFLAGS:
2639 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
2640 case SPDRP_DEVICEDESC:
2641 RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
2642 case SPDRP_DRIVER:
2643 RegistryPropertyName = REGSTR_VAL_DRIVER; break;
2644 case SPDRP_FRIENDLYNAME:
2645 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
2646 case SPDRP_HARDWAREID:
2647 RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
2648 case SPDRP_LOCATION_INFORMATION:
2649 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
2650 case SPDRP_LOWERFILTERS:
2651 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
2652 case SPDRP_MFG:
2653 RegistryPropertyName = REGSTR_VAL_MFG; break;
2654 case SPDRP_SECURITY:
2655 RegistryPropertyName = L"Security"; break;
2656 case SPDRP_SERVICE:
2657 RegistryPropertyName = REGSTR_VAL_SERVICE; break;
2658 case SPDRP_UI_NUMBER:
2659 RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
2660 case SPDRP_UI_NUMBER_DESC_FORMAT:
2661 RegistryPropertyName = L"UINumberDescFormat"; break;
2662 case SPDRP_UPPERFILTERS:
2663 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
2664 default:
2665 /* Should not happen */
2666 RegistryPropertyName = NULL; break;
2667 }
2668
2669 /* Open registry key name */
2670 rc = RegOpenKeyExW(
2671 list->HKLM,
2672 REGSTR_PATH_SYSTEMENUM,
2673 0, /* Options */
2674 0,
2675 &hEnumKey);
2676 if (rc != ERROR_SUCCESS)
2677 {
2678 SetLastError(rc);
2679 break;
2680 }
2681 rc = RegOpenKeyExW(
2682 hEnumKey,
2683 DevInfo->Data,
2684 0, /* Options */
2685 KEY_QUERY_VALUE,
2686 &hKey);
2687 RegCloseKey(hEnumKey);
2688 if (rc != ERROR_SUCCESS)
2689 {
2690 SetLastError(rc);
2691 break;
2692 }
2693 /* Read registry entry */
2694 BufferSize = PropertyBufferSize;
2695 rc = RegQueryValueExW(
2696 hKey,
2697 RegistryPropertyName,
2698 NULL, /* Reserved */
2699 PropertyRegDataType,
2700 PropertyBuffer,
2701 &BufferSize);
2702 if (RequiredSize)
2703 *RequiredSize = BufferSize;
2704 switch(rc) {
2705 case ERROR_SUCCESS:
2706 if (PropertyBuffer != NULL || BufferSize == 0)
2707 ret = TRUE;
2708 else
2709 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2710 break;
2711 case ERROR_MORE_DATA:
2712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2713 break;
2714 default:
2715 SetLastError(rc);
2716 }
2717 RegCloseKey(hKey);
2718 break;
2719 }
2720
2721 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2722 {
2723 DWORD required = (wcslen(DevInfo->Data) + 1) * sizeof(WCHAR);
2724
2725 if (PropertyRegDataType)
2726 *PropertyRegDataType = REG_SZ;
2727 if (RequiredSize)
2728 *RequiredSize = required;
2729 if (PropertyBufferSize >= required)
2730 {
2731 wcscpy((LPWSTR)PropertyBuffer, DevInfo->Data);
2732 ret = TRUE;
2733 }
2734 else
2735 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2736 break;
2737 }
2738
2739 /*case SPDRP_BUSTYPEGUID:
2740 case SPDRP_LEGACYBUSTYPE:
2741 case SPDRP_BUSNUMBER:
2742 case SPDRP_ENUMERATOR_NAME:
2743 case SPDRP_SECURITY_SDS:
2744 case SPDRP_DEVTYPE:
2745 case SPDRP_EXCLUSIVE:
2746 case SPDRP_CHARACTERISTICS:
2747 case SPDRP_ADDRESS:
2748 case SPDRP_DEVICE_POWER_DATA:*/
2749 #if (WINVER >= 0x501)
2750 /*case SPDRP_REMOVAL_POLICY:
2751 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2752 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2753 case SPDRP_INSTALL_STATE:*/
2754 #endif
2755
2756 default:
2757 {
2758 ERR("Property 0x%lx not implemented\n", Property);
2759 SetLastError(ERROR_NOT_SUPPORTED);
2760 }
2761 }
2762 }
2763
2764 TRACE("Returning %d\n", ret);
2765 return ret;
2766 }
2767
2768 /***********************************************************************
2769 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2770 */
2771 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
2772 IN HDEVINFO DeviceInfoSet,
2773 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2774 IN DWORD Property,
2775 IN CONST BYTE *PropertyBuffer,
2776 IN DWORD PropertyBufferSize)
2777 {
2778 FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2779 Property, PropertyBuffer, PropertyBufferSize);
2780 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2781 return FALSE;
2782 }
2783
2784 /***********************************************************************
2785 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2786 */
2787 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
2788 IN HDEVINFO DeviceInfoSet,
2789 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2790 IN DWORD Property,
2791 IN const BYTE *PropertyBuffer,
2792 IN DWORD PropertyBufferSize)
2793 {
2794 struct DeviceInfoSet *list;
2795 BOOL ret = FALSE;
2796
2797 TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2798 Property, PropertyBuffer, PropertyBufferSize);
2799
2800 if (!DeviceInfoSet)
2801 SetLastError(ERROR_INVALID_HANDLE);
2802 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2803 SetLastError(ERROR_INVALID_HANDLE);
2804 else if (!DeviceInfoData)
2805 SetLastError(ERROR_INVALID_HANDLE);
2806 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2807 SetLastError(ERROR_INVALID_USER_BUFFER);
2808 else
2809 {
2810 switch (Property)
2811 {
2812 case SPDRP_COMPATIBLEIDS:
2813 case SPDRP_CONFIGFLAGS:
2814 case SPDRP_FRIENDLYNAME:
2815 case SPDRP_HARDWAREID:
2816 case SPDRP_LOCATION_INFORMATION:
2817 case SPDRP_LOWERFILTERS:
2818 case SPDRP_SECURITY:
2819 case SPDRP_SERVICE:
2820 case SPDRP_UI_NUMBER_DESC_FORMAT:
2821 case SPDRP_UPPERFILTERS:
2822 {
2823 LPCWSTR RegistryPropertyName;
2824 DWORD RegistryDataType;
2825 HKEY hKey;
2826 LONG rc;
2827
2828 switch (Property)
2829 {
2830 case SPDRP_COMPATIBLEIDS:
2831 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
2832 RegistryDataType = REG_MULTI_SZ;
2833 break;
2834 case SPDRP_CONFIGFLAGS:
2835 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
2836 RegistryDataType = REG_DWORD;
2837 break;
2838 case SPDRP_FRIENDLYNAME:
2839 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
2840 RegistryDataType = REG_SZ;
2841 break;
2842 case SPDRP_HARDWAREID:
2843 RegistryPropertyName = REGSTR_VAL_HARDWAREID;
2844 RegistryDataType = REG_MULTI_SZ;
2845 break;
2846 case SPDRP_LOCATION_INFORMATION:
2847 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
2848 RegistryDataType = REG_SZ;
2849 break;
2850 case SPDRP_LOWERFILTERS:
2851 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
2852 RegistryDataType = REG_MULTI_SZ;
2853 break;
2854 case SPDRP_SECURITY:
2855 RegistryPropertyName = L"Security";
2856 RegistryDataType = REG_BINARY;
2857 break;
2858 case SPDRP_SERVICE:
2859 RegistryPropertyName = REGSTR_VAL_SERVICE;
2860 RegistryDataType = REG_SZ;
2861 break;
2862 case SPDRP_UI_NUMBER_DESC_FORMAT:
2863 RegistryPropertyName = L"UINumberDescFormat";
2864 RegistryDataType = REG_SZ;
2865 break;
2866 case SPDRP_UPPERFILTERS:
2867 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
2868 RegistryDataType = REG_MULTI_SZ;
2869 break;
2870 default:
2871 /* Should not happen */
2872 RegistryPropertyName = NULL;
2873 RegistryDataType = REG_BINARY;
2874 break;
2875 }
2876 /* Open device registry key */
2877 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
2878 if (hKey != INVALID_HANDLE_VALUE)
2879 {
2880 /* Write new data */
2881 rc = RegSetValueExW(
2882 hKey,
2883 RegistryPropertyName,
2884 0, /* Reserved */
2885 RegistryDataType,
2886 PropertyBuffer,
2887 PropertyBufferSize);
2888 if (rc == ERROR_SUCCESS)
2889 ret = TRUE;
2890 else
2891 SetLastError(rc);
2892 RegCloseKey(hKey);
2893 }
2894 break;
2895 }
2896
2897 /*case SPDRP_CHARACTERISTICS:
2898 case SPDRP_DEVTYPE:
2899 case SPDRP_EXCLUSIVE:*/
2900 #if (WINVER >= 0x501)
2901 //case SPDRP_REMOVAL_POLICY_OVERRIDE:
2902 #endif
2903 //case SPDRP_SECURITY_SDS:
2904
2905 default:
2906 {
2907 ERR("Property 0x%lx not implemented\n", Property);
2908 SetLastError(ERROR_NOT_SUPPORTED);
2909 }
2910 }
2911 }
2912
2913 TRACE("Returning %d\n", ret);
2914 return ret;
2915 }
2916
2917
2918 /***********************************************************************
2919 * SetupDiInstallClassA (SETUPAPI.@)
2920 */
2921 BOOL WINAPI SetupDiInstallClassA(
2922 IN HWND hwndParent OPTIONAL,
2923 IN PCSTR InfFileName,
2924 IN DWORD Flags,
2925 IN HSPFILEQ FileQueue OPTIONAL)
2926 {
2927 return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
2928 }
2929
2930
2931 /***********************************************************************
2932 * SetupDiInstallClassW (SETUPAPI.@)
2933 */
2934 BOOL WINAPI SetupDiInstallClassW(
2935 IN HWND hwndParent OPTIONAL,
2936 IN PCWSTR InfFileName,
2937 IN DWORD Flags,
2938 IN HSPFILEQ FileQueue OPTIONAL)
2939 {
2940 return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
2941 }
2942
2943
2944 /***********************************************************************
2945 * SetupDiInstallClassExA (SETUPAPI.@)
2946 */
2947 BOOL WINAPI SetupDiInstallClassExA(
2948 IN HWND hwndParent OPTIONAL,
2949 IN PCSTR InfFileName OPTIONAL,
2950 IN DWORD Flags,
2951 IN HSPFILEQ FileQueue OPTIONAL,
2952 IN const GUID* InterfaceClassGuid OPTIONAL,
2953 IN PVOID Reserved1,
2954 IN PVOID Reserved2)
2955 {
2956 PWSTR InfFileNameW = NULL;
2957 BOOL Result;
2958
2959 if (InfFileName)
2960 {
2961 InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
2962 if (InfFileNameW == NULL)
2963 {
2964 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2965 return FALSE;
2966 }
2967 }
2968
2969 Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
2970 FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
2971
2972 MyFree(InfFileNameW);
2973
2974 return Result;
2975 }
2976
2977
2978 static HKEY CreateClassKey(HINF hInf)
2979 {
2980 WCHAR FullBuffer[MAX_PATH];
2981 WCHAR Buffer[MAX_PATH];
2982 DWORD RequiredSize;
2983 HKEY hClassKey;
2984
2985 Buffer[0] = '\\';
2986 if (!SetupGetLineTextW(NULL,
2987 hInf,
2988 Version,
2989 ClassGUID,
2990 &Buffer[1],
2991 MAX_PATH - 1,
2992 &RequiredSize))
2993 {
2994 return INVALID_HANDLE_VALUE;
2995 }
2996
2997 lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
2998 lstrcatW(FullBuffer, Buffer);
2999
3000
3001 if (!SetupGetLineTextW(NULL,
3002 hInf,
3003 Version,
3004 Class,
3005 Buffer,
3006 MAX_PATH,
3007 &RequiredSize))
3008 {
3009 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3010 return INVALID_HANDLE_VALUE;
3011 }
3012
3013 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3014 FullBuffer,
3015 0,
3016 NULL,
3017 REG_OPTION_NON_VOLATILE,
3018 KEY_SET_VALUE,
3019 NULL,
3020 &hClassKey,
3021 NULL))
3022 {
3023 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3024 return INVALID_HANDLE_VALUE;
3025 }
3026
3027 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
3028 Class,
3029 0,
3030 REG_SZ,
3031 (LPBYTE)Buffer,
3032 RequiredSize * sizeof(WCHAR)))
3033 {
3034 RegCloseKey(hClassKey);
3035 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3036 return INVALID_HANDLE_VALUE;
3037 }
3038
3039 return hClassKey;
3040 }
3041
3042
3043 static BOOL
3044 InstallServicesSection(
3045 IN HINF hInf,
3046 IN PCWSTR SectionName,
3047 IN HDEVINFO DeviceInfoSet OPTIONAL,
3048 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3049 OUT PCWSTR* pAssociatedService OPTIONAL,
3050 OUT PBOOL pRebootRequired OPTIONAL)
3051 {
3052 INFCONTEXT ContextService;
3053 DWORD RequiredSize;
3054 INT Flags;
3055 BOOL ret = FALSE;
3056
3057 ret = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService);
3058 while (ret)
3059 {
3060 LPWSTR ServiceName = NULL;
3061 LPWSTR ServiceSection = NULL;
3062
3063 ret = SetupGetStringFieldW(
3064 &ContextService,
3065 1, /* Field index */
3066 NULL, 0,
3067 &RequiredSize);
3068 if (!ret)
3069 goto nextservice;
3070 if (RequiredSize > 0)
3071 {
3072 /* We got the needed size for the buffer */
3073 ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3074 if (!ServiceName)
3075 {
3076 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3077 goto nextservice;
3078 }
3079 ret = SetupGetStringFieldW(
3080 &ContextService,
3081 1, /* Field index */
3082 ServiceName, RequiredSize,
3083 &RequiredSize);
3084 if (!ret)
3085 goto nextservice;
3086 }
3087 ret = SetupGetIntField(
3088 &ContextService,
3089 2, /* Field index */
3090 &Flags);
3091 if (!ret)
3092 {
3093 /* The field may be empty. Ignore the error */
3094 Flags = 0;
3095 }
3096 ret = SetupGetStringFieldW(
3097 &ContextService,
3098 3, /* Field index */
3099 NULL, 0,
3100 &RequiredSize);
3101 if (!ret)
3102 {
3103 if (GetLastError() == ERROR_INVALID_PARAMETER)
3104 {
3105 /* This first is probably missing. It is not
3106 * required, so ignore the error */
3107 RequiredSize = 0;
3108 ret = TRUE;
3109 }
3110 else
3111 goto nextservice;
3112 }
3113 if (RequiredSize > 0)
3114 {
3115 /* We got the needed size for the buffer */
3116 ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
3117 if (!ServiceSection)
3118 {
3119 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3120 goto nextservice;
3121 }
3122 ret = SetupGetStringFieldW(
3123 &ContextService,
3124 3, /* Field index */
3125 ServiceSection, RequiredSize,
3126 &RequiredSize);
3127 if (!ret)
3128 goto nextservice;
3129
3130 SetLastError(ERROR_SUCCESS);
3131 ret = SetupInstallServicesFromInfSectionExW(
3132 hInf,
3133 ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
3134 }
3135 if (ret && (Flags & SPSVCINST_ASSOCSERVICE))
3136 {
3137 if (pAssociatedService)
3138 {
3139 *pAssociatedService = ServiceName;
3140 ServiceName = NULL;
3141 }
3142 if (pRebootRequired && GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
3143 *pRebootRequired = TRUE;
3144 }
3145 nextservice:
3146 HeapFree(GetProcessHeap(), 0, ServiceName);
3147 HeapFree(GetProcessHeap(), 0, ServiceSection);
3148 if (!ret)
3149 goto done;
3150 ret = SetupFindNextLine(&ContextService, &ContextService);
3151 }
3152
3153 ret = TRUE;
3154
3155 done:
3156 return ret;
3157 }
3158
3159 /***********************************************************************
3160 * SetupDiInstallClassExW (SETUPAPI.@)
3161 */
3162 BOOL WINAPI SetupDiInstallClassExW(
3163 IN HWND hwndParent OPTIONAL,
3164 IN PCWSTR InfFileName OPTIONAL,
3165 IN DWORD Flags,
3166 IN HSPFILEQ FileQueue OPTIONAL,
3167 IN const GUID* InterfaceClassGuid OPTIONAL,
3168 IN PVOID Reserved1,
3169 IN PVOID Reserved2)
3170 {
3171 BOOL ret = FALSE;
3172
3173 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
3174 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
3175
3176 if (!InfFileName && !InterfaceClassGuid)
3177 SetLastError(ERROR_INVALID_PARAMETER);
3178 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
3179 {
3180 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
3181 SetLastError(ERROR_INVALID_FLAGS);
3182 }
3183 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
3184 SetLastError(ERROR_INVALID_PARAMETER);
3185 else if (Reserved1 != NULL)
3186 SetLastError(ERROR_INVALID_PARAMETER);
3187 else if (Reserved2 != NULL)
3188 SetLastError(ERROR_INVALID_PARAMETER);
3189 else
3190 {
3191 WCHAR SectionName[MAX_PATH];
3192 HINF hInf = INVALID_HANDLE_VALUE;
3193 HKEY hClassKey = INVALID_HANDLE_VALUE;
3194 PVOID callback_context = NULL;
3195
3196 if (InterfaceClassGuid)
3197 {
3198 /* SetupDiCreateDeviceInterface??? */
3199 FIXME("Installing an interface is not implemented\n");
3200 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3201 }
3202 else
3203 {
3204 if (Flags & DI_NOVCP)
3205 FIXME("FileQueue argument ignored\n");
3206 if (Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
3207 FIXME("Flags 0x%lx ignored\n", Flags & (DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
3208
3209 /* Open the .inf file */
3210 hInf = SetupOpenInfFileW(
3211 InfFileName,
3212 NULL,
3213 INF_STYLE_WIN4,
3214 NULL);
3215 if (hInf == INVALID_HANDLE_VALUE)
3216 goto cleanup;
3217
3218 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
3219 hClassKey = CreateClassKey(hInf);
3220 if (hClassKey == INVALID_HANDLE_VALUE)
3221 goto cleanup;
3222
3223 /* Try to append a layout file */
3224 ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
3225 if (!ret)
3226 goto cleanup;
3227
3228 /* Retrieve the actual section name */
3229 ret = SetupDiGetActualSectionToInstallW(
3230 hInf,
3231 ClassInstall32,
3232 SectionName,
3233 MAX_PATH - wcslen(DotServices),
3234 NULL,
3235 NULL);
3236 if (!ret)
3237 goto cleanup;
3238
3239 callback_context = SetupInitDefaultQueueCallback(hwndParent);
3240 if (!callback_context)
3241 goto cleanup;
3242
3243 ret = SetupInstallFromInfSectionW(
3244 hwndParent,
3245 hInf,
3246 SectionName,
3247 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
3248 hClassKey,
3249 NULL, /* SourceRootPath */
3250 0, /* CopyFlags */
3251 SetupDefaultQueueCallbackW,
3252 callback_context,
3253 NULL,
3254 NULL);
3255 if (!ret)
3256 goto cleanup;
3257
3258 /* Install .Services section */
3259 lstrcatW(SectionName, DotServices);
3260 ret = InstallServicesSection(hInf, SectionName, NULL, NULL, NULL, NULL);
3261 if (!ret)
3262 goto cleanup;
3263
3264 ret = TRUE;
3265 }
3266
3267 cleanup:
3268 if (hInf != INVALID_HANDLE_VALUE)
3269 SetupCloseInfFile(hInf);
3270 if (hClassKey != INVALID_HANDLE_VALUE)
3271 RegCloseKey(hClassKey);
3272 SetupTermDefaultQueueCallback(callback_context);
3273 }
3274
3275 TRACE("Returning %d\n", ret);
3276 return ret;
3277 }
3278
3279
3280 /***********************************************************************
3281 * SetupDiOpenClassRegKey (SETUPAPI.@)
3282 */
3283 HKEY WINAPI SetupDiOpenClassRegKey(
3284 const GUID* ClassGuid,
3285 REGSAM samDesired)
3286 {
3287 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3288 DIOCR_INSTALLER, NULL, NULL);
3289 }
3290
3291
3292 /***********************************************************************
3293 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3294 */
3295 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3296 const GUID* ClassGuid OPTIONAL,
3297 REGSAM samDesired,
3298 DWORD Flags,
3299 PCSTR MachineName OPTIONAL,
3300 PVOID Reserved)
3301 {
3302 PWSTR MachineNameW = NULL;
3303 HKEY hKey;
3304
3305 TRACE("\n");
3306
3307 if (MachineName)
3308 {
3309 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3310 if (MachineNameW == NULL)
3311 return INVALID_HANDLE_VALUE;
3312 }
3313
3314 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3315 Flags, MachineNameW, Reserved);
3316
3317 if (MachineNameW)
3318 MyFree(MachineNameW);
3319
3320 return hKey;
3321 }
3322
3323
3324 /***********************************************************************
3325 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3326 */
3327 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3328 const GUID* ClassGuid OPTIONAL,
3329 REGSAM samDesired,
3330 DWORD Flags,
3331 PCWSTR MachineName OPTIONAL,
3332 PVOID Reserved)
3333 {
3334 LPWSTR lpGuidString;
3335 LPWSTR lpFullGuidString;
3336 DWORD dwLength;
3337 HKEY HKLM;
3338 HKEY hClassesKey;
3339 HKEY hClassKey;
3340 DWORD rc;
3341 LPCWSTR lpKeyName;
3342
3343 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3344 Flags, debugstr_w(MachineName), Reserved);
3345
3346 if (Flags == DIOCR_INSTALLER)
3347 {
3348 lpKeyName = REGSTR_PATH_CLASS_NT;
3349 }
3350 else if (Flags == DIOCR_INTERFACE)
3351 {
3352 lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3353 }
3354 else
3355 {
3356 ERR("Invalid Flags parameter!\n");
3357 SetLastError(ERROR_INVALID_FLAGS);
3358 return INVALID_HANDLE_VALUE;
3359 }
3360
3361 if (MachineName != NULL)
3362 {
3363 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3364 if (rc != ERROR_SUCCESS)
3365 {
3366 SetLastError(rc);
3367 return INVALID_HANDLE_VALUE;
3368 }
3369 }
3370 else
3371 HKLM = HKEY_LOCAL_MACHINE;
3372
3373 rc = RegOpenKeyExW(HKLM,
3374 lpKeyName,
3375 0,
3376 ClassGuid ? 0 : samDesired,
3377 &hClassesKey);
3378 if (MachineName != NULL) RegCloseKey(HKLM);
3379 if (rc != ERROR_SUCCESS)
3380 {
3381 SetLastError(rc);
3382 return INVALID_HANDLE_VALUE;
3383 }
3384
3385 if (ClassGuid == NULL)
3386 return hClassesKey;
3387
3388 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
3389 {
3390 SetLastError(ERROR_GEN_FAILURE);
3391 RegCloseKey(hClassesKey);
3392 return INVALID_HANDLE_VALUE;
3393 }
3394
3395 dwLength = lstrlenW(lpGuidString);
3396 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
3397 if (!lpFullGuidString)
3398 {
3399 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3400 RpcStringFreeW(&lpGuidString);
3401 return INVALID_HANDLE_VALUE;
3402 }
3403 lpFullGuidString[0] = '{';
3404 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
3405 lpFullGuidString[dwLength + 1] = '}';
3406 lpFullGuidString[dwLength + 2] = '\0';
3407 RpcStringFreeW(&lpGuidString);
3408
3409 rc = RegOpenKeyExW(hClassesKey,
3410 lpFullGuidString,
3411 0,
3412 samDesired,
3413 &hClassKey);
3414 if (rc != ERROR_SUCCESS)
3415 {
3416 SetLastError(rc);
3417 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
3418 RegCloseKey(hClassesKey);
3419 return INVALID_HANDLE_VALUE;
3420 }
3421
3422 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
3423 RegCloseKey(hClassesKey);
3424
3425 return hClassKey;
3426 }
3427
3428 /***********************************************************************
3429 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3430 */
3431 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3432 HDEVINFO DeviceInfoSet,
3433 PCWSTR DevicePath,
3434 DWORD OpenFlags,
3435 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3436 {
3437 FIXME("%p %s %08lx %p\n",
3438 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3439 return FALSE;
3440 }
3441
3442 /***********************************************************************
3443 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3444 */
3445 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3446 HDEVINFO DeviceInfoSet,
3447 PCSTR DevicePath,
3448 DWORD OpenFlags,
3449 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3450 {
3451 LPWSTR DevicePathW = NULL;
3452 BOOL bResult;
3453
3454 TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3455
3456 DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
3457 if (DevicePathW == NULL)
3458 return FALSE;
3459
3460 bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
3461 DevicePathW, OpenFlags, DeviceInterfaceData);
3462
3463 MyFree(DevicePathW);
3464
3465 return bResult;
3466 }
3467
3468 /***********************************************************************
3469 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3470 */
3471 BOOL WINAPI SetupDiSetClassInstallParamsA(
3472 HDEVINFO DeviceInfoSet,
3473 PSP_DEVINFO_DATA DeviceInfoData,
3474 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3475 DWORD ClassInstallParamsSize)
3476 {
3477 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3478 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3479 return FALSE;
3480 }
3481
3482 /***********************************************************************
3483 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3484 */
3485 BOOL WINAPI SetupDiSetClassInstallParamsW(
3486 IN HDEVINFO DeviceInfoSet,
3487 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3488 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3489 IN DWORD ClassInstallParamsSize)
3490 {
3491 struct DeviceInfoSet *list;
3492 BOOL ret = FALSE;
3493
3494 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
3495 ClassInstallParams, ClassInstallParamsSize);
3496
3497 if (!DeviceInfoSet)
3498 SetLastError(ERROR_INVALID_PARAMETER);
3499 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3500 SetLastError(ERROR_INVALID_HANDLE);
3501 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3502 SetLastError(ERROR_INVALID_HANDLE);
3503 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3504 SetLastError(ERROR_INVALID_USER_BUFFER);
3505 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
3506 SetLastError(ERROR_INVALID_USER_BUFFER);
3507 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
3508 SetLastError(ERROR_INVALID_PARAMETER);
3509 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
3510 SetLastError(ERROR_INVALID_PARAMETER);
3511 else
3512 {
3513 SP_DEVINSTALL_PARAMS_W InstallParams;
3514 BOOL Result;
3515
3516 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3517 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3518 if (!Result)
3519 goto done;
3520
3521 if (ClassInstallParams)
3522 {
3523 /* Check parameters in ClassInstallParams */
3524 if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE
3525 || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0]))
3526 {
3527 SetLastError(ERROR_INVALID_USER_BUFFER);
3528 goto done;
3529 }
3530 else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL)
3531 {
3532 FIXME("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction);
3533 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3534 goto done;
3535 }
3536 ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize);
3537 if (!ret)
3538 goto done;
3539 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
3540 }
3541 else
3542 {
3543 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
3544 }
3545
3546 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3547 }
3548
3549 done:
3550 TRACE("Returning %d\n", ret);
3551 return ret;
3552 }
3553
3554 static BOOL PropertyChangeHandler(
3555 IN HDEVINFO DeviceInfoSet,
3556 IN PSP_DEVINFO_DATA DeviceInfoData,
3557 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3558 IN DWORD ClassInstallParamsSize)
3559 {
3560 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
3561 BOOL ret = FALSE;
3562
3563 if (!DeviceInfoData)
3564 SetLastError(ERROR_INVALID_PARAMETER);
3565 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
3566 SetLastError(ERROR_INVALID_PARAMETER);
3567 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
3568 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
3569 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
3570 SetLastError(ERROR_INVALID_FLAGS);
3571 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
3572 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3573 SetLastError(ERROR_INVALID_FLAGS);
3574 else if (PropChangeParams
3575 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
3576 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3577 SetLastError(ERROR_INVALID_USER_BUFFER);
3578 else
3579 {
3580 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
3581 if (!DeviceInfoData)
3582 {
3583 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
3584 CurrentPropChangeParams = &list->ClassInstallParams.PropChange;
3585 }
3586 else
3587 {
3588 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
3589 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange;
3590 }
3591 if (*CurrentPropChangeParams)
3592 {
3593 MyFree(*CurrentPropChangeParams);
3594 *CurrentPropChangeParams = NULL;
3595 }
3596 if (PropChangeParams)
3597 {
3598 *CurrentPropChangeParams = MyMalloc(sizeof(SP_PROPCHANGE_PARAMS));
3599 if (!*CurrentPropChangeParams)
3600 {
3601 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3602 goto done;
3603 }
3604 memcpy(*CurrentPropChangeParams, PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
3605 }
3606 ret = TRUE;
3607 }
3608
3609 done:
3610 return ret;
3611 }
3612
3613 static DWORD
3614 GetFunctionPointer(
3615 IN PWSTR InstallerName,
3616 OUT HMODULE* ModulePointer,
3617 OUT PVOID* FunctionPointer)
3618 {
3619 HMODULE hModule = NULL;
3620 LPSTR FunctionNameA = NULL;
3621 PWCHAR Comma;
3622 DWORD rc;
3623
3624 *ModulePointer = NULL;
3625 *FunctionPointer = NULL;
3626
3627 Comma = strchrW(InstallerName, ',');
3628 if (!Comma)
3629 {
3630 rc = ERROR_INVALID_PARAMETER;
3631 goto cleanup;
3632 }
3633
3634 /* Load library */
3635 *Comma = '\0';
3636 hModule = LoadLibraryW(InstallerName);
3637 *Comma = ',';
3638 if (!hModule)
3639 {
3640 rc = GetLastError();
3641 goto cleanup;
3642 }
3643
3644 /* Skip comma spaces */
3645 while (*Comma == ',' || isspaceW(*Comma))
3646 Comma++;
3647
3648 /* W->A conversion for function name */
3649 FunctionNameA = UnicodeToMultiByte(Comma, CP_ACP);
3650 if (!FunctionNameA)
3651 {
3652 rc = GetLastError();
3653 goto cleanup;
3654 }
3655
3656 /* Search function */
3657 *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
3658 if (!*FunctionPointer)
3659 {
3660 rc = GetLastError();
3661 goto cleanup;
3662 }
3663
3664 *ModulePointer = hModule;
3665 rc = ERROR_SUCCESS;
3666
3667 cleanup:
3668 if (rc != ERROR_SUCCESS && hModule)
3669 FreeLibrary(hModule);
3670 MyFree(FunctionNameA);
3671 return rc;
3672 }
3673
3674 static DWORD
3675 FreeFunctionPointer(
3676 IN HMODULE ModulePointer,
3677 IN PVOID FunctionPointer)
3678 {
3679 if (ModulePointer == NULL)
3680 return ERROR_SUCCESS;
3681 if (FreeLibrary(ModulePointer))
3682 return ERROR_SUCCESS;
3683 else
3684 return GetLastError();
3685 }
3686
3687 /***********************************************************************
3688 * SetupDiCallClassInstaller (SETUPAPI.@)
3689 */
3690 BOOL WINAPI SetupDiCallClassInstaller(
3691 IN DI_FUNCTION InstallFunction,
3692 IN HDEVINFO DeviceInfoSet,
3693 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
3694 {
3695 BOOL ret = FALSE;
3696
3697 TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3698
3699 if (!DeviceInfoSet)
3700 SetLastError(ERROR_INVALID_PARAMETER);
3701 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3702 SetLastError(ERROR_INVALID_HANDLE);
3703 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3704 SetLastError(ERROR_INVALID_HANDLE);
3705 else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
3706 SetLastError(ERROR_INVALID_HANDLE);
3707 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3708 SetLastError(ERROR_INVALID_USER_BUFFER);
3709 else
3710 {
3711 SP_DEVINSTALL_PARAMS_W InstallParams;
3712 #define CLASS_COINSTALLER 0x1
3713 #define DEVICE_COINSTALLER 0x2
3714 #define CLASS_INSTALLER 0x4
3715 UCHAR CanHandle = 0;
3716 DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
3717
3718 switch (InstallFunction)
3719 {
3720 case DIF_ALLOW_INSTALL:
3721 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3722 break;
3723 case DIF_DESTROYPRIVATEDATA:
3724 CanHandle = CLASS_INSTALLER;
3725 break;
3726 case DIF_INSTALLDEVICE:
3727 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3728 DefaultHandler = SetupDiInstallDevice;
3729 break;
3730 case DIF_INSTALLDEVICEFILES:
3731 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3732 DefaultHandler = SetupDiInstallDriverFiles;
3733 break;
3734 case DIF_INSTALLINTERFACES:
3735 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3736 DefaultHandler = SetupDiInstallDeviceInterfaces;
3737 break;
3738 case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
3739 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3740 break;
3741 case DIF_NEWDEVICEWIZARD_POSTANALYZE:
3742 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3743 break;
3744 case DIF_NEWDEVICEWIZARD_PREANALYZE:
3745 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3746 break;
3747 case DIF_PROPERTYCHANGE:
3748 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3749 DefaultHandler = SetupDiChangeState;
3750 break;
3751 case DIF_REGISTER_COINSTALLERS:
3752 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3753 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
3754 break;
3755 case DIF_SELECTBESTCOMPATDRV:
3756 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3757 DefaultHandler = SetupDiSelectBestCompatDrv;
3758 break;
3759 default:
3760 ERR("Install function %u not supported\n", InstallFunction);
3761 SetLastError(ERROR_NOT_SUPPORTED);
3762 }
3763
3764 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
3765 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
3766 /* Don't process this call, as a parameter is invalid */
3767 CanHandle = 0;
3768
3769 if (CanHandle != 0)
3770 {
3771 LIST_ENTRY ClassCoInstallersListHead;
3772 LIST_ENTRY DeviceCoInstallersListHead;
3773 HMODULE ClassInstallerLibrary = NULL;
3774 CLASS_INSTALL_PROC ClassInstaller = NULL;
3775 COINSTALLER_CONTEXT_DATA Context;
3776 PLIST_ENTRY ListEntry;
3777 HKEY hKey;
3778 DWORD dwRegType, dwLength;
3779 DWORD rc = NO_ERROR;
3780
3781 InitializeListHead(&ClassCoInstallersListHead);
3782 InitializeListHead(&DeviceCoInstallersListHead);
3783
3784 if (CanHandle & DEVICE_COINSTALLER)
3785 {
3786 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
3787 if (hKey != INVALID_HANDLE_VALUE)
3788 {
3789 rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
3790 if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
3791 {
3792 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
3793 if (KeyBuffer != NULL)
3794 {
3795 rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
3796 if (rc == ERROR_SUCCESS)
3797 {
3798 LPWSTR ptr;
3799 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)