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