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