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