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