- Fix installation of INF sections including a section of the same name in another...
[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 HeapFree(GetProcessHeap(), 0, InstancePath);
1723 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1724 if (!InstancePath)
1725 {
1726 rc = ERROR_NOT_ENOUGH_MEMORY;
1727 goto cleanup;
1728 }
1729 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1730 if (rc != ERROR_SUCCESS)
1731 goto cleanup;
1732 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1733 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1734
1735 if (DeviceInstanceW)
1736 {
1737 /* Check if device enumerator is not the right one */
1738 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
1739 continue;
1740 }
1741
1742 /* Find class GUID associated to the device instance */
1743 rc = RegOpenKeyExW(
1744 list->HKLM,
1745 REGSTR_PATH_SYSTEMENUM,
1746 0, /* Options */
1747 0,
1748 &hEnumKey);
1749 if (rc != ERROR_SUCCESS)
1750 goto cleanup;
1751 rc = RegOpenKeyExW(
1752 hEnumKey,
1753 InstancePath,
1754 0, /* Options */
1755 KEY_QUERY_VALUE,
1756 &hKey);
1757 RegCloseKey(hEnumKey);
1758 if (rc != ERROR_SUCCESS)
1759 goto cleanup;
1760 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1761 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1762 RegCloseKey(hKey);
1763 if (rc != ERROR_SUCCESS)
1764 goto cleanup;
1765 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1766 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1767 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1768 {
1769 rc = ERROR_GEN_FAILURE;
1770 goto cleanup;
1771 }
1772 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1773
1774 /* If current device doesn't match the list GUID (if any), skip this entry */
1775 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1776 continue;
1777
1778 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1779 j = 0;
1780 while (TRUE)
1781 {
1782 struct DeviceInterface *interfaceInfo;
1783
1784 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1785 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1786 if (rc == ERROR_NO_MORE_ITEMS)
1787 break;
1788 if (rc != ERROR_SUCCESS)
1789 goto cleanup;
1790 j++;
1791 if (KeyBuffer[0] != '#')
1792 /* This entry doesn't represent an interesting entry */
1793 continue;
1794
1795 /* Open sub key */
1796 if (hReferenceKey != NULL)
1797 RegCloseKey(hReferenceKey);
1798 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1799 if (rc != ERROR_SUCCESS)
1800 goto cleanup;
1801
1802 /* Read SymbolicLink value */
1803 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1804 if (rc != ERROR_SUCCESS )
1805 goto cleanup;
1806 if (dwRegType != REG_SZ)
1807 {
1808 rc = ERROR_GEN_FAILURE;
1809 goto cleanup;
1810 }
1811
1812 /* We have found a device */
1813 /* Step 1. Create a device info element */
1814 if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
1815 {
1816 rc = GetLastError();
1817 goto cleanup;
1818 }
1819 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1820 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1821
1822 /* Step 2. Create an interface list for this element */
1823 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1824 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1825 if (!pSymbolicLink)
1826 {
1827 rc = ERROR_NOT_ENOUGH_MEMORY;
1828 goto cleanup;
1829 }
1830 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1831 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1832 if (rc != ERROR_SUCCESS)
1833 goto cleanup;
1834 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1835 {
1836 rc = GetLastError();
1837 goto cleanup;
1838 }
1839
1840 /* Step 3. Update flags */
1841 if (KeyBuffer[1] == '\0')
1842 interfaceInfo->Flags |= SPINT_DEFAULT;
1843 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
1844 if (rc != ERROR_SUCCESS)
1845 {
1846 if (OnlyPresentInterfaces)
1847 {
1848 DestroyDeviceInterface(interfaceInfo);
1849 continue;
1850 }
1851 else
1852 interfaceInfo->Flags |= SPINT_REMOVED;
1853 }
1854 else
1855 {
1856 dwLength = sizeof(DWORD);
1857 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength)
1858 && dwRegType == REG_DWORD && LinkedValue)
1859 interfaceInfo->Flags |= SPINT_ACTIVE;
1860 RegCloseKey(hControlKey);
1861 }
1862
1863 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1864 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1865 }
1866 }
1867 rc = ERROR_SUCCESS;
1868
1869 cleanup:
1870 if (hReferenceKey != NULL)
1871 RegCloseKey(hReferenceKey);
1872 if (hDeviceInstanceKey != NULL)
1873 RegCloseKey(hDeviceInstanceKey);
1874 if (hInterfaceKey != INVALID_HANDLE_VALUE)
1875 RegCloseKey(hInterfaceKey);
1876 HeapFree(GetProcessHeap(), 0, InstancePath);
1877 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1878 return rc;
1879 }
1880
1881 /***********************************************************************
1882 * SetupDiGetClassDevsExW (SETUPAPI.@)
1883 */
1884 HDEVINFO WINAPI
1885 SetupDiGetClassDevsExW(
1886 IN CONST GUID *ClassGuid OPTIONAL,
1887 IN PCWSTR Enumerator OPTIONAL,
1888 IN HWND hwndParent OPTIONAL,
1889 IN DWORD Flags,
1890 IN HDEVINFO DeviceInfoSet OPTIONAL,
1891 IN PCWSTR MachineName OPTIONAL,
1892 IN PVOID Reserved)
1893 {
1894 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1895 struct DeviceInfoSet *list;
1896 CONST GUID *pClassGuid;
1897 LONG rc;
1898 HDEVINFO ret = INVALID_HANDLE_VALUE;
1899
1900 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(ClassGuid), debugstr_w(Enumerator),
1901 hwndParent, Flags, DeviceInfoSet, debugstr_w(MachineName), Reserved);
1902
1903 /* Create the deviceset if not set */
1904 if (DeviceInfoSet)
1905 {
1906 list = (struct DeviceInfoSet *)DeviceInfoSet;
1907 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1908 {
1909 SetLastError(ERROR_INVALID_HANDLE);
1910 goto cleanup;
1911 }
1912 hDeviceInfo = DeviceInfoSet;
1913 }
1914 else
1915 {
1916 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1917 Flags & DIGCF_DEVICEINTERFACE ? NULL : ClassGuid,
1918 NULL, MachineName, NULL);
1919 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1920 goto cleanup;
1921 list = (struct DeviceInfoSet *)hDeviceInfo;
1922 }
1923
1924 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1925 pClassGuid = NULL;
1926 else
1927 pClassGuid = &list->ClassGuid;
1928
1929 if (Flags & DIGCF_PROFILE)
1930 FIXME(": flag DIGCF_PROFILE ignored\n");
1931
1932 if (Flags & DIGCF_ALLCLASSES)
1933 {
1934 rc = SETUP_CreateDevList(list, MachineName, pClassGuid, Enumerator);
1935 if (rc != ERROR_SUCCESS)
1936 {
1937 SetLastError(rc);
1938 goto cleanup;
1939 }
1940 ret = hDeviceInfo;
1941 }
1942 else if (Flags & DIGCF_DEVICEINTERFACE)
1943 {
1944 if (ClassGuid == NULL)
1945 {
1946 SetLastError(ERROR_INVALID_PARAMETER);
1947 goto cleanup;
1948 }
1949
1950 rc = SETUP_CreateInterfaceList(list, MachineName, ClassGuid, Enumerator, Flags & DIGCF_PRESENT);
1951 if (rc != ERROR_SUCCESS)
1952 {
1953 SetLastError(rc);
1954 goto cleanup;
1955 }
1956 ret = hDeviceInfo;
1957 }
1958 else
1959 {
1960 rc = SETUP_CreateDevList(list, MachineName, ClassGuid, Enumerator);
1961 if (rc != ERROR_SUCCESS)
1962 {
1963 SetLastError(rc);
1964 goto cleanup;
1965 }
1966 ret = hDeviceInfo;
1967 }
1968
1969 cleanup:
1970 if (!DeviceInfoSet && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != ret)
1971 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1972 return ret;
1973 }
1974
1975 /***********************************************************************
1976 * SetupDiGetClassImageIndex (SETUPAPI.@)
1977 */
1978
1979 static BOOL
1980 GetIconIndex(
1981 IN HKEY hClassKey,
1982 OUT PINT ImageIndex)
1983 {
1984 LPWSTR Buffer = NULL;
1985 DWORD dwRegType, dwLength;
1986 LONG rc;
1987 BOOL ret = FALSE;
1988
1989 /* Read icon registry key */
1990 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
1991 if (rc != ERROR_SUCCESS)
1992 {
1993 SetLastError(rc);
1994 goto cleanup;
1995 } else if (dwRegType != REG_SZ)
1996 {
1997 SetLastError(ERROR_INVALID_INDEX);
1998 goto cleanup;
1999 }
2000 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2001 if (!Buffer)
2002 {
2003 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2004 goto cleanup;
2005 }
2006 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2007 if (rc != ERROR_SUCCESS)
2008 {
2009 SetLastError(rc);
2010 goto cleanup;
2011 }
2012 /* make sure the returned buffer is NULL-terminated */
2013 Buffer[dwLength / sizeof(WCHAR)] = 0;
2014
2015 /* Transform icon value to a INT */
2016 *ImageIndex = atoiW(Buffer);
2017 ret = TRUE;
2018
2019 cleanup:
2020 MyFree(Buffer);
2021 return ret;
2022 }
2023
2024 BOOL WINAPI
2025 SetupDiGetClassImageIndex(
2026 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
2027 IN CONST GUID *ClassGuid,
2028 OUT PINT ImageIndex)
2029 {
2030 struct ClassImageList *list;
2031 BOOL ret = FALSE;
2032
2033 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
2034
2035 if (!ClassImageListData || !ClassGuid || !ImageIndex)
2036 SetLastError(ERROR_INVALID_PARAMETER);
2037 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2038 SetLastError(ERROR_INVALID_USER_BUFFER);
2039 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
2040 SetLastError(ERROR_INVALID_USER_BUFFER);
2041 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
2042 SetLastError(ERROR_INVALID_USER_BUFFER);
2043 else if (!ImageIndex)
2044 SetLastError(ERROR_INVALID_PARAMETER);
2045 else
2046 {
2047 HKEY hKey = INVALID_HANDLE_VALUE;
2048 INT iconIndex;
2049
2050 /* Read Icon registry entry into Buffer */
2051 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL);
2052 if (hKey == INVALID_HANDLE_VALUE)
2053 goto cleanup;
2054 if (!GetIconIndex(hKey, &iconIndex))
2055 goto cleanup;
2056
2057 if (iconIndex >= 0)
2058 {
2059 SetLastError(ERROR_INVALID_INDEX);
2060 goto cleanup;
2061 }
2062
2063 *ImageIndex = -iconIndex;
2064 ret = TRUE;
2065
2066 cleanup:
2067 if (hKey != INVALID_HANDLE_VALUE)
2068 RegCloseKey(hKey);
2069 }
2070
2071 TRACE("Returning %d\n", ret);
2072 return ret;
2073 }
2074
2075 /***********************************************************************
2076 * SetupDiGetClassImageList(SETUPAPI.@)
2077 */
2078 BOOL WINAPI
2079 SetupDiGetClassImageList(
2080 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
2081 {
2082 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
2083 }
2084
2085 /***********************************************************************
2086 * SetupDiGetClassImageListExA(SETUPAPI.@)
2087 */
2088 BOOL WINAPI
2089 SetupDiGetClassImageListExA(
2090 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2091 IN PCSTR MachineName OPTIONAL,
2092 IN PVOID Reserved)
2093 {
2094 PWSTR MachineNameW = NULL;
2095 BOOL ret;
2096
2097 if (MachineName)
2098 {
2099 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2100 if (MachineNameW == NULL)
2101 return FALSE;
2102 }
2103
2104 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
2105
2106 if (MachineNameW)
2107 MyFree(MachineNameW);
2108
2109 return ret;
2110 }
2111
2112 /***********************************************************************
2113 * SetupDiGetClassImageListExW(SETUPAPI.@)
2114 */
2115 BOOL WINAPI
2116 SetupDiGetClassImageListExW(
2117 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2118 IN PCWSTR MachineName OPTIONAL,
2119 IN PVOID Reserved)
2120 {
2121 BOOL ret = FALSE;
2122
2123 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
2124
2125 if (!ClassImageListData)
2126 SetLastError(ERROR_INVALID_PARAMETER);
2127 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2128 SetLastError(ERROR_INVALID_USER_BUFFER);
2129 else if (Reserved)
2130 SetLastError(ERROR_INVALID_PARAMETER);
2131 else
2132 {
2133 struct ClassImageList *list = NULL;
2134 DWORD size;
2135
2136 size = FIELD_OFFSET(struct ClassImageList, szData);
2137 if (MachineName)
2138 size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
2139 list = HeapAlloc(GetProcessHeap(), 0, size);
2140 if (!list)
2141 {
2142 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2143 goto cleanup;
2144 }
2145 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
2146 if (MachineName)
2147 {
2148 list->szData[0] = list->szData[1] = '\\';
2149 strcpyW(list->szData + 2, MachineName);
2150 list->MachineName = list->szData;
2151 }
2152 else
2153 {
2154 list->MachineName = NULL;
2155 }
2156
2157 ClassImageListData->Reserved = (ULONG_PTR)list;
2158 ret = TRUE;
2159
2160 cleanup:
2161 if (!ret)
2162 MyFree(list);
2163 }
2164
2165 TRACE("Returning %d\n", ret);
2166 return ret;
2167 }
2168
2169 /***********************************************************************
2170 * SetupDiLoadClassIcon(SETUPAPI.@)
2171 */
2172 BOOL WINAPI
2173 SetupDiLoadClassIcon(
2174 IN CONST GUID *ClassGuid,
2175 OUT HICON *LargeIcon OPTIONAL,
2176 OUT PINT MiniIconIndex OPTIONAL)
2177 {
2178 BOOL ret = FALSE;
2179
2180 if (!ClassGuid)
2181 SetLastError(ERROR_INVALID_PARAMETER);
2182 else
2183 {
2184 LPWSTR Buffer = NULL;
2185 LPCWSTR DllName;
2186 INT iconIndex;
2187 HKEY hKey = INVALID_HANDLE_VALUE;
2188
2189 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
2190 if (hKey == INVALID_HANDLE_VALUE)
2191 goto cleanup;
2192
2193 if (!GetIconIndex(hKey, &iconIndex))
2194 goto cleanup;
2195
2196 if (iconIndex > 0)
2197 {
2198 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
2199 PWCHAR Comma;
2200 LONG rc;
2201 DWORD dwRegType, dwLength;
2202 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
2203 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2204 {
2205 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2206 if (Buffer == NULL)
2207 {
2208 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2209 goto cleanup;
2210 }
2211 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2212 if (rc != ERROR_SUCCESS)
2213 {
2214 SetLastError(rc);
2215 goto cleanup;
2216 }
2217 /* make sure the returned buffer is NULL-terminated */
2218 Buffer[dwLength / sizeof(WCHAR)] = 0;
2219 }
2220 else if
2221 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
2222 && dwRegType == REG_SZ)
2223 {
2224 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2225 if (Buffer == NULL)
2226 {
2227 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2228 goto cleanup;
2229 }
2230 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2231 if (rc != ERROR_SUCCESS)
2232 {
2233 SetLastError(rc);
2234 goto cleanup;
2235 }
2236 /* make sure the returned buffer is NULL-terminated */
2237 Buffer[dwLength / sizeof(WCHAR)] = 0;
2238 }
2239 else
2240 {
2241 /* Unable to find where to load the icon */
2242 SetLastError(ERROR_FILE_NOT_FOUND);
2243 goto cleanup;
2244 }
2245 Comma = strchrW(Buffer, ',');
2246 if (!Comma)
2247 {
2248 SetLastError(ERROR_GEN_FAILURE);
2249 goto cleanup;
2250 }
2251 *Comma = '\0';
2252 DllName = Buffer;
2253 }
2254 else
2255 {
2256 /* Look up icon in setupapi.dll */
2257 DllName = L"setupapi.dll";
2258 iconIndex = -iconIndex;
2259 }
2260
2261 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
2262 if (LargeIcon)
2263 {
2264 if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
2265 {
2266 SetLastError(ERROR_INVALID_INDEX);
2267 goto cleanup;
2268 }
2269 }
2270 if (MiniIconIndex)
2271 *MiniIconIndex = iconIndex;
2272 ret = TRUE;
2273
2274 cleanup:
2275 if (hKey != INVALID_HANDLE_VALUE)
2276 RegCloseKey(hKey);
2277 MyFree(Buffer);
2278 }
2279
2280 TRACE("Returning %d\n", ret);
2281 return ret;
2282 }
2283
2284 /***********************************************************************
2285 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2286 */
2287 BOOL WINAPI
2288 SetupDiEnumDeviceInterfaces(
2289 IN HDEVINFO DeviceInfoSet,
2290 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
2291 IN CONST GUID *InterfaceClassGuid,
2292 IN DWORD MemberIndex,
2293 OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2294 {
2295 BOOL ret = FALSE;
2296
2297 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
2298 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2299
2300 if (!DeviceInterfaceData)
2301 SetLastError(ERROR_INVALID_PARAMETER);
2302 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2303 SetLastError(ERROR_INVALID_USER_BUFFER);
2304 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
2305 {
2306 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2307
2308 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2309 {
2310 PLIST_ENTRY ItemList = list->ListHead.Flink;
2311 BOOL Found = FALSE;
2312 while (ItemList != &list->ListHead && !Found)
2313 {
2314 PLIST_ENTRY InterfaceListEntry;
2315 struct DeviceInfoElement *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfoElement, ListEntry);
2316 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
2317 {
2318 /* We are not searching for this element */
2319 ItemList = ItemList->Flink;
2320 continue;
2321 }
2322 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
2323 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
2324 {
2325 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2326 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2327 {
2328 InterfaceListEntry = InterfaceListEntry->Flink;
2329 continue;
2330 }
2331 if (MemberIndex-- == 0)
2332 {
2333 /* return this item */
2334 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2335 &DevItf->InterfaceClassGuid,
2336 sizeof(GUID));
2337 DeviceInterfaceData->Flags = DevItf->Flags;
2338 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2339 Found = TRUE;
2340 }
2341 InterfaceListEntry = InterfaceListEntry->Flink;
2342 }
2343 ItemList = ItemList->Flink;
2344 }
2345 if (!Found)
2346 SetLastError(ERROR_NO_MORE_ITEMS);
2347 else
2348 ret = TRUE;
2349 }
2350 else
2351 SetLastError(ERROR_INVALID_HANDLE);
2352 }
2353 else
2354 SetLastError(ERROR_INVALID_HANDLE);
2355 return ret;
2356 }
2357
2358 static VOID
2359 ReferenceInfFile(struct InfFileDetails* infFile)
2360 {
2361 InterlockedIncrement(&infFile->References);
2362 }
2363
2364 static VOID
2365 DereferenceInfFile(struct InfFileDetails* infFile)
2366 {
2367 if (InterlockedDecrement(&infFile->References) == 0)
2368 {
2369 SetupCloseInfFile(infFile->hInf);
2370 HeapFree(GetProcessHeap(), 0, infFile);
2371 }
2372 }
2373
2374 static BOOL
2375 DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
2376 {
2377 DereferenceInfFile(driverInfo->InfFileDetails);
2378 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
2379 HeapFree(GetProcessHeap(), 0, driverInfo);
2380 return TRUE;
2381 }
2382
2383 static BOOL
2384 DestroyClassInstallParams(struct ClassInstallParams* installParams)
2385 {
2386 return HeapFree(GetProcessHeap(), 0, installParams->PropChange);
2387 }
2388
2389 static BOOL
2390 DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
2391 {
2392 PLIST_ENTRY ListEntry;
2393 struct DriverInfoElement *driverInfo;
2394 struct DeviceInterface *deviceInterface;
2395
2396 while (!IsListEmpty(&deviceInfo->DriverListHead))
2397 {
2398 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
2399 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
2400 if (!DestroyDriverInfoElement(driverInfo))
2401 return FALSE;
2402 }
2403 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
2404 {
2405 ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
2406 deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
2407 if (!DestroyDeviceInterface(deviceInterface))
2408 return FALSE;
2409 }
2410 DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
2411 return HeapFree(GetProcessHeap(), 0, deviceInfo);
2412 }
2413
2414 static BOOL
2415 DestroyDeviceInfoSet(struct DeviceInfoSet* list)
2416 {
2417 PLIST_ENTRY ListEntry;
2418 struct DeviceInfoElement *deviceInfo;
2419
2420 while (!IsListEmpty(&list->ListHead))
2421 {
2422 ListEntry = RemoveHeadList(&list->ListHead);
2423 deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfoElement, ListEntry);
2424 if (!DestroyDeviceInfoElement(deviceInfo))
2425 return FALSE;
2426 }
2427 if (list->HKLM != HKEY_LOCAL_MACHINE)
2428 RegCloseKey(list->HKLM);
2429 CM_Disconnect_Machine(list->hMachine);
2430 DestroyClassInstallParams(&list->ClassInstallParams);
2431 return HeapFree(GetProcessHeap(), 0, list);
2432 }
2433
2434 /***********************************************************************
2435 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2436 */
2437 BOOL WINAPI
2438 SetupDiDestroyDeviceInfoList(
2439 IN HDEVINFO DeviceInfoSet)
2440 {
2441 BOOL ret = FALSE;
2442
2443 TRACE("%p\n", DeviceInfoSet);
2444 if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
2445 {
2446 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2447
2448 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2449 ret = DestroyDeviceInfoSet(list);
2450 else
2451 SetLastError(ERROR_INVALID_HANDLE);
2452 }
2453 else
2454 SetLastError(ERROR_INVALID_HANDLE);
2455
2456 TRACE("Returning %d\n", ret);
2457 return ret;
2458 }
2459
2460 /***********************************************************************
2461 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2462 */
2463 BOOL WINAPI
2464 SetupDiGetDeviceInterfaceDetailA(
2465 IN HDEVINFO DeviceInfoSet,
2466 IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2467 OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData OPTIONAL,
2468 IN DWORD DeviceInterfaceDetailDataSize,
2469 OUT PDWORD RequiredSize OPTIONAL,
2470 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
2471 {
2472 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2473 DWORD sizeW = 0, sizeA;
2474 BOOL ret = FALSE;
2475
2476 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2477 DeviceInterfaceData, DeviceInterfaceDetailData,
2478 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2479
2480 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2481 SetLastError(ERROR_INVALID_USER_BUFFER);
2482 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2483 SetLastError(ERROR_INVALID_PARAMETER);
2484 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2485 SetLastError(ERROR_INVALID_PARAMETER);
2486 else
2487 {
2488 if (DeviceInterfaceDetailData != NULL)
2489 {
2490 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2491 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2492 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2493 if (!DeviceInterfaceDetailDataW)
2494 {
2495 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2496 }
2497 }
2498 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2499 {
2500 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2501 ret = SetupDiGetDeviceInterfaceDetailW(
2502 DeviceInfoSet,
2503 DeviceInterfaceData,
2504 DeviceInterfaceDetailDataW,
2505 sizeW,
2506 &sizeW,
2507 DeviceInfoData);
2508 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2509 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2510 if (RequiredSize)
2511 *RequiredSize = sizeA;
2512 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2513 {
2514 if (!WideCharToMultiByte(
2515 CP_ACP, 0,
2516 DeviceInterfaceDetailDataW->DevicePath, -1,
2517 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2518 NULL, NULL))
2519 {
2520 ret = FALSE;
2521 }
2522 }
2523 }
2524 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2525 }
2526
2527 TRACE("Returning %d\n", ret);
2528 return ret;
2529 }
2530
2531 /***********************************************************************
2532 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2533 */
2534 BOOL WINAPI
2535 SetupDiGetDeviceInterfaceDetailW(
2536 IN HDEVINFO DeviceInfoSet,
2537 IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2538 OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData OPTIONAL,
2539 IN DWORD DeviceInterfaceDetailDataSize,
2540 OUT PDWORD RequiredSize OPTIONAL,
2541 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
2542 {
2543 BOOL ret = FALSE;
2544
2545 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2546 DeviceInterfaceData, DeviceInterfaceDetailData,
2547 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2548
2549 if (!DeviceInfoSet || !DeviceInterfaceData)
2550 SetLastError(ERROR_INVALID_PARAMETER);
2551 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2552 SetLastError(ERROR_INVALID_HANDLE);
2553 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2554 SetLastError(ERROR_INVALID_HANDLE);
2555 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2556 SetLastError(ERROR_INVALID_USER_BUFFER);
2557 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2558 SetLastError(ERROR_INVALID_USER_BUFFER);
2559 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2560 SetLastError(ERROR_INVALID_USER_BUFFER);
2561 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2562 SetLastError(ERROR_INVALID_PARAMETER);
2563 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2564 SetLastError(ERROR_INVALID_PARAMETER);
2565 else
2566 {
2567 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2568 LPCWSTR devName = deviceInterface->SymbolicLink;
2569 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2570 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2571
2572 if (sizeRequired > DeviceInterfaceDetailDataSize)
2573 {
2574 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2575 if (RequiredSize)
2576 *RequiredSize = sizeRequired;
2577 }
2578 else
2579 {
2580 strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
2581 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2582 if (DeviceInfoData)
2583 {
2584 memcpy(&DeviceInfoData->ClassGuid,
2585 &deviceInterface->DeviceInfo->ClassGuid,
2586 sizeof(GUID));
2587 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
2588 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2589 }
2590 ret = TRUE;
2591 }
2592 }
2593
2594 TRACE("Returning %d\n", ret);
2595 return ret;
2596 }
2597
2598 /***********************************************************************
2599 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2600 */
2601 BOOL WINAPI
2602 SetupDiGetDeviceRegistryPropertyA(
2603 IN HDEVINFO DeviceInfoSet,
2604 IN PSP_DEVINFO_DATA DeviceInfoData,
2605 IN DWORD Property,
2606 OUT PDWORD PropertyRegDataType OPTIONAL,
2607 OUT PBYTE PropertyBuffer OPTIONAL,
2608 IN DWORD PropertyBufferSize,
2609 OUT PDWORD RequiredSize OPTIONAL)
2610 {
2611 BOOL bResult;
2612 BOOL bIsStringProperty;
2613 DWORD RegType;
2614 DWORD RequiredSizeA, RequiredSizeW;
2615 DWORD PropertyBufferSizeW = 0;
2616 PBYTE PropertyBufferW = NULL;
2617
2618 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2619 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2620 RequiredSize);
2621
2622 if (PropertyBufferSize != 0)
2623 {
2624 PropertyBufferSizeW = PropertyBufferSize * 2;
2625 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2626 if (!PropertyBufferW)
2627 {
2628 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2629 return FALSE;
2630 }
2631 }
2632
2633 bResult = SetupDiGetDeviceRegistryPropertyW(
2634 DeviceInfoSet,
2635 DeviceInfoData,
2636 Property,
2637 &RegType,
2638 PropertyBufferW,
2639 PropertyBufferSizeW,
2640 &RequiredSizeW);
2641
2642 if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2643 {
2644 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2645
2646 if (bIsStringProperty)
2647 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2648 else
2649 RequiredSizeA = RequiredSizeW;
2650 if (RequiredSize)
2651 *RequiredSize = RequiredSizeA;
2652 if (PropertyRegDataType)
2653 *PropertyRegDataType = RegType;
2654 }
2655
2656 if (!bResult)
2657 {
2658 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2659 return bResult;
2660 }
2661
2662 if (RequiredSizeA <= PropertyBufferSize)
2663 {
2664 if (bIsStringProperty && PropertyBufferSize > 0)
2665 {
2666 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2667 {
2668 /* Last error is already set by WideCharToMultiByte */
2669 bResult = FALSE;
2670 }
2671 }
2672 else
2673 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2674 }
2675 else
2676 {
2677 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2678 bResult = FALSE;
2679 }
2680
2681 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2682 return bResult;
2683 }
2684
2685 /***********************************************************************
2686 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2687 */
2688 BOOL WINAPI
2689 SetupDiGetDeviceRegistryPropertyW(
2690 IN HDEVINFO DeviceInfoSet,
2691 IN PSP_DEVINFO_DATA DeviceInfoData,
2692 IN DWORD Property,
2693 OUT PDWORD PropertyRegDataType OPTIONAL,
2694 OUT PBYTE PropertyBuffer OPTIONAL,
2695 IN DWORD PropertyBufferSize,
2696 OUT PDWORD RequiredSize OPTIONAL)
2697 {
2698 HKEY hEnumKey, hKey;
2699 DWORD rc;
2700 BOOL ret = FALSE;
2701
2702 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2703 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2704 RequiredSize);
2705
2706 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2707 SetLastError(ERROR_INVALID_HANDLE);
2708 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2709 SetLastError(ERROR_INVALID_HANDLE);
2710 else if (!DeviceInfoData)
2711 SetLastError(ERROR_INVALID_PARAMETER);
2712 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2713 SetLastError(ERROR_INVALID_USER_BUFFER);
2714 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2715 SetLastError(ERROR_INVALID_PARAMETER);
2716 else
2717 {
2718 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2719 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2720
2721 switch (Property)
2722 {
2723 case SPDRP_CAPABILITIES:
2724 case SPDRP_CLASS:
2725 case SPDRP_CLASSGUID:
2726 case SPDRP_COMPATIBLEIDS:
2727 case SPDRP_CONFIGFLAGS:
2728 case SPDRP_DEVICEDESC:
2729 case SPDRP_DRIVER:
2730 case SPDRP_FRIENDLYNAME:
2731 case SPDRP_HARDWAREID:
2732 case SPDRP_LOCATION_INFORMATION:
2733 case SPDRP_LOWERFILTERS:
2734 case SPDRP_MFG:
2735 case SPDRP_SECURITY:
2736 case SPDRP_SERVICE:
2737 case SPDRP_UI_NUMBER:
2738 case SPDRP_UI_NUMBER_DESC_FORMAT:
2739 case SPDRP_UPPERFILTERS:
2740 {
2741 LPCWSTR RegistryPropertyName;
2742 DWORD BufferSize;
2743
2744 switch (Property)
2745 {
2746 case SPDRP_CAPABILITIES:
2747 RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
2748 case SPDRP_CLASS:
2749 RegistryPropertyName = REGSTR_VAL_CLASS; break;
2750 case SPDRP_CLASSGUID:
2751 RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
2752 case SPDRP_COMPATIBLEIDS:
2753 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
2754 case SPDRP_CONFIGFLAGS:
2755 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
2756 case SPDRP_DEVICEDESC:
2757 RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
2758 case SPDRP_DRIVER:
2759 RegistryPropertyName = REGSTR_VAL_DRIVER; break;
2760 case SPDRP_FRIENDLYNAME:
2761 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
2762 case SPDRP_HARDWAREID:
2763 RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
2764 case SPDRP_LOCATION_INFORMATION:
2765 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
2766 case SPDRP_LOWERFILTERS:
2767 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
2768 case SPDRP_MFG:
2769 RegistryPropertyName = REGSTR_VAL_MFG; break;
2770 case SPDRP_SECURITY:
2771 RegistryPropertyName = REGSTR_SECURITY; break;
2772 case SPDRP_SERVICE:
2773 RegistryPropertyName = REGSTR_VAL_SERVICE; break;
2774 case SPDRP_UI_NUMBER:
2775 RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
2776 case SPDRP_UI_NUMBER_DESC_FORMAT:
2777 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
2778 case SPDRP_UPPERFILTERS:
2779 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
2780 default:
2781 /* Should not happen */
2782 RegistryPropertyName = NULL; break;
2783 }
2784
2785 /* Open registry key name */
2786 rc = RegOpenKeyExW(
2787 list->HKLM,
2788 REGSTR_PATH_SYSTEMENUM,
2789 0, /* Options */
2790 0,
2791 &hEnumKey);
2792 if (rc != ERROR_SUCCESS)
2793 {
2794 SetLastError(rc);
2795 break;
2796 }
2797 rc = RegOpenKeyExW(
2798 hEnumKey,
2799 DevInfo->Data,
2800 0, /* Options */
2801 KEY_QUERY_VALUE,
2802 &hKey);
2803 RegCloseKey(hEnumKey);
2804 if (rc != ERROR_SUCCESS)
2805 {
2806 SetLastError(rc);
2807 break;
2808 }
2809 /* Read registry entry */
2810 BufferSize = PropertyBufferSize;
2811 rc = RegQueryValueExW(
2812 hKey,
2813 RegistryPropertyName,
2814 NULL, /* Reserved */
2815 PropertyRegDataType,
2816 PropertyBuffer,
2817 &BufferSize);
2818 if (RequiredSize)
2819 *RequiredSize = BufferSize;
2820 switch(rc) {
2821 case ERROR_SUCCESS:
2822 if (PropertyBuffer != NULL || BufferSize == 0)
2823 ret = TRUE;
2824 else
2825 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2826 break;
2827 case ERROR_MORE_DATA:
2828 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2829 break;
2830 default:
2831 SetLastError(rc);
2832 }
2833 RegCloseKey(hKey);
2834 break;
2835 }
2836
2837 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2838 {
2839 DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
2840
2841 if (PropertyRegDataType)
2842 *PropertyRegDataType = REG_SZ;
2843 if (RequiredSize)
2844 *RequiredSize = required;
2845 if (PropertyBufferSize >= required)
2846 {
2847 strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
2848 ret = TRUE;
2849 }
2850 else
2851 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2852 break;
2853 }
2854
2855 /*case SPDRP_BUSTYPEGUID:
2856 case SPDRP_LEGACYBUSTYPE:
2857 case SPDRP_BUSNUMBER:
2858 case SPDRP_ENUMERATOR_NAME:
2859 case SPDRP_SECURITY_SDS:
2860 case SPDRP_DEVTYPE:
2861 case SPDRP_EXCLUSIVE:
2862 case SPDRP_CHARACTERISTICS:
2863 case SPDRP_ADDRESS:
2864 case SPDRP_DEVICE_POWER_DATA:*/
2865 #if (WINVER >= 0x501)
2866 /*case SPDRP_REMOVAL_POLICY:
2867 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2868 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2869 case SPDRP_INSTALL_STATE:*/
2870 #endif
2871
2872 default:
2873 {
2874 ERR("Property 0x%lx not implemented\n", Property);
2875 SetLastError(ERROR_NOT_SUPPORTED);
2876 }
2877 }
2878 }
2879
2880 TRACE("Returning %d\n", ret);
2881 return ret;
2882 }
2883
2884 /***********************************************************************
2885 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2886 */
2887 BOOL WINAPI
2888 SetupDiSetDeviceRegistryPropertyA(
2889 IN HDEVINFO DeviceInfoSet,
2890 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2891 IN DWORD Property,
2892 IN CONST BYTE *PropertyBuffer OPTIONAL,
2893 IN DWORD PropertyBufferSize)
2894 {
2895 FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2896 Property, PropertyBuffer, PropertyBufferSize);
2897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2898 return FALSE;
2899 }
2900
2901 /***********************************************************************
2902 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2903 */
2904 BOOL WINAPI
2905 SetupDiSetDeviceRegistryPropertyW(
2906 IN HDEVINFO DeviceInfoSet,
2907 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2908 IN DWORD Property,
2909 IN CONST BYTE *PropertyBuffer OPTIONAL,
2910 IN DWORD PropertyBufferSize)
2911 {
2912 struct DeviceInfoSet *list;
2913 BOOL ret = FALSE;
2914
2915 TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2916 Property, PropertyBuffer, PropertyBufferSize);
2917
2918 if (!DeviceInfoSet)
2919 SetLastError(ERROR_INVALID_HANDLE);
2920 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2921 SetLastError(ERROR_INVALID_HANDLE);
2922 else if (!DeviceInfoData)
2923 SetLastError(ERROR_INVALID_HANDLE);
2924 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2925 SetLastError(ERROR_INVALID_USER_BUFFER);
2926 else
2927 {
2928 switch (Property)
2929 {
2930 case SPDRP_COMPATIBLEIDS:
2931 case SPDRP_CONFIGFLAGS:
2932 case SPDRP_FRIENDLYNAME:
2933 case SPDRP_HARDWAREID:
2934 case SPDRP_LOCATION_INFORMATION:
2935 case SPDRP_LOWERFILTERS:
2936 case SPDRP_SECURITY:
2937 case SPDRP_SERVICE:
2938 case SPDRP_UI_NUMBER_DESC_FORMAT:
2939 case SPDRP_UPPERFILTERS:
2940 {
2941 LPCWSTR RegistryPropertyName;
2942 DWORD RegistryDataType;
2943 HKEY hKey;
2944 LONG rc;
2945
2946 switch (Property)
2947 {
2948 case SPDRP_COMPATIBLEIDS:
2949 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
2950 RegistryDataType = REG_MULTI_SZ;
2951 break;
2952 case SPDRP_CONFIGFLAGS:
2953 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
2954 RegistryDataType = REG_DWORD;
2955 break;
2956 case SPDRP_FRIENDLYNAME:
2957 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
2958 RegistryDataType = REG_SZ;
2959 break;
2960 case SPDRP_HARDWAREID:
2961 RegistryPropertyName = REGSTR_VAL_HARDWAREID;
2962 RegistryDataType = REG_MULTI_SZ;
2963 break;
2964 case SPDRP_LOCATION_INFORMATION:
2965 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
2966 RegistryDataType = REG_SZ;
2967 break;
2968 case SPDRP_LOWERFILTERS:
2969 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
2970 RegistryDataType = REG_MULTI_SZ;
2971 break;
2972 case SPDRP_SECURITY:
2973 RegistryPropertyName = REGSTR_SECURITY;
2974 RegistryDataType = REG_BINARY;
2975 break;
2976 case SPDRP_SERVICE:
2977 RegistryPropertyName = REGSTR_VAL_SERVICE;
2978 RegistryDataType = REG_SZ;
2979 break;
2980 case SPDRP_UI_NUMBER_DESC_FORMAT:
2981 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
2982 RegistryDataType = REG_SZ;
2983 break;
2984 case SPDRP_UPPERFILTERS:
2985 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
2986 RegistryDataType = REG_MULTI_SZ;
2987 break;
2988 default:
2989 /* Should not happen */
2990 RegistryPropertyName = NULL;
2991 RegistryDataType = REG_BINARY;
2992 break;
2993 }
2994 /* Open device registry key */
2995 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
2996 if (hKey != INVALID_HANDLE_VALUE)
2997 {
2998 /* Write new data */
2999 rc = RegSetValueExW(
3000 hKey,
3001 RegistryPropertyName,
3002 0, /* Reserved */
3003 RegistryDataType,
3004 PropertyBuffer,
3005 PropertyBufferSize);
3006 if (rc == ERROR_SUCCESS)
3007 ret = TRUE;
3008 else
3009 SetLastError(rc);
3010 RegCloseKey(hKey);
3011 }
3012 break;
3013 }
3014
3015 /*case SPDRP_CHARACTERISTICS:
3016 case SPDRP_DEVTYPE:
3017 case SPDRP_EXCLUSIVE:*/
3018 #if (WINVER >= 0x501)
3019 //case SPDRP_REMOVAL_POLICY_OVERRIDE:
3020 #endif
3021 //case SPDRP_SECURITY_SDS:
3022
3023 default:
3024 {
3025 ERR("Property 0x%lx not implemented\n", Property);
3026 SetLastError(ERROR_NOT_SUPPORTED);
3027 }
3028 }
3029 }
3030
3031 TRACE("Returning %d\n", ret);
3032 return ret;
3033 }
3034
3035
3036 /***********************************************************************
3037 * SetupDiInstallClassA (SETUPAPI.@)
3038 */
3039 BOOL WINAPI
3040 SetupDiInstallClassA(
3041 IN HWND hwndParent OPTIONAL,
3042 IN PCSTR InfFileName,
3043 IN DWORD Flags,
3044 IN HSPFILEQ FileQueue OPTIONAL)
3045 {
3046 return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3047 }
3048
3049
3050 /***********************************************************************
3051 * SetupDiInstallClassW (SETUPAPI.@)
3052 */
3053 BOOL WINAPI
3054 SetupDiInstallClassW(
3055 IN HWND hwndParent OPTIONAL,
3056 IN PCWSTR InfFileName,
3057 IN DWORD Flags,
3058 IN HSPFILEQ FileQueue OPTIONAL)
3059 {
3060 return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3061 }
3062
3063
3064 /***********************************************************************
3065 * SetupDiInstallClassExA (SETUPAPI.@)
3066 */
3067 BOOL WINAPI
3068 SetupDiInstallClassExA(
3069 IN HWND hwndParent OPTIONAL,
3070 IN PCSTR InfFileName OPTIONAL,
3071 IN DWORD Flags,
3072 IN HSPFILEQ FileQueue OPTIONAL,
3073 IN CONST GUID *InterfaceClassGuid OPTIONAL,
3074 IN PVOID Reserved1,
3075 IN PVOID Reserved2)
3076 {
3077 PWSTR InfFileNameW = NULL;
3078 BOOL Result;
3079
3080 if (InfFileName)
3081 {
3082 InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
3083 if (InfFileNameW == NULL)
3084 {
3085 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3086 return FALSE;
3087 }
3088 }
3089
3090 Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3091 FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3092
3093 MyFree(InfFileNameW);
3094
3095 return Result;
3096 }
3097
3098
3099 static HKEY
3100 CreateClassKey(HINF hInf)
3101 {
3102 WCHAR FullBuffer[MAX_PATH];
3103 WCHAR Buffer[MAX_PATH];
3104 DWORD RequiredSize;
3105 HKEY hClassKey = NULL;
3106 HKEY ret = INVALID_HANDLE_VALUE;
3107
3108 FullBuffer[0] = '\0';
3109 Buffer[0] = '\\';
3110 if (!SetupGetLineTextW(NULL,
3111 hInf,
3112 Version,
3113 ClassGUID,
3114 &Buffer[1],
3115 MAX_PATH - 1,
3116 &RequiredSize))
3117 {
3118 goto cleanup;
3119 }
3120
3121 lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3122 lstrcatW(FullBuffer, Buffer);
3123
3124 if (!SetupGetLineTextW(NULL,
3125 hInf,
3126 Version,
3127 Class,
3128 Buffer,
3129 MAX_PATH,
3130 &RequiredSize))
3131 {
3132 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3133 goto cleanup;
3134 }
3135
3136 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3137 FullBuffer,
3138 0,
3139 NULL,
3140 REG_OPTION_NON_VOLATILE,
3141 KEY_SET_VALUE,
3142 NULL,
3143 &hClassKey,
3144 NULL))
3145 {
3146 goto cleanup;
3147 }
3148
3149 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
3150 Class,
3151 0,
3152 REG_SZ,
3153 (LPBYTE)Buffer,
3154 RequiredSize * sizeof(WCHAR)))
3155 {
3156 goto cleanup;
3157 }
3158
3159 ret = hClassKey;
3160
3161 cleanup:
3162 if (hClassKey != NULL && hClassKey != ret)
3163 RegCloseKey(hClassKey);
3164 if (ret == INVALID_HANDLE_VALUE && FullBuffer[0] != '\0')
3165 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3166 return ret;
3167 }
3168
3169
3170 /***********************************************************************
3171 * SetupDiInstallClassExW (SETUPAPI.@)
3172 */
3173 BOOL WINAPI
3174 SetupDiInstallClassExW(
3175 IN HWND hwndParent OPTIONAL,
3176 IN PCWSTR InfFileName OPTIONAL,
3177 IN DWORD Flags,
3178 IN HSPFILEQ FileQueue OPTIONAL,
3179 IN CONST GUID *InterfaceClassGuid OPTIONAL,
3180 IN PVOID Reserved1,
3181 IN PVOID Reserved2)
3182 {
3183 BOOL ret = FALSE;
3184
3185 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
3186 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
3187
3188 if (!InfFileName)
3189 {
3190 FIXME("Case not implemented: InfFileName NULL\n");
3191 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3192 }
3193 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
3194 {
3195 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
3196 SetLastError(ERROR_INVALID_FLAGS);
3197 }
3198 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
3199 SetLastError(ERROR_INVALID_PARAMETER);
3200 else if (Reserved1 != NULL)
3201 SetLastError(ERROR_INVALID_PARAMETER);
3202 else if (Reserved2 != NULL)
3203 SetLastError(ERROR_INVALID_PARAMETER);
3204 else
3205 {
3206 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3207 SP_DEVINSTALL_PARAMS_W InstallParams;
3208 WCHAR SectionName[MAX_PATH];
3209 HINF hInf = INVALID_HANDLE_VALUE;
3210 HKEY hRootKey = INVALID_HANDLE_VALUE;
3211 PVOID callback_context = NULL;
3212
3213 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
3214
3215 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3216 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
3217 goto cleanup;
3218 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
3219 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
3220 if (Flags & DI_NOVCP)
3221 InstallParams.FileQueue = FileQueue;
3222 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
3223 goto cleanup;
3224
3225 /* Open the .inf file */
3226 hInf = SetupOpenInfFileW(
3227 InfFileName,
3228 NULL,
3229 INF_STYLE_WIN4,
3230 NULL);
3231 if (hInf == INVALID_HANDLE_VALUE)
3232 goto cleanup;
3233
3234 /* Try to append a layout file */
3235 ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
3236 if (!ret)
3237 goto cleanup;
3238
3239 if (InterfaceClassGuid)
3240 {
3241 /* Retrieve the actual section name */
3242 ret = SetupDiGetActualSectionToInstallW(
3243 hInf,
3244 InterfaceInstall32,
3245 SectionName,
3246 MAX_PATH,
3247 NULL,
3248 NULL);
3249 if (!ret)
3250 goto cleanup;
3251
3252 /* Open registry key related to this interface */
3253 /* FIXME: What happens if the key doesn't exist? */
3254 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
3255 if (hRootKey == INVALID_HANDLE_VALUE)
3256 goto cleanup;
3257
3258 /* SetupDiCreateDeviceInterface??? */
3259 FIXME("Installing an interface is not implemented\n");
3260 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3261 }
3262 else
3263 {
3264 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
3265 hRootKey = CreateClassKey(hInf);
3266 if (hRootKey == INVALID_HANDLE_VALUE)
3267 goto cleanup;
3268
3269 /* Retrieve the actual section name */
3270 ret = SetupDiGetActualSectionToInstallW(
3271 hInf,
3272 ClassInstall32,
3273 SectionName,
3274 MAX_PATH - strlenW(DotServices),
3275 NULL,
3276 NULL);
3277 if (!ret)
3278 goto cleanup;
3279
3280 callback_context = SetupInitDefaultQueueCallback(hwndParent);
3281 if (!callback_context)
3282 goto cleanup;
3283
3284 ret = SetupInstallFromInfSectionW(
3285 hwndParent,
3286 hInf,
3287 SectionName,
3288 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
3289 hRootKey,
3290 NULL, /* SourceRootPath */
3291 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
3292 SetupDefaultQueueCallbackW,
3293 callback_context,
3294 hDeviceInfo,
3295 NULL);
3296 if (!ret)
3297 goto cleanup;
3298
3299 /* Install .Services section */
3300 lstrcatW(SectionName, DotServices);
3301 ret = SetupInstallServicesFromInfSectionExW(
3302 hInf,
3303 SectionName,
3304 0,
3305 hDeviceInfo,
3306 NULL,
3307 NULL,
3308 NULL);
3309 if (!ret)
3310 goto cleanup;
3311
3312 ret = TRUE;
3313 }
3314
3315 cleanup:
3316 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3317 SetupDiDestroyDeviceInfoList(hDeviceInfo);
3318 if (hInf != INVALID_HANDLE_VALUE)
3319 SetupCloseInfFile(hInf);
3320 if (hRootKey != INVALID_HANDLE_VALUE)
3321 RegCloseKey(hRootKey);
3322 SetupTermDefaultQueueCallback(callback_context);
3323 }
3324
3325 TRACE("Returning %d\n", ret);
3326 return ret;
3327 }
3328
3329
3330 /***********************************************************************
3331 * SetupDiOpenClassRegKey (SETUPAPI.@)
3332 */
3333 HKEY WINAPI
3334 SetupDiOpenClassRegKey(
3335 IN CONST GUID *ClassGuid OPTIONAL,
3336 IN REGSAM samDesired)
3337 {
3338 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3339 DIOCR_INSTALLER, NULL, NULL);
3340 }
3341
3342
3343 /***********************************************************************
3344 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3345 */
3346 HKEY WINAPI
3347 SetupDiOpenClassRegKeyExA(
3348 IN CONST GUID *ClassGuid OPTIONAL,
3349 IN REGSAM samDesired,
3350 IN DWORD Flags,
3351 IN PCSTR MachineName OPTIONAL,
3352 IN PVOID Reserved)
3353 {
3354 PWSTR MachineNameW = NULL;
3355 HKEY hKey;
3356
3357 TRACE("\n");
3358
3359 if (MachineName)
3360 {
3361 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3362 if (MachineNameW == NULL)
3363 return INVALID_HANDLE_VALUE;
3364 }
3365
3366 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3367 Flags, MachineNameW, Reserved);
3368
3369 if (MachineNameW)
3370 MyFree(MachineNameW);
3371
3372 return hKey;
3373 }
3374
3375
3376 /***********************************************************************
3377 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3378 */
3379 HKEY WINAPI
3380 SetupDiOpenClassRegKeyExW(
3381 IN CONST GUID* ClassGuid OPTIONAL,
3382 IN REGSAM samDesired,
3383 IN DWORD Flags,
3384 IN PCWSTR MachineName OPTIONAL,
3385 IN PVOID Reserved)
3386 {
3387 LPWSTR lpGuidString = NULL;
3388 LPWSTR lpFullGuidString = NULL;
3389 DWORD dwLength;
3390 HKEY HKLM;
3391 HKEY hClassesKey = NULL;
3392 HKEY hClassKey = NULL;
3393 HKEY ret = INVALID_HANDLE_VALUE;
3394 DWORD rc;
3395 LPCWSTR lpKeyName;
3396
3397 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3398 Flags, debugstr_w(MachineName), Reserved);
3399
3400 if (Flags == DIOCR_INSTALLER)
3401 lpKeyName = REGSTR_PATH_CLASS_NT;
3402 else if (Flags == DIOCR_INTERFACE)
3403 lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3404 else
3405 {
3406 ERR("Invalid Flags parameter!\n");
3407 SetLastError(ERROR_INVALID_FLAGS);
3408 goto cleanup;
3409 }
3410
3411 if (MachineName != NULL)
3412 {
3413 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3414 if (rc != ERROR_SUCCESS)
3415 {
3416 SetLastError(rc);
3417 goto cleanup;
3418 }
3419 }
3420 else
3421 HKLM = HKEY_LOCAL_MACHINE;
3422
3423 rc = RegOpenKeyExW(HKLM,
3424 lpKeyName,
3425 0,
3426 ClassGuid ? 0 : samDesired,
3427 &hClassesKey);
3428 if (MachineName != NULL) RegCloseKey(HKLM);
3429 if (rc != ERROR_SUCCESS)
3430 {
3431 SetLastError(rc);
3432 goto cleanup;
3433 }
3434
3435 if (ClassGuid == NULL)
3436 {
3437 /* Stop here. We don't need to open a subkey */
3438 ret = hClassesKey;
3439 goto cleanup;
3440 }
3441
3442 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
3443 {
3444 SetLastError(ERROR_GEN_FAILURE);
3445 goto cleanup;
3446 }
3447
3448 dwLength = lstrlenW(lpGuidString);
3449 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
3450 if (!lpFullGuidString)
3451 {
3452 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3453 goto cleanup;
3454 }
3455 lpFullGuidString[0] = '{';
3456 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
3457 lpFullGuidString[dwLength + 1] = '}';
3458 lpFullGuidString[dwLength + 2] = '\0';
3459
3460 rc = RegOpenKeyExW(hClassesKey,
3461 lpFullGuidString,
3462 0,
3463 samDesired,
3464 &hClassKey);
3465 if (rc != ERROR_SUCCESS)
3466 {
3467 SetLastError(rc);
3468 goto cleanup;
3469 }
3470 ret = hClassKey;
3471
3472 cleanup:
3473 if (hClassKey != NULL && hClassKey != ret)
3474 RegCloseKey(hClassKey);
3475 if (hClassesKey != NULL && hClassesKey != ret)
3476 RegCloseKey(hClassesKey);
3477 if (lpGuidString)
3478 RpcStringFreeW(&lpGuidString);
3479 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
3480
3481 return ret;
3482 }
3483
3484 /***********************************************************************
3485 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3486 */
3487 BOOL WINAPI
3488 SetupDiOpenDeviceInterfaceW(
3489 IN HDEVINFO DeviceInfoSet,
3490 IN PCWSTR DevicePath,
3491 IN DWORD OpenFlags,
3492 OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL)
3493 {
3494 FIXME("%p %s %08lx %p\n",
3495 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3496 return FALSE;
3497 }
3498
3499 /***********************************************************************
3500 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3501 */
3502 BOOL WINAPI
3503 SetupDiOpenDeviceInterfaceA(
3504 IN HDEVINFO DeviceInfoSet,
3505 IN PCSTR DevicePath,
3506 IN DWORD OpenFlags,
3507 OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData OPTIONAL)
3508 {
3509 LPWSTR DevicePathW = NULL;
3510 BOOL bResult;
3511
3512 TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3513
3514 DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
3515 if (DevicePathW == NULL)
3516 return FALSE;
3517
3518 bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
3519 DevicePathW, OpenFlags, DeviceInterfaceData);
3520
3521 MyFree(DevicePathW);
3522
3523 return bResult;
3524 }
3525
3526 /***********************************************************************
3527 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3528 */
3529 BOOL WINAPI
3530 SetupDiSetClassInstallParamsA(
3531 IN HDEVINFO DeviceInfoSet,
3532 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3533 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3534 IN DWORD ClassInstallParamsSize)
3535 {
3536 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3537 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3538 return FALSE;
3539 }
3540
3541 /***********************************************************************
3542 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3543 */
3544 BOOL WINAPI
3545 SetupDiSetClassInstallParamsW(
3546 IN HDEVINFO DeviceInfoSet,
3547 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3548 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3549 IN DWORD ClassInstallParamsSize)
3550 {
3551 struct DeviceInfoSet *list;
3552 BOOL ret = FALSE;
3553
3554 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
3555 ClassInstallParams, ClassInstallParamsSize);
3556
3557 if (!DeviceInfoSet)
3558 SetLastError(ERROR_INVALID_PARAMETER);
3559 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3560 SetLastError(ERROR_INVALID_HANDLE);
3561 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3562 SetLastError(ERROR_INVALID_HANDLE);
3563 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3564 SetLastError(ERROR_INVALID_USER_BUFFER);
3565 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
3566 SetLastError(ERROR_INVALID_USER_BUFFER);
3567 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
3568 SetLastError(ERROR_INVALID_PARAMETER);
3569 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
3570 SetLastError(ERROR_INVALID_PARAMETER);
3571 else
3572 {
3573 SP_DEVINSTALL_PARAMS_W InstallParams;
3574 BOOL Result;
3575
3576 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
3577 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3578 if (!Result)
3579 goto done;
3580
3581 if (ClassInstallParams)
3582 {
3583 /* Check parameters in ClassInstallParams */
3584 if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE
3585 || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0]))
3586 {
3587 SetLastError(ERROR_INVALID_USER_BUFFER);
3588 goto done;
3589 }
3590 else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL)
3591 {
3592 FIXME("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction);
3593 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3594 goto done;
3595 }
3596 ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize);
3597 if (!ret)
3598 goto done;
3599 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
3600 }
3601 else
3602 {
3603 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
3604 }
3605
3606 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3607 }
3608
3609 done:
3610 TRACE("Returning %d\n", ret);
3611 return ret;
3612 }
3613
3614 static BOOL
3615 PropertyChangeHandler(
3616 IN HDEVINFO DeviceInfoSet,
3617 IN PSP_DEVINFO_DATA DeviceInfoData,
3618 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3619 IN DWORD ClassInstallParamsSize)
3620 {
3621 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
3622 BOOL ret = FALSE;
3623
3624 if (!DeviceInfoData)
3625 SetLastError(ERROR_INVALID_PARAMETER);
3626 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
3627 SetLastError(ERROR_INVALID_PARAMETER);
3628 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
3629 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
3630 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
3631 SetLastError(ERROR_INVALID_FLAGS);
3632 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
3633 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3634 SetLastError(ERROR_INVALID_FLAGS);
3635 else if (PropChangeParams
3636 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
3637 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3638 SetLastError(ERROR_INVALID_USER_BUFFER);
3639 else
3640 {
3641 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
3642 if (!DeviceInfoData)
3643 {
3644 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
3645 CurrentPropChangeParams = &list->ClassInstallParams.PropChange;
3646 }
3647 else
3648 {
3649 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
3650 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange;
3651 }
3652 if (*CurrentPropChangeParams)
3653 {
3654 MyFree(*CurrentPropChangeParams);
3655 *CurrentPropChangeParams = NULL;
3656 }
3657 if (PropChangeParams)