Fully implement SetupDiGetDriverInfoDetailW
[reactos.git] / reactos / dll / win32 / setupapi / devinst.c
1 /*
2 * SetupAPI device installer
3 *
4 * Copyright 2000 Andreas Mohr for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "setupapi_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
25
26 /* Unicode constants */
27 static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0};
28 static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
29 static const WCHAR Class[] = {'C','l','a','s','s',0};
30 static const WCHAR ClassInstall32[] = {'C','l','a','s','s','I','n','s','t','a','l','l','3','2',0};
31 static const WCHAR Control[] = {'C','o','n','t','r','o','l',0};
32 static const WCHAR DeviceInstance[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
33 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
34 static const WCHAR DotHW[] = {'.','H','W',0};
35 static const WCHAR DotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0};
36 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
37 static const WCHAR InterfaceInstall32[] = {'I','n','t','e','r','f','a','c','e','I','n','s','t','a','l','l','3','2',0};
38 static const WCHAR Linked[] = {'L','i','n','k','e','d',0};
39 static const WCHAR SymbolicLink[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
40 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
41
42 static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
43 static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
44 static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
45 static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
46 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[] = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
47
48 static const WCHAR INF_MANUFACTURER[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
49 static const WCHAR INF_PROVIDER[] = {'P','r','o','v','i','d','e','r',0};
50 static const WCHAR INF_DRIVER_VER[] = {'D','r','i','v','e','r','V','e','r',0};
51
52 typedef DWORD
53 (CALLBACK* CLASS_INSTALL_PROC) (
54 IN DI_FUNCTION InstallFunction,
55 IN HDEVINFO DeviceInfoSet,
56 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
57 typedef BOOL
58 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
59 IN HDEVINFO DeviceInfoSet,
60 IN OUT PSP_DEVINFO_DATA DeviceInfoData);
61 typedef DWORD
62 (CALLBACK* COINSTALLER_PROC) (
63 IN DI_FUNCTION InstallFunction,
64 IN HDEVINFO DeviceInfoSet,
65 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
66 IN OUT PCOINSTALLER_CONTEXT_DATA Context);
67 typedef BOOL
68 (WINAPI* PROPERTY_PAGE_PROVIDER) (
69 IN PSP_PROPSHEETPAGE_REQUEST PropPageRequest,
70 IN LPFNADDPROPSHEETPAGE fAddFunc,
71 IN LPARAM lParam);
72 typedef BOOL
73 (*UPDATE_CLASS_PARAM_HANDLER) (
74 IN HDEVINFO DeviceInfoSet,
75 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
76 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
77 IN DWORD ClassInstallParamsSize);
78
79 struct CoInstallerElement
80 {
81 LIST_ENTRY ListEntry;
82
83 HMODULE Module;
84 COINSTALLER_PROC Function;
85 BOOL DoPostProcessing;
86 PVOID PrivateData;
87 };
88
89 static BOOL
90 PropertyChangeHandler(
91 IN HDEVINFO DeviceInfoSet,
92 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
93 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
94 IN DWORD ClassInstallParamsSize);
95
96 static UPDATE_CLASS_PARAM_HANDLER UpdateClassInstallParamHandlers[] = {
97 NULL, /* DIF_SELECTDEVICE */
98 NULL, /* DIF_INSTALLDEVICE */
99 NULL, /* DIF_ASSIGNRESOURCES */
100 NULL, /* DIF_PROPERTIES */
101 NULL, /* DIF_REMOVE */
102 NULL, /* DIF_FIRSTTIMESETUP */
103 NULL, /* DIF_FOUNDDEVICE */
104 NULL, /* DIF_SELECTCLASSDRIVERS */
105 NULL, /* DIF_VALIDATECLASSDRIVERS */
106 NULL, /* DIF_INSTALLCLASSDRIVERS */
107 NULL, /* DIF_CALCDISKSPACE */
108 NULL, /* DIF_DESTROYPRIVATEDATA */
109 NULL, /* DIF_VALIDATEDRIVER */
110 NULL, /* DIF_MOVEDEVICE */
111 NULL, /* DIF_DETECT */
112 NULL, /* DIF_INSTALLWIZARD */
113 NULL, /* DIF_DESTROYWIZARDDATA */
114 PropertyChangeHandler, /* DIF_PROPERTYCHANGE */
115 NULL, /* DIF_ENABLECLASS */
116 NULL, /* DIF_DETECTVERIFY */
117 NULL, /* DIF_INSTALLDEVICEFILES */
118 NULL, /* DIF_UNREMOVE */
119 NULL, /* DIF_SELECTBESTCOMPATDRV */
120 NULL, /* DIF_ALLOW_INSTALL */
121 NULL, /* DIF_REGISTERDEVICE */
122 NULL, /* DIF_NEWDEVICEWIZARD_PRESELECT */
123 NULL, /* DIF_NEWDEVICEWIZARD_SELECT */
124 NULL, /* DIF_NEWDEVICEWIZARD_PREANALYZE */
125 NULL, /* DIF_NEWDEVICEWIZARD_POSTANALYZE */
126 NULL, /* DIF_NEWDEVICEWIZARD_FINISHINSTALL */
127 NULL, /* DIF_UNUSED1 */
128 NULL, /* DIF_INSTALLINTERFACES */
129 NULL, /* DIF_DETECTCANCEL */
130 NULL, /* DIF_REGISTER_COINSTALLERS */
131 NULL, /* DIF_ADDPROPERTYPAGE_ADVANCED */
132 NULL, /* DIF_ADDPROPERTYPAGE_BASIC */
133 NULL, /* DIF_RESERVED1 */
134 NULL, /* DIF_TROUBLESHOOTER */
135 NULL, /* DIF_POWERMESSAGEWAKE */
136 NULL, /* DIF_ADDREMOTEPROPERTYPAGE_ADVANCED */
137 NULL, /* DIF_UPDATEDRIVER_UI */
138 NULL /* DIF_RESERVED2 */
139 };
140
141 /***********************************************************************
142 * SetupDiBuildClassInfoList (SETUPAPI.@)
143 */
144 BOOL WINAPI SetupDiBuildClassInfoList(
145 DWORD Flags,
146 LPGUID ClassGuidList,
147 DWORD ClassGuidListSize,
148 PDWORD RequiredSize)
149 {
150 TRACE("\n");
151 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
152 ClassGuidListSize, RequiredSize,
153 NULL, NULL);
154 }
155
156 /***********************************************************************
157 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
158 */
159 BOOL WINAPI SetupDiBuildClassInfoListExA(
160 DWORD Flags,
161 LPGUID ClassGuidList,
162 DWORD ClassGuidListSize,
163 PDWORD RequiredSize,
164 LPCSTR MachineName,
165 PVOID Reserved)
166 {
167 LPWSTR MachineNameW = NULL;
168 BOOL bResult;
169
170 TRACE("\n");
171
172 if (MachineName)
173 {
174 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
175 if (MachineNameW == NULL) return FALSE;
176 }
177
178 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
179 ClassGuidListSize, RequiredSize,
180 MachineNameW, Reserved);
181
182 if (MachineNameW)
183 MyFree(MachineNameW);
184
185 return bResult;
186 }
187
188 /***********************************************************************
189 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
190 */
191 BOOL WINAPI SetupDiBuildClassInfoListExW(
192 DWORD Flags,
193 LPGUID ClassGuidList,
194 DWORD ClassGuidListSize,
195 PDWORD RequiredSize,
196 LPCWSTR MachineName,
197 PVOID Reserved)
198 {
199 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
200 HKEY hClassesKey;
201 HKEY hClassKey;
202 DWORD dwLength;
203 DWORD dwIndex;
204 LONG lError;
205 DWORD dwGuidListIndex = 0;
206
207 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
208 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
209
210 if (RequiredSize != NULL)
211 *RequiredSize = 0;
212
213 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
214 KEY_ENUMERATE_SUB_KEYS,
215 DIOCR_INSTALLER,
216 MachineName,
217 Reserved);
218 if (hClassesKey == INVALID_HANDLE_VALUE)
219 {
220 return FALSE;
221 }
222
223 for (dwIndex = 0; ; dwIndex++)
224 {
225 dwLength = MAX_GUID_STRING_LEN + 1;
226 lError = RegEnumKeyExW(hClassesKey,
227 dwIndex,
228 szKeyName,
229 &dwLength,
230 NULL,
231 NULL,
232 NULL,
233 NULL);
234 TRACE("RegEnumKeyExW() returns %ld\n", lError);
235 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
236 {
237 TRACE("Key name: %s\n", debugstr_w(szKeyName));
238
239 if (RegOpenKeyExW(hClassesKey,
240 szKeyName,
241 0,
242 KEY_QUERY_VALUE,
243 &hClassKey))
244 {
245 RegCloseKey(hClassesKey);
246 return FALSE;
247 }
248
249 if (!RegQueryValueExW(hClassKey,
250 REGSTR_VAL_NOUSECLASS,
251 NULL,
252 NULL,
253 NULL,
254 NULL))
255 {
256 TRACE("'NoUseClass' value found!\n");
257 RegCloseKey(hClassKey);
258 continue;
259 }
260
261 if ((Flags & DIBCI_NOINSTALLCLASS) &&
262 (!RegQueryValueExW(hClassKey,
263 REGSTR_VAL_NOINSTALLCLASS,
264 NULL,
265 NULL,
266 NULL,
267 NULL)))
268 {
269 TRACE("'NoInstallClass' value found!\n");
270 RegCloseKey(hClassKey);
271 continue;
272 }
273
274 if ((Flags & DIBCI_NODISPLAYCLASS) &&
275 (!RegQueryValueExW(hClassKey,
276 REGSTR_VAL_NODISPLAYCLASS,
277 NULL,
278 NULL,
279 NULL,
280 NULL)))
281 {
282 TRACE("'NoDisplayClass' value found!\n");
283 RegCloseKey(hClassKey);
284 continue;
285 }
286
287 RegCloseKey(hClassKey);
288
289 TRACE("Guid: %s\n", debugstr_w(szKeyName));
290 if (dwGuidListIndex < ClassGuidListSize)
291 {
292 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
293 {
294 szKeyName[37] = 0;
295 }
296 TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
297
298 UuidFromStringW(&szKeyName[1],
299 &ClassGuidList[dwGuidListIndex]);
300 }
301
302 dwGuidListIndex++;
303 }
304
305 if (lError != ERROR_SUCCESS)
306 break;
307 }
308
309 RegCloseKey(hClassesKey);
310
311 if (RequiredSize != NULL)
312 *RequiredSize = dwGuidListIndex;
313
314 if (ClassGuidListSize < dwGuidListIndex)
315 {
316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
317 return FALSE;
318 }
319
320 return TRUE;
321 }
322
323 /***********************************************************************
324 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
325 */
326 BOOL WINAPI SetupDiClassGuidsFromNameA(
327 LPCSTR ClassName,
328 LPGUID ClassGuidList,
329 DWORD ClassGuidListSize,
330 PDWORD RequiredSize)
331 {
332 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
333 ClassGuidListSize, RequiredSize,
334 NULL, NULL);
335 }
336
337 /***********************************************************************
338 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
339 */
340 BOOL WINAPI SetupDiClassGuidsFromNameW(
341 LPCWSTR ClassName,
342 LPGUID ClassGuidList,
343 DWORD ClassGuidListSize,
344 PDWORD RequiredSize)
345 {
346 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
347 ClassGuidListSize, RequiredSize,
348 NULL, NULL);
349 }
350
351 /***********************************************************************
352 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
353 */
354 BOOL WINAPI SetupDiClassGuidsFromNameExA(
355 LPCSTR ClassName,
356 LPGUID ClassGuidList,
357 DWORD ClassGuidListSize,
358 PDWORD RequiredSize,
359 LPCSTR MachineName,
360 PVOID Reserved)
361 {
362 LPWSTR ClassNameW = NULL;
363 LPWSTR MachineNameW = NULL;
364 BOOL bResult;
365
366 TRACE("\n");
367
368 ClassNameW = MultiByteToUnicode(ClassName, CP_ACP);
369 if (ClassNameW == NULL)
370 return FALSE;
371
372 if (MachineNameW)
373 {
374 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
375 if (MachineNameW == NULL)
376 {
377 MyFree(ClassNameW);
378 return FALSE;
379 }
380 }
381
382 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
383 ClassGuidListSize, RequiredSize,
384 MachineNameW, Reserved);
385
386 if (MachineNameW)
387 MyFree(MachineNameW);
388
389 MyFree(ClassNameW);
390
391 return bResult;
392 }
393
394 /***********************************************************************
395 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
396 */
397 BOOL WINAPI SetupDiClassGuidsFromNameExW(
398 LPCWSTR ClassName,
399 LPGUID ClassGuidList,
400 DWORD ClassGuidListSize,
401 PDWORD RequiredSize,
402 LPCWSTR MachineName,
403 PVOID Reserved)
404 {
405 WCHAR szKeyName[MAX_GUID_STRING_LEN + 1];
406 WCHAR szClassName[256];
407 HKEY hClassesKey;
408 HKEY hClassKey;
409 DWORD dwLength;
410 DWORD dwIndex;
411 LONG lError;
412 DWORD dwGuidListIndex = 0;
413
414 TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
415 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
416
417 if (RequiredSize != NULL)
418 *RequiredSize = 0;
419
420 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
421 KEY_ENUMERATE_SUB_KEYS,
422 DIOCR_INSTALLER,
423 MachineName,
424 Reserved);
425 if (hClassesKey == INVALID_HANDLE_VALUE)
426 {
427 return FALSE;
428 }
429
430 for (dwIndex = 0; ; dwIndex++)
431 {
432 dwLength = MAX_GUID_STRING_LEN + 1;
433 lError = RegEnumKeyExW(hClassesKey,
434 dwIndex,
435 szKeyName,
436 &dwLength,
437 NULL,
438 NULL,
439 NULL,
440 NULL);
441 TRACE("RegEnumKeyExW() returns %ld\n", lError);
442 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
443 {
444 TRACE("Key name: %s\n", debugstr_w(szKeyName));
445
446 if (RegOpenKeyExW(hClassesKey,
447 szKeyName,
448 0,
449 KEY_QUERY_VALUE,
450 &hClassKey))
451 {
452 RegCloseKey(hClassesKey);
453 return FALSE;
454 }
455
456 dwLength = 256 * sizeof(WCHAR);
457 if (!RegQueryValueExW(hClassKey,
458 Class,
459 NULL,
460 NULL,
461 (LPBYTE)szClassName,
462 &dwLength))
463 {
464 TRACE("Class name: %s\n", debugstr_w(szClassName));
465
466 if (strcmpiW(szClassName, ClassName) == 0)
467 {
468 TRACE("Found matching class name\n");
469
470 TRACE("Guid: %s\n", debugstr_w(szKeyName));
471 if (dwGuidListIndex < ClassGuidListSize)
472 {
473 if (szKeyName[0] == L'{' && szKeyName[37] == L'}')
474 {
475 szKeyName[37] = 0;
476 }
477 TRACE("Guid: %s\n", debugstr_w(&szKeyName[1]));
478
479 UuidFromStringW(&szKeyName[1],
480 &ClassGuidList[dwGuidListIndex]);
481 }
482
483 dwGuidListIndex++;
484 }
485 }
486
487 RegCloseKey(hClassKey);
488 }
489
490 if (lError != ERROR_SUCCESS)
491 break;
492 }
493
494 RegCloseKey(hClassesKey);
495
496 if (RequiredSize != NULL)
497 *RequiredSize = dwGuidListIndex;
498
499 if (ClassGuidListSize < dwGuidListIndex)
500 {
501 SetLastError(ERROR_INSUFFICIENT_BUFFER);
502 return FALSE;
503 }
504
505 return TRUE;
506 }
507
508 /***********************************************************************
509 * SetupDiClassNameFromGuidA (SETUPAPI.@)
510 */
511 BOOL WINAPI SetupDiClassNameFromGuidA(
512 const GUID* ClassGuid,
513 PSTR ClassName,
514 DWORD ClassNameSize,
515 PDWORD RequiredSize)
516 {
517 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
518 ClassNameSize, RequiredSize,
519 NULL, NULL);
520 }
521
522 /***********************************************************************
523 * SetupDiClassNameFromGuidW (SETUPAPI.@)
524 */
525 BOOL WINAPI SetupDiClassNameFromGuidW(
526 const GUID* ClassGuid,
527 PWSTR ClassName,
528 DWORD ClassNameSize,
529 PDWORD RequiredSize)
530 {
531 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
532 ClassNameSize, RequiredSize,
533 NULL, NULL);
534 }
535
536 /***********************************************************************
537 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
538 */
539 BOOL WINAPI SetupDiClassNameFromGuidExA(
540 const GUID* ClassGuid,
541 PSTR ClassName,
542 DWORD ClassNameSize,
543 PDWORD RequiredSize,
544 PCSTR MachineName,
545 PVOID Reserved)
546 {
547 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
548 LPWSTR MachineNameW = NULL;
549 BOOL ret;
550
551 if (MachineName)
552 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
553 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
554 NULL, MachineNameW, Reserved);
555 if (ret)
556 {
557 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
558 ClassNameSize, NULL, NULL);
559
560 if (!ClassNameSize && RequiredSize)
561 *RequiredSize = len;
562 }
563 MyFree(MachineNameW);
564 return ret;
565 }
566
567 /***********************************************************************
568 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
569 */
570 BOOL WINAPI SetupDiClassNameFromGuidExW(
571 const GUID* ClassGuid,
572 PWSTR ClassName,
573 DWORD ClassNameSize,
574 PDWORD RequiredSize,
575 PCWSTR MachineName,
576 PVOID Reserved)
577 {
578 HKEY hKey;
579 DWORD dwLength;
580 LONG rc;
581
582 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
583 ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
584
585 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
586 KEY_QUERY_VALUE,
587 DIOCR_INSTALLER,
588 MachineName,
589 Reserved);
590 if (hKey == INVALID_HANDLE_VALUE)
591 {
592 return FALSE;
593 }
594
595 if (RequiredSize != NULL)
596 {
597 dwLength = 0;
598 rc = RegQueryValueExW(hKey,
599 Class,
600 NULL,
601 NULL,
602 NULL,
603 &dwLength);
604 if (rc != ERROR_SUCCESS)
605 {
606 SetLastError(rc);
607 RegCloseKey(hKey);
608 return FALSE;
609 }
610
611 *RequiredSize = dwLength / sizeof(WCHAR);
612 }
613
614 dwLength = ClassNameSize * sizeof(WCHAR);
615 rc = RegQueryValueExW(hKey,
616 Class,
617 NULL,
618 NULL,
619 (LPBYTE)ClassName,
620 &dwLength);
621 if (rc != ERROR_SUCCESS)
622 {
623 SetLastError(rc);
624 RegCloseKey(hKey);
625 return FALSE;
626 }
627
628 RegCloseKey(hKey);
629
630 return TRUE;
631 }
632
633 /***********************************************************************
634 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
635 */
636 HDEVINFO WINAPI
637 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
638 HWND hwndParent)
639 {
640 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
641 }
642
643 /***********************************************************************
644 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
645 */
646 HDEVINFO WINAPI
647 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
648 HWND hwndParent,
649 PCSTR MachineName,
650 PVOID Reserved)
651 {
652 LPWSTR MachineNameW = NULL;
653 HDEVINFO hDevInfo;
654
655 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
656 debugstr_a(MachineName), Reserved);
657
658 if (MachineName)
659 {
660 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
661 if (MachineNameW == NULL)
662 return (HDEVINFO)INVALID_HANDLE_VALUE;
663 }
664
665 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
666 MachineNameW, Reserved);
667
668 if (MachineNameW)
669 MyFree(MachineNameW);
670
671 return hDevInfo;
672 }
673
674 static DWORD
675 GetErrorCodeFromCrCode(const IN CONFIGRET cr)
676 {
677 switch (cr)
678 {
679 case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
680 case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
681 case CR_SUCCESS: return ERROR_SUCCESS;
682 default:
683 /* FIXME */
684 return ERROR_GEN_FAILURE;
685 }
686
687 /* Does not happen */
688 }
689
690 /***********************************************************************
691 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
692 */
693 HDEVINFO WINAPI
694 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
695 HWND hwndParent,
696 PCWSTR MachineName,
697 PVOID Reserved)
698 {
699 struct DeviceInfoSet *list;
700 LPWSTR UNCServerName = NULL;
701 DWORD size;
702 DWORD rc;
703 //CONFIGRET cr;
704 HDEVINFO ret = (HDEVINFO)INVALID_HANDLE_VALUE;;
705
706 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
707 debugstr_w(MachineName), Reserved);
708
709 size = FIELD_OFFSET(struct DeviceInfoSet, szData);
710 if (MachineName)
711 size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
712 list = HeapAlloc(GetProcessHeap(), 0, size);
713 if (!list)
714 {
715 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
716 goto cleanup;
717 }
718 memset(list, 0, sizeof(struct DeviceInfoSet));
719
720 list->magic = SETUP_DEV_INFO_SET_MAGIC;
721 memcpy(
722 &list->ClassGuid,
723 ClassGuid ? ClassGuid : &GUID_NULL,
724 sizeof(list->ClassGuid));
725 list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
726 list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
727 list->InstallParams.hwndParent = hwndParent;
728 if (MachineName)
729 {
730 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
731 if (rc != ERROR_SUCCESS)
732 {
733 SetLastError(rc);
734 goto cleanup;
735 }
736 UNCServerName = HeapAlloc(GetProcessHeap(), 0, (strlenW(MachineName) + 3) * sizeof(WCHAR));
737 if (!UNCServerName)
738 {
739 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
740 goto cleanup;
741 }
742
743 strcpyW(UNCServerName + 2, MachineName);
744 list->szData[0] = list->szData[1] = '\\';
745 strcpyW(list->szData + 2, MachineName);
746 list->MachineName = list->szData;
747 }
748 else
749 {
750 DWORD Size = MAX_PATH;
751 list->HKLM = HKEY_LOCAL_MACHINE;
752 UNCServerName = HeapAlloc(GetProcessHeap(), 0, (MAX_PATH + 2) * sizeof(WCHAR));
753 if (!UNCServerName)
754 {
755 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
756 goto cleanup;
757 }
758 if (!GetComputerNameW(UNCServerName + 2, &Size))
759 goto cleanup;
760 list->MachineName = NULL;
761 }
762 #if 0
763 UNCServerName[0] = UNCServerName[1] = '\\';
764 cr = CM_Connect_MachineW(UNCServerName, &list->hMachine);
765 if (cr != CR_SUCCESS)
766 {
767 SetLastError(GetErrorCodeFromCrCode(cr));
768 goto cleanup;
769 }
770 #endif
771 InitializeListHead(&list->DriverListHead);
772 InitializeListHead(&list->ListHead);
773
774 ret = (HDEVINFO)list;
775
776 cleanup:
777 if (ret == INVALID_HANDLE_VALUE)
778 {
779 if (list && list->HKLM != 0 && list->HKLM != HKEY_LOCAL_MACHINE)
780 RegCloseKey(list->HKLM);
781 HeapFree(GetProcessHeap(), 0, list);
782 }
783 HeapFree(GetProcessHeap(), 0, UNCServerName);
784 return ret;
785 }
786
787 /***********************************************************************
788 * SetupDiEnumDeviceInfo (SETUPAPI.@)
789 */
790 BOOL WINAPI SetupDiEnumDeviceInfo(
791 HDEVINFO DeviceInfoSet,
792 DWORD MemberIndex,
793 PSP_DEVINFO_DATA DeviceInfoData)
794 {
795 BOOL ret = FALSE;
796
797 TRACE("%p, 0x%08lx, %p\n", DeviceInfoSet, MemberIndex, DeviceInfoData);
798 if (!DeviceInfoData)
799 SetLastError(ERROR_INVALID_PARAMETER);
800 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
801 {
802 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
803
804 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
805 SetLastError(ERROR_INVALID_HANDLE);
806 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
807 SetLastError(ERROR_INVALID_USER_BUFFER);
808 else
809 {
810 PLIST_ENTRY ItemList = list->ListHead.Flink;
811 while (ItemList != &list->ListHead && MemberIndex-- > 0)
812 ItemList = ItemList->Flink;
813 if (ItemList == &list->ListHead)
814 SetLastError(ERROR_NO_MORE_ITEMS);
815 else
816 {
817 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
818 memcpy(&DeviceInfoData->ClassGuid,
819 &DevInfo->ClassGuid,
820 sizeof(GUID));
821 DeviceInfoData->DevInst = DevInfo->dnDevInst;
822 DeviceInfoData->Reserved = (ULONG_PTR)DevInfo;
823 ret = TRUE;
824 }
825 }
826 }
827 else
828 SetLastError(ERROR_INVALID_HANDLE);
829 return ret;
830 }
831
832 /***********************************************************************
833 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
834 */
835 BOOL WINAPI
836 SetupDiGetActualSectionToInstallA(
837 IN HINF InfHandle,
838 IN PCSTR InfSectionName,
839 OUT PSTR InfSectionWithExt OPTIONAL,
840 IN DWORD InfSectionWithExtSize,
841 OUT PDWORD RequiredSize OPTIONAL,
842 OUT PSTR *Extension OPTIONAL)
843 {
844 return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
845 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
846 Extension, NULL);
847 }
848
849 /***********************************************************************
850 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
851 */
852 BOOL WINAPI
853 SetupDiGetActualSectionToInstallW(
854 IN HINF InfHandle,
855 IN PCWSTR InfSectionName,
856 OUT PWSTR InfSectionWithExt OPTIONAL,
857 IN DWORD InfSectionWithExtSize,
858 OUT PDWORD RequiredSize OPTIONAL,
859 OUT PWSTR *Extension OPTIONAL)
860 {
861 return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
862 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
863 Extension, NULL);
864 }
865
866 /***********************************************************************
867 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
868 */
869 BOOL WINAPI
870 SetupDiGetActualSectionToInstallExA(
871 IN HINF InfHandle,
872 IN PCSTR InfSectionName,
873 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
874 OUT PSTR InfSectionWithExt OPTIONAL,
875 IN DWORD InfSectionWithExtSize,
876 OUT PDWORD RequiredSize OPTIONAL,
877 OUT PSTR* Extension OPTIONAL,
878 IN PVOID Reserved)
879 {
880 LPWSTR InfSectionNameW = NULL;
881 LPWSTR InfSectionWithExtW = NULL;
882 PWSTR ExtensionW;
883 BOOL bResult = FALSE;
884
885 TRACE("\n");
886
887 if (InfSectionName)
888 {
889 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
890 if (InfSectionNameW == NULL)
891 goto cleanup;
892 }
893 if (InfSectionWithExt)
894 {
895 InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
896 if (InfSectionWithExtW == NULL)
897 goto cleanup;
898 }
899
900 bResult = SetupDiGetActualSectionToInstallExW(
901 InfHandle, InfSectionNameW, AlternatePlatformInfo,
902 InfSectionWithExt ? InfSectionWithExtW : NULL,
903 InfSectionWithExtSize,
904 RequiredSize,
905 Extension ? &ExtensionW : NULL,
906 Reserved);
907
908 if (bResult && InfSectionWithExt)
909 {
910 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
911 InfSectionWithExtSize, NULL, NULL) != 0;
912 }
913 if (bResult && Extension)
914 {
915 if (ExtensionW == NULL)
916 *Extension = NULL;
917 else
918 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
919 }
920
921 cleanup:
922 MyFree(InfSectionNameW);
923 MyFree(InfSectionWithExtW);
924
925 return bResult;
926 }
927
928 /***********************************************************************
929 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
930 */
931 BOOL WINAPI
932 SetupDiGetActualSectionToInstallExW(
933 IN HINF InfHandle,
934 IN PCWSTR InfSectionName,
935 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
936 OUT PWSTR InfSectionWithExt OPTIONAL,
937 IN DWORD InfSectionWithExtSize,
938 OUT PDWORD RequiredSize OPTIONAL,
939 OUT PWSTR* Extension OPTIONAL,
940 IN PVOID Reserved)
941 {
942 BOOL ret = FALSE;
943
944 TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
945 AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
946 RequiredSize, Extension, Reserved);
947
948 if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
949 SetLastError(ERROR_INVALID_HANDLE);
950 else if (!InfSectionName)
951 SetLastError(ERROR_INVALID_PARAMETER);
952 else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
953 SetLastError(ERROR_INVALID_USER_BUFFER);
954 else if (Reserved != NULL)
955 SetLastError(ERROR_INVALID_PARAMETER);
956 else
957 {
958 static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
959 PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
960 LPCWSTR pExtensionPlatform, pExtensionArchitecture;
961 WCHAR SectionName[LINE_LEN + 1];
962 LONG lLineCount = -1;
963 DWORD dwFullLength;
964
965 /* Fill platform info if needed */
966 if (AlternatePlatformInfo)
967 pPlatformInfo = AlternatePlatformInfo;
968 else if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
969 {
970 /* That's the first time we go here. We need to fill in the structure */
971 OSVERSIONINFO VersionInfo;
972 SYSTEM_INFO SystemInfo;
973 VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
974 ret = GetVersionEx(&VersionInfo);
975 if (!ret)
976 goto done;
977 GetSystemInfo(&SystemInfo);
978 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
979 CurrentPlatform.Platform = VersionInfo.dwPlatformId;
980 CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
981 CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
982 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
983 CurrentPlatform.Reserved = 0;
984 }
985
986 static const WCHAR ExtensionPlatformNone[] = {'.',0};
987 static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
988 static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
989
990 static const WCHAR ExtensionArchitectureNone[] = {0};
991 static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
992 static const WCHAR ExtensionArchitectureamd64[] = {'a','m','d','6','4',0};
993 static const WCHAR ExtensionArchitectureia64[] = {'i','a','6','4',0};
994 static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
995 static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
996 static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
997
998 /* Set various extensions values */
999 switch (pPlatformInfo->Platform)
1000 {
1001 case VER_PLATFORM_WIN32_WINDOWS:
1002 pExtensionPlatform = ExtensionPlatformWindows;
1003 break;
1004 case VER_PLATFORM_WIN32_NT:
1005 pExtensionPlatform = ExtensionPlatformNT;
1006 break;
1007 default:
1008 ERR("Unkown platform 0x%lx\n", pPlatformInfo->Platform);
1009 pExtensionPlatform = ExtensionPlatformNone;
1010 break;
1011 }
1012 switch (pPlatformInfo->ProcessorArchitecture)
1013 {
1014 case PROCESSOR_ARCHITECTURE_ALPHA:
1015 pExtensionArchitecture = ExtensionArchitecturealpha;
1016 break;
1017 case PROCESSOR_ARCHITECTURE_AMD64:
1018 pExtensionArchitecture = ExtensionArchitectureamd64;
1019 break;
1020 case PROCESSOR_ARCHITECTURE_IA64:
1021 pExtensionArchitecture = ExtensionArchitectureia64;
1022 break;
1023 case PROCESSOR_ARCHITECTURE_INTEL:
1024 pExtensionArchitecture = ExtensionArchitecturex86;
1025 break;
1026 case PROCESSOR_ARCHITECTURE_MIPS:
1027 pExtensionArchitecture = ExtensionArchitecturemips;
1028 break;
1029 case PROCESSOR_ARCHITECTURE_PPC:
1030 pExtensionArchitecture = ExtensionArchitectureppc;
1031 break;
1032 default:
1033 ERR("Unknown processor architecture 0x%x\n", pPlatformInfo->ProcessorArchitecture);
1034 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1035 pExtensionArchitecture = ExtensionArchitectureNone;
1036 break;
1037 }
1038
1039 static const WCHAR FormatPlatformArchitectureMajorMinor[] = {'%','s','%','s','%','s','.','%','l','u','.','%','l','u',0};
1040 static const WCHAR FormatPlatformMajorMinor[] = {'%','s','%','s','.','%','l','u','.','%','l','u',0};
1041 static const WCHAR FormatPlatformArchitectureMajor[] = {'%','s','%','s','%','s','.','%','l','u',0};
1042 static const WCHAR FormatPlatformMajor[] = {'%','s','%','s','.','%','l','u',0};
1043 static const WCHAR FormatPlatformArchitecture[] = {'%','s','%','s','%','s',0};
1044 static const WCHAR FormatPlatform[] = {'%','s','%','s',0};
1045 static const WCHAR FormatNone[] = {'%','s',0};
1046
1047 SectionName[LINE_LEN] = UNICODE_NULL;
1048
1049 /* Test with platform.architecture.major.minor extension */
1050 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitectureMajorMinor, InfSectionName,
1051 pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
1052 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1053 if (lLineCount != -1) goto sectionfound;
1054
1055 /* Test with platform.major.minor extension */
1056 snprintfW(SectionName, LINE_LEN, FormatPlatformMajorMinor, InfSectionName,
1057 pExtensionPlatform, pPlatformInfo->MajorVersion, pPlatformInfo->MinorVersion);
1058 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1059 if (lLineCount != -1) goto sectionfound;
1060
1061 /* Test with platform.architecture.major extension */
1062 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitectureMajor, InfSectionName,
1063 pExtensionPlatform, pExtensionArchitecture, pPlatformInfo->MajorVersion);
1064 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1065 if (lLineCount != -1) goto sectionfound;
1066
1067 /* Test with platform.major extension */
1068 snprintfW(SectionName, LINE_LEN, FormatPlatformMajor, InfSectionName,
1069 pExtensionPlatform, pPlatformInfo->MajorVersion);
1070 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1071 if (lLineCount != -1) goto sectionfound;
1072
1073 /* Test with platform.architecture extension */
1074 snprintfW(SectionName, LINE_LEN, FormatPlatformArchitecture, InfSectionName,
1075 pExtensionPlatform, pExtensionArchitecture);
1076 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1077 if (lLineCount != -1) goto sectionfound;
1078
1079 /* Test with platform extension */
1080 snprintfW(SectionName, LINE_LEN, FormatPlatform, InfSectionName,
1081 pExtensionPlatform);
1082 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1083 if (lLineCount != -1) goto sectionfound;
1084
1085 /* Test without extension */
1086 snprintfW(SectionName, LINE_LEN, FormatNone, InfSectionName);
1087 lLineCount = SetupGetLineCountW(InfHandle, SectionName);
1088 if (lLineCount != -1) goto sectionfound;
1089
1090 /* No appropriate section found */
1091 SetLastError(ERROR_INVALID_PARAMETER);
1092 goto done;
1093
1094 sectionfound:
1095 dwFullLength = lstrlenW(SectionName);
1096 if (InfSectionWithExt != NULL && InfSectionWithExtSize != 0)
1097 {
1098 if (InfSectionWithExtSize < (dwFullLength + 1))
1099 {
1100 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1101 goto done;
1102 }
1103
1104 lstrcpyW(InfSectionWithExt, SectionName);
1105 if (Extension != NULL)
1106 {
1107 DWORD dwLength = lstrlenW(SectionName);
1108 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
1109 }
1110 }
1111
1112 if (RequiredSize != NULL)
1113 *RequiredSize = dwFullLength + 1;
1114
1115 ret = TRUE;
1116 }
1117
1118 done:
1119 TRACE("Returning %d\n", ret);
1120 return ret;
1121 }
1122
1123
1124 /***********************************************************************
1125 * SetupDiGetClassDescriptionA (SETUPAPI.@)
1126 */
1127 BOOL WINAPI SetupDiGetClassDescriptionA(
1128 const GUID* ClassGuid,
1129 PSTR ClassDescription,
1130 DWORD ClassDescriptionSize,
1131 PDWORD RequiredSize)
1132 {
1133 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
1134 ClassDescriptionSize,
1135 RequiredSize, NULL, NULL);
1136 }
1137
1138 /***********************************************************************
1139 * SetupDiGetClassDescriptionW (SETUPAPI.@)
1140 */
1141 BOOL WINAPI SetupDiGetClassDescriptionW(
1142 const GUID* ClassGuid,
1143 PWSTR ClassDescription,
1144 DWORD ClassDescriptionSize,
1145 PDWORD RequiredSize)
1146 {
1147 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
1148 ClassDescriptionSize,
1149 RequiredSize, NULL, NULL);
1150 }
1151
1152 /***********************************************************************
1153 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
1154 */
1155 BOOL WINAPI SetupDiGetClassDescriptionExA(
1156 const GUID* ClassGuid,
1157 PSTR ClassDescription,
1158 DWORD ClassDescriptionSize,
1159 PDWORD RequiredSize,
1160 PCSTR MachineName,
1161 PVOID Reserved)
1162 {
1163 PWCHAR ClassDescriptionW;
1164 LPWSTR MachineNameW = NULL;
1165 BOOL ret;
1166
1167 TRACE("\n");
1168 if (ClassDescriptionSize > 0)
1169 {
1170 ClassDescriptionW = HeapAlloc(GetProcessHeap(), 0, ClassDescriptionSize * sizeof(WCHAR));
1171 if (!ClassDescriptionW)
1172 {
1173 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1174 ret = FALSE;
1175 goto end;
1176 }
1177 }
1178 else
1179 ClassDescriptionW = NULL;
1180
1181 if (MachineName)
1182 {
1183 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
1184 if (!MachineNameW)
1185 {
1186 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1187 ret = FALSE;
1188 goto end;
1189 }
1190 }
1191
1192 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW, ClassDescriptionSize * sizeof(WCHAR),
1193 NULL, MachineNameW, Reserved);
1194 if (ret)
1195 {
1196 int len = WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
1197 ClassDescriptionSize, NULL, NULL);
1198
1199 if (!ClassDescriptionSize && RequiredSize)
1200 *RequiredSize = len;
1201 }
1202
1203 end:
1204 HeapFree(GetProcessHeap(), 0, ClassDescriptionW);
1205 MyFree(MachineNameW);
1206 return ret;
1207 }
1208
1209 /***********************************************************************
1210 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
1211 */
1212 BOOL WINAPI SetupDiGetClassDescriptionExW(
1213 const GUID* ClassGuid,
1214 PWSTR ClassDescription,
1215 DWORD ClassDescriptionSize,
1216 PDWORD RequiredSize,
1217 PCWSTR MachineName,
1218 PVOID Reserved)
1219 {
1220 HKEY hKey;
1221 DWORD dwLength;
1222
1223 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
1224 ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
1225
1226 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
1227 KEY_QUERY_VALUE,
1228 DIOCR_INSTALLER,
1229 MachineName,
1230 Reserved);
1231 if (hKey == INVALID_HANDLE_VALUE)
1232 {
1233 WARN("SetupDiOpenClassRegKeyExW() failed (Error %lu)\n", GetLastError());
1234 return FALSE;
1235 }
1236
1237 if (RequiredSize != NULL)
1238 {
1239 dwLength = 0;
1240 if (RegQueryValueExW(hKey,
1241 NULL,
1242 NULL,
1243 NULL,
1244 NULL,
1245 &dwLength))
1246 {
1247 RegCloseKey(hKey);
1248 return FALSE;
1249 }
1250
1251 *RequiredSize = dwLength / sizeof(WCHAR);
1252 }
1253
1254 dwLength = ClassDescriptionSize * sizeof(WCHAR);
1255 if (RegQueryValueExW(hKey,
1256 NULL,
1257 NULL,
1258 NULL,
1259 (LPBYTE)ClassDescription,
1260 &dwLength))
1261 {
1262 RegCloseKey(hKey);
1263 return FALSE;
1264 }
1265
1266 RegCloseKey(hKey);
1267
1268 return TRUE;
1269 }
1270
1271 /***********************************************************************
1272 * SetupDiGetClassDevsA (SETUPAPI.@)
1273 */
1274 HDEVINFO WINAPI SetupDiGetClassDevsA(
1275 CONST GUID *class,
1276 LPCSTR enumstr,
1277 HWND parent,
1278 DWORD flags)
1279 {
1280 return SetupDiGetClassDevsExA(class, enumstr, parent,
1281 flags, NULL, NULL, NULL);
1282 }
1283
1284 /***********************************************************************
1285 * SetupDiGetClassDevsW (SETUPAPI.@)
1286 */
1287 HDEVINFO WINAPI SetupDiGetClassDevsW(
1288 CONST GUID *class,
1289 LPCWSTR enumstr,
1290 HWND parent,
1291 DWORD flags)
1292 {
1293 return SetupDiGetClassDevsExW(class, enumstr, parent,
1294 flags, NULL, NULL, NULL);
1295 }
1296
1297 /***********************************************************************
1298 * SetupDiGetClassDevsExA (SETUPAPI.@)
1299 */
1300 HDEVINFO WINAPI SetupDiGetClassDevsExA(
1301 CONST GUID *class,
1302 LPCSTR enumstr,
1303 HWND parent,
1304 DWORD flags,
1305 HDEVINFO deviceset,
1306 LPCSTR machine,
1307 PVOID reserved)
1308 {
1309 HDEVINFO ret;
1310 LPWSTR enumstrW = NULL;
1311 LPWSTR machineW = NULL;
1312
1313 if (enumstr)
1314 {
1315 int len = MultiByteToWideChar(CP_ACP, 0, enumstr, -1, NULL, 0);
1316 enumstrW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1317 if (!enumstrW)
1318 {
1319 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1320 goto end;
1321 }
1322 MultiByteToWideChar(CP_ACP, 0, enumstr, -1, enumstrW, len);
1323 }
1324 if (machine)
1325 {
1326 int len = MultiByteToWideChar(CP_ACP, 0, machine, -1, NULL, 0);
1327 machineW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1328 if (!machineW)
1329 {
1330 ret = (HDEVINFO)INVALID_HANDLE_VALUE;
1331 goto end;
1332 }
1333 MultiByteToWideChar(CP_ACP, 0, machine, -1, machineW, len);
1334 }
1335 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset, machineW, reserved);
1336
1337 end:
1338 HeapFree(GetProcessHeap(), 0, enumstrW);
1339 HeapFree(GetProcessHeap(), 0, machineW);
1340 return ret;
1341 }
1342
1343 static BOOL
1344 CreateDeviceInfoElement(
1345 IN struct DeviceInfoSet *list,
1346 IN LPCWSTR InstancePath,
1347 IN LPCGUID pClassGuid,
1348 OUT struct DeviceInfoElement **pDeviceInfo)
1349 {
1350 DWORD size;
1351 CONFIGRET cr;
1352 struct DeviceInfoElement *deviceInfo;
1353
1354 *pDeviceInfo = NULL;
1355
1356 size = FIELD_OFFSET(struct DeviceInfoElement, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
1357 deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
1358 if (!deviceInfo)
1359 {
1360 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1361 return FALSE;
1362 }
1363 memset(deviceInfo, 0, size);
1364
1365 cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
1366 if (cr != CR_SUCCESS)
1367 {
1368 SetLastError(GetErrorCodeFromCrCode(cr));
1369 return FALSE;
1370 }
1371
1372 deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1373 strcpyW(deviceInfo->Data, InstancePath);
1374 deviceInfo->DeviceName = deviceInfo->Data;
1375 deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
1376 deviceInfo->DeviceDescription = NULL;
1377 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
1378 deviceInfo->CreationFlags = 0;
1379 InitializeListHead(&deviceInfo->DriverListHead);
1380 InitializeListHead(&deviceInfo->InterfaceListHead);
1381
1382 *pDeviceInfo = deviceInfo;
1383 return TRUE;
1384 }
1385
1386 static BOOL
1387 CreateDeviceInterface(
1388 IN struct DeviceInfoElement* deviceInfo,
1389 IN LPCWSTR SymbolicLink,
1390 IN LPCGUID pInterfaceGuid,
1391 OUT struct DeviceInterface **pDeviceInterface)
1392 {
1393 struct DeviceInterface *deviceInterface;
1394
1395 *pDeviceInterface = NULL;
1396
1397 deviceInterface = HeapAlloc(GetProcessHeap(), 0,
1398 FIELD_OFFSET(struct DeviceInterface, SymbolicLink) + (strlenW(SymbolicLink) + 1) * sizeof(WCHAR));
1399 if (!deviceInterface)
1400 {
1401 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1402 return FALSE;
1403 }
1404 deviceInterface->DeviceInfo = deviceInfo;
1405 strcpyW(deviceInterface->SymbolicLink, SymbolicLink);
1406 deviceInterface->Flags = 0; /* FIXME */
1407 memcpy(&deviceInterface->InterfaceClassGuid, pInterfaceGuid, sizeof(GUID));
1408
1409 *pDeviceInterface = deviceInterface;
1410 return TRUE;
1411 }
1412
1413 static LONG SETUP_CreateDevListFromEnumerator(
1414 struct DeviceInfoSet *list,
1415 LPCGUID pClassGuid OPTIONAL,
1416 LPCWSTR Enumerator,
1417 HKEY hEnumeratorKey) /* handle to Enumerator registry key */
1418 {
1419 HKEY hDeviceIdKey, hInstanceIdKey;
1420 WCHAR KeyBuffer[MAX_PATH];
1421 WCHAR InstancePath[MAX_PATH];
1422 LPWSTR pEndOfInstancePath; /* Pointer into InstancePath buffer */
1423 struct DeviceInfoElement *deviceInfo;
1424 DWORD i = 0, j;
1425 DWORD dwLength, dwRegType;
1426 DWORD rc;
1427
1428 /* Enumerate device IDs (subkeys of hEnumeratorKey) */
1429 while (TRUE)
1430 {
1431 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1432 rc = RegEnumKeyExW(hEnumeratorKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1433 if (rc == ERROR_NO_MORE_ITEMS)
1434 break;
1435 if (rc != ERROR_SUCCESS)
1436 return rc;
1437 i++;
1438
1439 /* Open device id sub key */
1440 rc = RegOpenKeyExW(hEnumeratorKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hDeviceIdKey);
1441 if (rc != ERROR_SUCCESS)
1442 return rc;
1443 strcpyW(InstancePath, Enumerator);
1444 strcatW(InstancePath, L"\\");
1445 strcatW(InstancePath, KeyBuffer);
1446 strcatW(InstancePath, L"\\");
1447 pEndOfInstancePath = &InstancePath[strlenW(InstancePath)];
1448
1449 /* Enumerate instance IDs (subkeys of hDeviceIdKey) */
1450 j = 0;
1451 while (TRUE)
1452 {
1453 GUID KeyGuid;
1454
1455 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1456 rc = RegEnumKeyExW(hDeviceIdKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1457 if (rc == ERROR_NO_MORE_ITEMS)
1458 break;
1459 if (rc != ERROR_SUCCESS)
1460 {
1461 RegCloseKey(hDeviceIdKey);
1462 return rc;
1463 }
1464 j++;
1465
1466 /* Open instance id sub key */
1467 rc = RegOpenKeyExW(hDeviceIdKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hInstanceIdKey);
1468 if (rc != ERROR_SUCCESS)
1469 {
1470 RegCloseKey(hDeviceIdKey);
1471 return rc;
1472 }
1473 *pEndOfInstancePath = '\0';
1474 strcatW(InstancePath, KeyBuffer);
1475
1476 /* Read ClassGUID value */
1477 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1478 rc = RegQueryValueExW(hInstanceIdKey, ClassGUID, NULL, &dwRegType, (LPBYTE)KeyBuffer, &dwLength);
1479 RegCloseKey(hInstanceIdKey);
1480 if (rc == ERROR_FILE_NOT_FOUND)
1481 {
1482 if (pClassGuid)
1483 /* Skip this bad entry as we can't verify it */
1484 continue;
1485 /* Set a default GUID for this device */
1486 memcpy(&KeyGuid, &GUID_NULL, sizeof(GUID));
1487 }
1488 else if (rc != ERROR_SUCCESS)
1489 {
1490 RegCloseKey(hDeviceIdKey);
1491 return rc;
1492 }
1493 else if (dwRegType != REG_SZ)
1494 {
1495 RegCloseKey(hDeviceIdKey);
1496 return ERROR_GEN_FAILURE;
1497 }
1498 else
1499 {
1500 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1501 if (UuidFromStringW(&KeyBuffer[1], &KeyGuid) != RPC_S_OK)
1502 /* Bad GUID, skip the entry */
1503 continue;
1504 }
1505
1506 if (pClassGuid && !IsEqualIID(&KeyGuid, pClassGuid))
1507 {
1508 /* Skip this entry as it is not the right device class */
1509 continue;
1510 }
1511
1512 /* Add the entry to the list */
1513 if (!CreateDeviceInfoElement(list, InstancePath, &KeyGuid, &deviceInfo))
1514 {
1515 RegCloseKey(hDeviceIdKey);
1516 return GetLastError();
1517 }
1518 TRACE("Adding '%s' to device info set %p\n", debugstr_w(InstancePath), list);
1519 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1520 }
1521 RegCloseKey(hDeviceIdKey);
1522 }
1523
1524 return ERROR_SUCCESS;
1525 }
1526
1527 static LONG SETUP_CreateDevList(
1528 struct DeviceInfoSet *list,
1529 PCWSTR MachineName OPTIONAL,
1530 LPGUID class OPTIONAL,
1531 PCWSTR Enumerator OPTIONAL)
1532 {
1533 HKEY HKLM, hEnumKey, hEnumeratorKey;
1534 WCHAR KeyBuffer[MAX_PATH];
1535 DWORD i;
1536 DWORD dwLength;
1537 DWORD rc;
1538
1539 if (class && IsEqualIID(class, &GUID_NULL))
1540 class = NULL;
1541
1542 /* Open Enum key */
1543 if (MachineName != NULL)
1544 {
1545 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
1546 if (rc != ERROR_SUCCESS)
1547 return rc;
1548 }
1549 else
1550 HKLM = HKEY_LOCAL_MACHINE;
1551
1552 rc = RegOpenKeyExW(HKLM,
1553 REGSTR_PATH_SYSTEMENUM,
1554 0,
1555 KEY_ENUMERATE_SUB_KEYS,
1556 &hEnumKey);
1557 if (MachineName != NULL) RegCloseKey(HKLM);
1558 if (rc != ERROR_SUCCESS)
1559 return rc;
1560
1561 /* If enumerator is provided, call directly SETUP_CreateDevListFromEnumerator.
1562 * Else, enumerate all enumerators and call SETUP_CreateDevListFromEnumerator
1563 * for each one.
1564 */
1565 if (Enumerator)
1566 {
1567 rc = RegOpenKeyExW(
1568 hEnumKey,
1569 Enumerator,
1570 0,
1571 KEY_ENUMERATE_SUB_KEYS,
1572 &hEnumeratorKey);
1573 RegCloseKey(hEnumKey);
1574 if (rc != ERROR_SUCCESS)
1575 return rc;
1576 rc = SETUP_CreateDevListFromEnumerator(list, class, Enumerator, hEnumeratorKey);
1577 RegCloseKey(hEnumeratorKey);
1578 return rc;
1579 }
1580 else
1581 {
1582 /* Enumerate enumerators */
1583 i = 0;
1584 while (TRUE)
1585 {
1586 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1587 rc = RegEnumKeyExW(hEnumKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1588 if (rc == ERROR_NO_MORE_ITEMS)
1589 break;
1590 if (rc != ERROR_SUCCESS)
1591 {
1592 RegCloseKey(hEnumKey);
1593 return rc;
1594 }
1595 i++;
1596
1597 /* Open sub key */
1598 rc = RegOpenKeyExW(hEnumKey, KeyBuffer, 0, KEY_ENUMERATE_SUB_KEYS, &hEnumeratorKey);
1599 if (rc != ERROR_SUCCESS)
1600 {
1601 RegCloseKey(hEnumKey);
1602 return rc;
1603 }
1604
1605 /* Call SETUP_CreateDevListFromEnumerator */
1606 rc = SETUP_CreateDevListFromEnumerator(list, class, KeyBuffer, hEnumeratorKey);
1607 RegCloseKey(hEnumeratorKey);
1608 if (rc != ERROR_SUCCESS)
1609 {
1610 RegCloseKey(hEnumKey);
1611 return rc;
1612 }
1613 }
1614 RegCloseKey(hEnumKey);
1615 return ERROR_SUCCESS;
1616 }
1617 }
1618
1619 static LONG SETUP_CreateInterfaceList(
1620 struct DeviceInfoSet *list,
1621 PCWSTR MachineName,
1622 LPGUID InterfaceGuid,
1623 PCWSTR DeviceInstanceW /* OPTIONAL */)
1624 {
1625 HKEY hInterfaceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */
1626 HKEY hDeviceInstanceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath} */
1627 HKEY hReferenceKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString} */
1628 HKEY hControlKey; /* HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID}\##?#{InstancePath}\#{ReferenceString}\Control */
1629 HKEY hEnumKey; /* HKLM\SYSTEM\CurrentControlSet\Enum */
1630 HKEY hKey; /* HKLM\SYSTEM\CurrentControlSet\Enum\{Instance\Path} */
1631 LONG rc;
1632 WCHAR KeyBuffer[max(MAX_PATH, MAX_GUID_STRING_LEN) + 1];
1633 PWSTR InstancePath;
1634 DWORD i, j;
1635 DWORD dwLength, dwInstancePathLength;
1636 DWORD dwRegType;
1637 DWORD LinkedValue;
1638 GUID ClassGuid;
1639 struct DeviceInfoElement *deviceInfo;
1640
1641 /* Open registry key related to this interface */
1642 hInterfaceKey = SetupDiOpenClassRegKeyExW(InterfaceGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, MachineName, NULL);
1643 if (hInterfaceKey == INVALID_HANDLE_VALUE)
1644 return GetLastError();
1645
1646 /* Enumerate sub keys of hInterfaceKey */
1647 i = 0;
1648 while (TRUE)
1649 {
1650 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1651 rc = RegEnumKeyExW(hInterfaceKey, i, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1652 if (rc == ERROR_NO_MORE_ITEMS)
1653 break;
1654 if (rc != ERROR_SUCCESS)
1655 {
1656 RegCloseKey(hInterfaceKey);
1657 return rc;
1658 }
1659 i++;
1660
1661 /* Open sub key */
1662 rc = RegOpenKeyExW(hInterfaceKey, KeyBuffer, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hDeviceInstanceKey);
1663 if (rc != ERROR_SUCCESS)
1664 {
1665 RegCloseKey(hInterfaceKey);
1666 return rc;
1667 }
1668
1669 /* Read DeviceInstance */
1670 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, &dwRegType, NULL, &dwInstancePathLength);
1671 if (rc != ERROR_SUCCESS )
1672 {
1673 RegCloseKey(hDeviceInstanceKey);
1674 RegCloseKey(hInterfaceKey);
1675 return rc;
1676 }
1677 if (dwRegType != REG_SZ)
1678 {
1679 RegCloseKey(hDeviceInstanceKey);
1680 RegCloseKey(hInterfaceKey);
1681 return ERROR_GEN_FAILURE;
1682 }
1683 InstancePath = HeapAlloc(GetProcessHeap(), 0, dwInstancePathLength + sizeof(WCHAR));
1684 if (!InstancePath)
1685 {
1686 RegCloseKey(hDeviceInstanceKey);
1687 RegCloseKey(hInterfaceKey);
1688 return ERROR_NOT_ENOUGH_MEMORY;
1689 }
1690 rc = RegQueryValueExW(hDeviceInstanceKey, DeviceInstance, NULL, NULL, (LPBYTE)InstancePath, &dwInstancePathLength);
1691 if (rc != ERROR_SUCCESS)
1692 {
1693 HeapFree(GetProcessHeap(), 0, InstancePath);
1694 RegCloseKey(hDeviceInstanceKey);
1695 RegCloseKey(hInterfaceKey);
1696 return rc;
1697 }
1698 InstancePath[dwInstancePathLength / sizeof(WCHAR)] = '\0';
1699 TRACE("DeviceInstance %s\n", debugstr_w(InstancePath));
1700
1701 if (DeviceInstanceW)
1702 {
1703 /* Check if device enumerator is not the right one */
1704 if (strcmpW(DeviceInstanceW, InstancePath) != 0)
1705 {
1706 HeapFree(GetProcessHeap(), 0, InstancePath);
1707 RegCloseKey(hDeviceInstanceKey);
1708 continue;
1709 }
1710 }
1711
1712 /* Find class GUID associated to the device instance */
1713 rc = RegOpenKeyExW(
1714 list->HKLM,
1715 REGSTR_PATH_SYSTEMENUM,
1716 0, /* Options */
1717 0,
1718 &hEnumKey);
1719 if (rc != ERROR_SUCCESS)
1720 {
1721 HeapFree(GetProcessHeap(), 0, InstancePath);
1722 RegCloseKey(hDeviceInstanceKey);
1723 RegCloseKey(hInterfaceKey);
1724 return rc;
1725 }
1726 rc = RegOpenKeyExW(
1727 hEnumKey,
1728 InstancePath,
1729 0, /* Options */
1730 KEY_QUERY_VALUE,
1731 &hKey);
1732 RegCloseKey(hEnumKey);
1733 if (rc != ERROR_SUCCESS)
1734 {
1735 HeapFree(GetProcessHeap(), 0, InstancePath);
1736 RegCloseKey(hDeviceInstanceKey);
1737 RegCloseKey(hInterfaceKey);
1738 return rc;
1739 }
1740 dwLength = sizeof(KeyBuffer) - sizeof(WCHAR);
1741 rc = RegQueryValueExW(hKey, ClassGUID, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
1742 RegCloseKey(hKey);
1743 if (rc != ERROR_SUCCESS)
1744 {
1745 HeapFree(GetProcessHeap(), 0, InstancePath);
1746 RegCloseKey(hDeviceInstanceKey);
1747 RegCloseKey(hInterfaceKey);
1748 return rc;
1749 }
1750 KeyBuffer[dwLength / sizeof(WCHAR)] = '\0';
1751 KeyBuffer[37] = '\0'; /* Replace the } by a NULL character */
1752 if (UuidFromStringW(&KeyBuffer[1], &ClassGuid) != RPC_S_OK)
1753 {
1754 HeapFree(GetProcessHeap(), 0, InstancePath);
1755 RegCloseKey(hDeviceInstanceKey);
1756 RegCloseKey(hInterfaceKey);
1757 return ERROR_GEN_FAILURE;
1758 }
1759 TRACE("ClassGUID %s\n", debugstr_guid(&ClassGuid));
1760
1761 /* If current device doesn't match the list GUID (if any), skip this entry */
1762 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
1763 {
1764 HeapFree(GetProcessHeap(), 0, InstancePath);
1765 RegCloseKey(hDeviceInstanceKey);
1766 continue;
1767 }
1768
1769 /* Enumerate subkeys of hDeviceInstanceKey (ie "#ReferenceString" in IoRegisterDeviceInterface). Skip entries that don't start with '#' */
1770 j = 0;
1771 while (TRUE)
1772 {
1773 LPWSTR pSymbolicLink;
1774 struct DeviceInterface *interfaceInfo;
1775
1776 dwLength = sizeof(KeyBuffer) / sizeof(KeyBuffer[0]);
1777 rc = RegEnumKeyExW(hDeviceInstanceKey, j, KeyBuffer, &dwLength, NULL, NULL, NULL, NULL);
1778 if (rc == ERROR_NO_MORE_ITEMS)
1779 break;
1780 if (rc != ERROR_SUCCESS)
1781 {
1782 HeapFree(GetProcessHeap(), 0, InstancePath);
1783 RegCloseKey(hDeviceInstanceKey);
1784 RegCloseKey(hInterfaceKey);
1785 return rc;
1786 }
1787 j++;
1788 if (KeyBuffer[0] != '#')
1789 /* This entry doesn't represent an interesting entry */
1790 continue;
1791
1792 /* Open sub key */
1793 rc = RegOpenKeyExW(hDeviceInstanceKey, KeyBuffer, 0, KEY_QUERY_VALUE, &hReferenceKey);
1794 if (rc != ERROR_SUCCESS)
1795 {
1796 RegCloseKey(hDeviceInstanceKey);
1797 RegCloseKey(hInterfaceKey);
1798 return rc;
1799 }
1800
1801 /* Read SymbolicLink value */
1802 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, &dwRegType, NULL, &dwLength);
1803 if (rc != ERROR_SUCCESS )
1804 {
1805 RegCloseKey(hReferenceKey);
1806 RegCloseKey(hDeviceInstanceKey);
1807 RegCloseKey(hInterfaceKey);
1808 return rc;
1809 }
1810 if (dwRegType != REG_SZ)
1811 {
1812 RegCloseKey(hReferenceKey);
1813 RegCloseKey(hDeviceInstanceKey);
1814 RegCloseKey(hInterfaceKey);
1815 return ERROR_GEN_FAILURE;
1816 }
1817
1818 /* We have found a device */
1819 /* Step 1. Create a device info element */
1820 if (!CreateDeviceInfoElement(list, InstancePath, &ClassGuid, &deviceInfo))
1821 {
1822 RegCloseKey(hReferenceKey);
1823 RegCloseKey(hDeviceInstanceKey);
1824 RegCloseKey(hInterfaceKey);
1825 return GetLastError();
1826 }
1827 TRACE("Adding device %s to list\n", debugstr_w(InstancePath));
1828 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
1829
1830 /* Step 2. Create an interface list for this element */
1831 pSymbolicLink = HeapAlloc(GetProcessHeap(), 0, (dwLength + 1) * sizeof(WCHAR));
1832 if (!pSymbolicLink)
1833 {
1834 RegCloseKey(hReferenceKey);
1835 RegCloseKey(hDeviceInstanceKey);
1836 RegCloseKey(hInterfaceKey);
1837 return ERROR_NOT_ENOUGH_MEMORY;
1838 }
1839 rc = RegQueryValueExW(hReferenceKey, SymbolicLink, NULL, NULL, (LPBYTE)pSymbolicLink, &dwLength);
1840 pSymbolicLink[dwLength / sizeof(WCHAR)] = '\0';
1841 RegCloseKey(hReferenceKey);
1842 if (rc != ERROR_SUCCESS)
1843 {
1844 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1845 RegCloseKey(hDeviceInstanceKey);
1846 RegCloseKey(hInterfaceKey);
1847 return rc;
1848 }
1849 if (!CreateDeviceInterface(deviceInfo, pSymbolicLink, InterfaceGuid, &interfaceInfo))
1850 {
1851 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1852 RegCloseKey(hDeviceInstanceKey);
1853 RegCloseKey(hInterfaceKey);
1854 return GetLastError();
1855 }
1856
1857 /* Step 3. Update flags */
1858 if (KeyBuffer[1] == '\0')
1859 interfaceInfo->Flags |= SPINT_DEFAULT;
1860 rc = RegOpenKeyExW(hReferenceKey, Control, 0, KEY_QUERY_VALUE, &hControlKey);
1861 if (!rc)
1862 interfaceInfo->Flags |= SPINT_REMOVED;
1863 else
1864 {
1865 dwLength = sizeof(DWORD);
1866 if (RegQueryValueExW(hControlKey, Linked, NULL, &dwRegType, (LPBYTE)&LinkedValue, &dwLength)
1867 && dwRegType == REG_DWORD && LinkedValue)
1868 interfaceInfo->Flags |= SPINT_ACTIVE;
1869 RegCloseKey(hControlKey);
1870 }
1871
1872 TRACE("Adding interface %s to list\n", debugstr_w(pSymbolicLink));
1873 HeapFree(GetProcessHeap(), 0, pSymbolicLink);
1874 InsertTailList(&deviceInfo->InterfaceListHead, &interfaceInfo->ListEntry);
1875 }
1876 RegCloseKey(hDeviceInstanceKey);
1877 }
1878 RegCloseKey(hInterfaceKey);
1879 return ERROR_SUCCESS;
1880 }
1881
1882 /***********************************************************************
1883 * SetupDiGetClassDevsExW (SETUPAPI.@)
1884 */
1885 HDEVINFO WINAPI SetupDiGetClassDevsExW(
1886 CONST GUID *class,
1887 LPCWSTR enumstr,
1888 HWND parent,
1889 DWORD flags,
1890 HDEVINFO deviceset,
1891 LPCWSTR machine,
1892 PVOID reserved)
1893 {
1894 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1895 struct DeviceInfoSet *list;
1896 LPGUID pClassGuid;
1897 LONG rc;
1898
1899 TRACE("%s %s %p 0x%08lx %p %s %p\n", debugstr_guid(class), debugstr_w(enumstr),
1900 parent, flags, deviceset, debugstr_w(machine), reserved);
1901
1902 /* Create the deviceset if not set */
1903 if (deviceset)
1904 {
1905 list = (struct DeviceInfoSet *)deviceset;
1906 if (list->magic != SETUP_DEV_INFO_SET_MAGIC)
1907 {
1908 SetLastError(ERROR_INVALID_HANDLE);
1909 return INVALID_HANDLE_VALUE;
1910 }
1911 hDeviceInfo = deviceset;
1912 }
1913 else
1914 {
1915 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
1916 flags & DIGCF_DEVICEINTERFACE ? NULL : class,
1917 NULL, machine, NULL);
1918 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1919 return INVALID_HANDLE_VALUE;
1920 list = (struct DeviceInfoSet *)hDeviceInfo;
1921 }
1922
1923 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
1924 pClassGuid = NULL;
1925 else
1926 pClassGuid = &list->ClassGuid;
1927
1928 if (flags & DIGCF_PRESENT)
1929 FIXME(": flag DIGCF_PRESENT ignored\n");
1930 if (flags & DIGCF_PROFILE)
1931 FIXME(": flag DIGCF_PROFILE ignored\n");
1932
1933 if (flags & DIGCF_ALLCLASSES)
1934 {
1935 rc = SETUP_CreateDevList(list, machine, pClassGuid, enumstr);
1936 if (rc != ERROR_SUCCESS)
1937 {
1938 SetLastError(rc);
1939 if (!deviceset)
1940 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1941 return INVALID_HANDLE_VALUE;
1942 }
1943 return hDeviceInfo;
1944 }
1945 else if (flags & DIGCF_DEVICEINTERFACE)
1946 {
1947 if (class == NULL)
1948 {
1949 SetLastError(ERROR_INVALID_PARAMETER);
1950 if (!deviceset)
1951 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1952 return INVALID_HANDLE_VALUE;
1953 }
1954
1955 rc = SETUP_CreateInterfaceList(list, machine, (LPGUID)class, enumstr);
1956 if (rc != ERROR_SUCCESS)
1957 {
1958 SetLastError(rc);
1959 if (!deviceset)
1960 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1961 return INVALID_HANDLE_VALUE;
1962 }
1963 return hDeviceInfo;
1964 }
1965 else
1966 {
1967 rc = SETUP_CreateDevList(list, machine, (LPGUID)class, enumstr);
1968 if (rc != ERROR_SUCCESS)
1969 {
1970 SetLastError(rc);
1971 if (!deviceset)
1972 SetupDiDestroyDeviceInfoList(hDeviceInfo);
1973 return INVALID_HANDLE_VALUE;
1974 }
1975 return hDeviceInfo;
1976 }
1977 }
1978
1979 /***********************************************************************
1980 * SetupDiGetClassImageIndex (SETUPAPI.@)
1981 */
1982
1983 static BOOL GetIconIndex(
1984 IN HKEY hClassKey,
1985 OUT PINT ImageIndex)
1986 {
1987 LPWSTR Buffer = NULL;
1988 DWORD dwRegType, dwLength;
1989 LONG rc;
1990 BOOL ret = FALSE;
1991
1992 /* Read icon registry key */
1993 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, &dwRegType, NULL, &dwLength);
1994 if (rc != ERROR_SUCCESS)
1995 {
1996 SetLastError(rc);
1997 goto cleanup;
1998 } else if (dwRegType != REG_SZ)
1999 {
2000 SetLastError(ERROR_INVALID_INDEX);
2001 goto cleanup;
2002 }
2003 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2004 if (!Buffer)
2005 {
2006 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2007 goto cleanup;
2008 }
2009 rc = RegQueryValueExW(hClassKey, REGSTR_VAL_INSICON, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2010 if (rc != ERROR_SUCCESS)
2011 {
2012 SetLastError(rc);
2013 goto cleanup;
2014 }
2015 /* make sure the returned buffer is NULL-terminated */
2016 Buffer[dwLength / sizeof(WCHAR)] = 0;
2017
2018 /* Transform icon value to a INT */
2019 *ImageIndex = atoiW(Buffer);
2020 ret = TRUE;
2021
2022 cleanup:
2023 MyFree(Buffer);
2024 return ret;
2025 }
2026
2027 BOOL WINAPI SetupDiGetClassImageIndex(
2028 IN PSP_CLASSIMAGELIST_DATA ClassImageListData,
2029 IN CONST GUID *ClassGuid,
2030 OUT PINT ImageIndex)
2031 {
2032 struct ClassImageList *list;
2033 BOOL ret = FALSE;
2034
2035 TRACE("%p %s %p\n", ClassImageListData, debugstr_guid(ClassGuid), ImageIndex);
2036
2037 if (!ClassImageListData || !ClassGuid || !ImageIndex)
2038 SetLastError(ERROR_INVALID_PARAMETER);
2039 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2040 SetLastError(ERROR_INVALID_USER_BUFFER);
2041 else if ((list = (struct ClassImageList *)ClassImageListData->Reserved) == NULL)
2042 SetLastError(ERROR_INVALID_USER_BUFFER);
2043 else if (list->magic != SETUP_CLASS_IMAGE_LIST_MAGIC)
2044 SetLastError(ERROR_INVALID_USER_BUFFER);
2045 else if (!ImageIndex)
2046 SetLastError(ERROR_INVALID_PARAMETER);
2047 else
2048 {
2049 HKEY hKey = INVALID_HANDLE_VALUE;
2050 INT iconIndex;
2051
2052 /* Read Icon registry entry into Buffer */
2053 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INTERFACE, list->MachineName, NULL);
2054 if (hKey == INVALID_HANDLE_VALUE)
2055 goto cleanup;
2056 if (!GetIconIndex(hKey, &iconIndex))
2057 goto cleanup;
2058
2059 if (iconIndex >= 0)
2060 {
2061 SetLastError(ERROR_INVALID_INDEX);
2062 goto cleanup;
2063 }
2064
2065 *ImageIndex = -iconIndex;
2066 ret = TRUE;
2067
2068 cleanup:
2069 if (hKey != INVALID_HANDLE_VALUE)
2070 RegCloseKey(hKey);
2071 }
2072
2073 TRACE("Returning %d\n", ret);
2074 return ret;
2075 }
2076
2077 /***********************************************************************
2078 * SetupDiGetClassImageList(SETUPAPI.@)
2079 */
2080 BOOL WINAPI SetupDiGetClassImageList(
2081 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData)
2082 {
2083 return SetupDiGetClassImageListExW(ClassImageListData, NULL, NULL);
2084 }
2085
2086 /***********************************************************************
2087 * SetupDiGetClassImageListExA(SETUPAPI.@)
2088 */
2089 BOOL WINAPI SetupDiGetClassImageListExA(
2090 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2091 IN PCSTR MachineName OPTIONAL,
2092 IN PVOID Reserved)
2093 {
2094 PWSTR MachineNameW = NULL;
2095 BOOL ret;
2096
2097 if (MachineName)
2098 {
2099 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
2100 if (MachineNameW == NULL)
2101 return FALSE;
2102 }
2103
2104 ret = SetupDiGetClassImageListExW(ClassImageListData, MachineNameW, Reserved);
2105
2106 if (MachineNameW)
2107 MyFree(MachineNameW);
2108
2109 return ret;
2110 }
2111
2112 /***********************************************************************
2113 * SetupDiGetClassImageListExW(SETUPAPI.@)
2114 */
2115 BOOL WINAPI SetupDiGetClassImageListExW(
2116 OUT PSP_CLASSIMAGELIST_DATA ClassImageListData,
2117 IN PCWSTR MachineName OPTIONAL,
2118 IN PVOID Reserved)
2119 {
2120 BOOL ret = FALSE;
2121
2122 TRACE("%p %p %p\n", ClassImageListData, debugstr_w(MachineName), Reserved);
2123
2124 if (!ClassImageListData)
2125 SetLastError(ERROR_INVALID_PARAMETER);
2126 else if (ClassImageListData->cbSize != sizeof(SP_CLASSIMAGELIST_DATA))
2127 SetLastError(ERROR_INVALID_USER_BUFFER);
2128 else if (Reserved)
2129 SetLastError(ERROR_INVALID_PARAMETER);
2130 else
2131 {
2132 struct ClassImageList *list = NULL;
2133 DWORD size;
2134
2135 size = FIELD_OFFSET(struct ClassImageList, szData);
2136 if (MachineName)
2137 size += (strlenW(MachineName) + 3) * sizeof(WCHAR);
2138 list = HeapAlloc(GetProcessHeap(), 0, size);
2139 if (!list)
2140 {
2141 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2142 goto cleanup;
2143 }
2144 list->magic = SETUP_CLASS_IMAGE_LIST_MAGIC;
2145 if (MachineName)
2146 {
2147 list->szData[0] = list->szData[1] = '\\';
2148 strcpyW(list->szData + 2, MachineName);
2149 list->MachineName = list->szData;
2150 }
2151 else
2152 {
2153 list->MachineName = NULL;
2154 }
2155
2156 ClassImageListData->Reserved = (DWORD)list; /* FIXME: 64 bit portability issue */
2157 ret = TRUE;
2158
2159 cleanup:
2160 if (!ret)
2161 MyFree(list);
2162 }
2163
2164 TRACE("Returning %d\n", ret);
2165 return ret;
2166 }
2167
2168 /***********************************************************************
2169 * SetupDiLoadClassIcon(SETUPAPI.@)
2170 */
2171 BOOL WINAPI SetupDiLoadClassIcon(
2172 IN CONST GUID *ClassGuid,
2173 OUT HICON *LargeIcon OPTIONAL,
2174 OUT PINT MiniIconIndex OPTIONAL)
2175 {
2176 BOOL ret = FALSE;
2177
2178 if (!ClassGuid)
2179 SetLastError(ERROR_INVALID_PARAMETER);
2180 else
2181 {
2182 LPWSTR Buffer = NULL;
2183 LPCWSTR DllName;
2184 INT iconIndex;
2185 HKEY hKey = INVALID_HANDLE_VALUE;
2186
2187 hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_QUERY_VALUE);
2188 if (hKey == INVALID_HANDLE_VALUE)
2189 goto cleanup;
2190
2191 if (!GetIconIndex(hKey, &iconIndex))
2192 goto cleanup;
2193
2194 if (iconIndex > 0)
2195 {
2196 /* Look up icon in dll specified by Installer32 or EnumPropPages32 key */
2197 PWCHAR Comma;
2198 LONG rc;
2199 DWORD dwRegType, dwLength;
2200 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
2201 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
2202 {
2203 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2204 if (Buffer == NULL)
2205 {
2206 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2207 goto cleanup;
2208 }
2209 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2210 if (rc != ERROR_SUCCESS)
2211 {
2212 SetLastError(rc);
2213 goto cleanup;
2214 }
2215 /* make sure the returned buffer is NULL-terminated */
2216 Buffer[dwLength / sizeof(WCHAR)] = 0;
2217 }
2218 else if
2219 (ERROR_SUCCESS == (rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength))
2220 && dwRegType == REG_SZ)
2221 {
2222 Buffer = MyMalloc(dwLength + sizeof(WCHAR));
2223 if (Buffer == NULL)
2224 {
2225 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2226 goto cleanup;
2227 }
2228 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)Buffer, &dwLength);
2229 if (rc != ERROR_SUCCESS)
2230 {
2231 SetLastError(rc);
2232 goto cleanup;
2233 }
2234 /* make sure the returned buffer is NULL-terminated */
2235 Buffer[dwLength / sizeof(WCHAR)] = 0;
2236 }
2237 else
2238 {
2239 /* Unable to find where to load the icon */
2240 SetLastError(ERROR_FILE_NOT_FOUND);
2241 goto cleanup;
2242 }
2243 Comma = strchrW(Buffer, ',');
2244 if (!Comma)
2245 {
2246 SetLastError(ERROR_GEN_FAILURE);
2247 goto cleanup;
2248 }
2249 *Comma = '\0';
2250 DllName = Buffer;
2251 }
2252 else
2253 {
2254 /* Look up icon in setupapi.dll */
2255 DllName = L"setupapi.dll";
2256 iconIndex = -iconIndex;
2257 }
2258
2259 TRACE("Icon index %d, dll name %s\n", iconIndex, debugstr_w(DllName));
2260 if (LargeIcon)
2261 {
2262 if (1 != ExtractIconEx(DllName, iconIndex, LargeIcon, NULL, 1))
2263 {
2264 SetLastError(ERROR_INVALID_INDEX);
2265 goto cleanup;
2266 }
2267 }
2268 if (MiniIconIndex)
2269 *MiniIconIndex = iconIndex;
2270 ret = TRUE;
2271
2272 cleanup:
2273 if (hKey != INVALID_HANDLE_VALUE)
2274 RegCloseKey(hKey);
2275 MyFree(Buffer);
2276 }
2277
2278 TRACE("Returning %d\n", ret);
2279 return ret;
2280 }
2281
2282 /***********************************************************************
2283 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2284 */
2285 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2286 HDEVINFO DeviceInfoSet,
2287 PSP_DEVINFO_DATA DeviceInfoData,
2288 CONST GUID * InterfaceClassGuid,
2289 DWORD MemberIndex,
2290 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2291 {
2292 BOOL ret = FALSE;
2293
2294 TRACE("%p, %p, %s, %ld, %p\n", DeviceInfoSet, DeviceInfoData,
2295 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2296
2297 if (!DeviceInterfaceData)
2298 SetLastError(ERROR_INVALID_PARAMETER);
2299 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2300 SetLastError(ERROR_INVALID_USER_BUFFER);
2301 else if (DeviceInfoSet && DeviceInfoSet != (HDEVINFO)INVALID_HANDLE_VALUE)
2302 {
2303 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2304
2305 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2306 {
2307 PLIST_ENTRY ItemList = list->ListHead.Flink;
2308 BOOL Found = FALSE;
2309 while (ItemList != &list->ListHead && !Found)
2310 {
2311 PLIST_ENTRY InterfaceListEntry;
2312 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)ItemList;
2313 if (DeviceInfoData && (struct DeviceInfoElement *)DeviceInfoData->Reserved != DevInfo)
2314 {
2315 /* We are not searching for this element */
2316 ItemList = ItemList->Flink;
2317 continue;
2318 }
2319 InterfaceListEntry = DevInfo->InterfaceListHead.Flink;
2320 while (InterfaceListEntry != &DevInfo->InterfaceListHead && !Found)
2321 {
2322 struct DeviceInterface *DevItf = (struct DeviceInterface *)InterfaceListEntry;
2323 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2324 {
2325 InterfaceListEntry = InterfaceListEntry->Flink;
2326 continue;
2327 }
2328 if (MemberIndex-- == 0)
2329 {
2330 /* return this item */
2331 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2332 &DevItf->InterfaceClassGuid,
2333 sizeof(GUID));
2334 DeviceInterfaceData->Flags = DevItf->Flags;
2335 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2336 Found = TRUE;
2337 }
2338 InterfaceListEntry = InterfaceListEntry->Flink;
2339 }
2340 ItemList = ItemList->Flink;
2341 }
2342 if (!Found)
2343 SetLastError(ERROR_NO_MORE_ITEMS);
2344 else
2345 ret = TRUE;
2346 }
2347 else
2348 SetLastError(ERROR_INVALID_HANDLE);
2349 }
2350 else
2351 SetLastError(ERROR_INVALID_HANDLE);
2352 return ret;
2353 }
2354
2355 static VOID ReferenceInfFile(struct InfFileDetails* infFile)
2356 {
2357 InterlockedIncrement(&infFile->References);
2358 }
2359
2360 static VOID DereferenceInfFile(struct InfFileDetails* infFile)
2361 {
2362 if (InterlockedDecrement(&infFile->References) == 0)
2363 {
2364 SetupCloseInfFile(infFile->hInf);
2365 HeapFree(GetProcessHeap(), 0, infFile);
2366 }
2367 }
2368
2369 static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
2370 {
2371 DereferenceInfFile(driverInfo->InfFileDetails);
2372 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
2373 HeapFree(GetProcessHeap(), 0, driverInfo);
2374 return TRUE;
2375 }
2376
2377 static BOOL DestroyClassInstallParams(struct ClassInstallParams* installParams)
2378 {
2379 HeapFree(GetProcessHeap(), 0, installParams->PropChange);
2380 return TRUE;
2381 }
2382
2383 static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
2384 {
2385 PLIST_ENTRY ListEntry;
2386 struct DriverInfoElement *driverInfo;
2387
2388 while (!IsListEmpty(&deviceInfo->DriverListHead))
2389 {
2390 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
2391 driverInfo = (struct DriverInfoElement *)ListEntry;
2392 if (!DestroyDriverInfoElement(driverInfo))
2393 return FALSE;
2394 }
2395 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
2396 {
2397 ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
2398 HeapFree(GetProcessHeap(), 0, ListEntry);
2399 }
2400 DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
2401 HeapFree(GetProcessHeap(), 0, deviceInfo);
2402 return TRUE;
2403 }
2404
2405 static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
2406 {
2407 PLIST_ENTRY ListEntry;
2408 struct DeviceInfoElement *deviceInfo;
2409
2410 while (!IsListEmpty(&list->ListHead))
2411 {
2412 ListEntry = RemoveHeadList(&list->ListHead);
2413 deviceInfo = (struct DeviceInfoElement *)ListEntry;
2414 if (!DestroyDeviceInfoElement(deviceInfo))
2415 return FALSE;
2416 }
2417 if (list->HKLM != HKEY_LOCAL_MACHINE)
2418 RegCloseKey(list->HKLM);
2419 CM_Disconnect_Machine(list->hMachine);
2420 DestroyClassInstallParams(&list->ClassInstallParams);
2421 HeapFree(GetProcessHeap(), 0, list);
2422 return TRUE;
2423 }
2424
2425 /***********************************************************************
2426 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2427 */
2428 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
2429 {
2430 BOOL ret = FALSE;
2431
2432 TRACE("%p\n", devinfo);
2433 if (devinfo && devinfo != (HDEVINFO)INVALID_HANDLE_VALUE)
2434 {
2435 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2436
2437 if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
2438 ret = DestroyDeviceInfoSet(list);
2439 else
2440 SetLastError(ERROR_INVALID_HANDLE);
2441 }
2442 else
2443 SetLastError(ERROR_INVALID_HANDLE);
2444
2445 TRACE("Returning %d\n", ret);
2446 return ret;
2447 }
2448
2449 /***********************************************************************
2450 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2451 */
2452 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
2453 HDEVINFO DeviceInfoSet,
2454 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2455 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2456 DWORD DeviceInterfaceDetailDataSize,
2457 PDWORD RequiredSize,
2458 PSP_DEVINFO_DATA DeviceInfoData)
2459 {
2460 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2461 DWORD sizeW = 0, sizeA;
2462 BOOL ret = FALSE;
2463
2464 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2465 DeviceInterfaceData, DeviceInterfaceDetailData,
2466 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2467
2468 if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A))
2469 SetLastError(ERROR_INVALID_USER_BUFFER);
2470 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2471 SetLastError(ERROR_INVALID_PARAMETER);
2472 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + 1)
2473 SetLastError(ERROR_INVALID_PARAMETER);
2474 else
2475 {
2476 if (DeviceInterfaceDetailData != NULL)
2477 {
2478 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
2479 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2480 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, sizeW);
2481 if (!DeviceInterfaceDetailDataW)
2482 {
2483 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2484 }
2485 }
2486 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2487 {
2488 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2489 ret = SetupDiGetDeviceInterfaceDetailW(
2490 DeviceInfoSet,
2491 DeviceInterfaceData,
2492 DeviceInterfaceDetailDataW,
2493 sizeW,
2494 &sizeW,
2495 DeviceInfoData);
2496 sizeA = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2497 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
2498 if (RequiredSize)
2499 *RequiredSize = sizeA;
2500 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize <= sizeA)
2501 {
2502 if (!WideCharToMultiByte(
2503 CP_ACP, 0,
2504 DeviceInterfaceDetailDataW->DevicePath, -1,
2505 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2506 NULL, NULL))
2507 {
2508 ret = FALSE;
2509 }
2510 }
2511 }
2512 HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailDataW);
2513 }
2514
2515 TRACE("Returning %d\n", ret);
2516 return ret;
2517 }
2518
2519 /***********************************************************************
2520 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
2521 */
2522 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
2523 HDEVINFO DeviceInfoSet,
2524 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2525 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
2526 DWORD DeviceInterfaceDetailDataSize,
2527 PDWORD RequiredSize,
2528 PSP_DEVINFO_DATA DeviceInfoData)
2529 {
2530 BOOL ret = FALSE;
2531
2532 TRACE("%p %p %p %lu %p %p\n", DeviceInfoSet,
2533 DeviceInterfaceData, DeviceInterfaceDetailData,
2534 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2535
2536 if (!DeviceInfoSet || !DeviceInterfaceData)
2537 SetLastError(ERROR_INVALID_PARAMETER);
2538 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2539 SetLastError(ERROR_INVALID_HANDLE);
2540 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2541 SetLastError(ERROR_INVALID_HANDLE);
2542 else if (DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2543 SetLastError(ERROR_INVALID_USER_BUFFER);
2544 else if (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
2545 SetLastError(ERROR_INVALID_USER_BUFFER);
2546 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2547 SetLastError(ERROR_INVALID_USER_BUFFER);
2548 else if (DeviceInterfaceDetailData == NULL && DeviceInterfaceDetailDataSize != 0)
2549 SetLastError(ERROR_INVALID_PARAMETER);
2550 else if (DeviceInterfaceDetailData != NULL && DeviceInterfaceDetailDataSize < FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + sizeof(WCHAR))
2551 SetLastError(ERROR_INVALID_PARAMETER);
2552 else
2553 {
2554 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2555 LPCWSTR devName = deviceInterface->SymbolicLink;
2556 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
2557 (lstrlenW(devName) + 1) * sizeof(WCHAR);
2558
2559 if (sizeRequired > DeviceInterfaceDetailDataSize)
2560 {
2561 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2562 if (RequiredSize)
2563 *RequiredSize = sizeRequired;
2564 }
2565 else
2566 {
2567 strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
2568 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
2569 if (DeviceInfoData)
2570 {
2571 memcpy(&DeviceInfoData->ClassGuid,
2572 &deviceInterface->DeviceInfo->ClassGuid,
2573 sizeof(GUID));
2574 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
2575 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
2576 }
2577 ret = TRUE;
2578 }
2579 }
2580
2581 TRACE("Returning %d\n", ret);
2582 return ret;
2583 }
2584
2585 /***********************************************************************
2586 * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
2587 */
2588 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
2589 HDEVINFO devinfo,
2590 PSP_DEVINFO_DATA DeviceInfoData,
2591 DWORD Property,
2592 PDWORD PropertyRegDataType,
2593 PBYTE PropertyBuffer,
2594 DWORD PropertyBufferSize,
2595 PDWORD RequiredSize)
2596 {
2597 BOOL bResult;
2598 BOOL bIsStringProperty;
2599 DWORD RegType;
2600 DWORD RequiredSizeA, RequiredSizeW;
2601 DWORD PropertyBufferSizeW;
2602 PBYTE PropertyBufferW;
2603
2604 TRACE("%p %p %ld %p %p %ld %p\n", devinfo, DeviceInfoData,
2605 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2606 RequiredSize);
2607
2608 PropertyBufferSizeW = PropertyBufferSize * 2;
2609 PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
2610
2611 bResult = SetupDiGetDeviceRegistryPropertyW(
2612 devinfo,
2613 DeviceInfoData,
2614 Property,
2615 &RegType,
2616 PropertyBufferW,
2617 PropertyBufferSizeW,
2618 &RequiredSizeW);
2619
2620 if (bResult || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2621 {
2622 bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
2623
2624 if (bIsStringProperty)
2625 RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
2626 else
2627 RequiredSizeA = RequiredSizeW;
2628 if (RequiredSize)
2629 *RequiredSize = RequiredSizeA;
2630 if (PropertyRegDataType)
2631 *PropertyRegDataType = RegType;
2632 }
2633
2634 if (!bResult)
2635 {
2636 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2637 return bResult;
2638 }
2639
2640 if (RequiredSizeA <= PropertyBufferSize)
2641 {
2642 if (bIsStringProperty && PropertyBufferSize > 0)
2643 {
2644 if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
2645 {
2646 /* Last error is already set by WideCharToMultiByte */
2647 bResult = FALSE;
2648 }
2649 }
2650 else
2651 memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
2652 }
2653 else
2654 {
2655 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2656 bResult = FALSE;
2657 }
2658
2659 HeapFree(GetProcessHeap(), 0, PropertyBufferW);
2660 return bResult;
2661 }
2662
2663 /***********************************************************************
2664 * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
2665 */
2666 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
2667 HDEVINFO DeviceInfoSet,
2668 PSP_DEVINFO_DATA DeviceInfoData,
2669 DWORD Property,
2670 PDWORD PropertyRegDataType,
2671 PBYTE PropertyBuffer,
2672 DWORD PropertyBufferSize,
2673 PDWORD RequiredSize)
2674 {
2675 HKEY hEnumKey, hKey;
2676 DWORD rc;
2677 BOOL ret = FALSE;
2678
2679 TRACE("%p %p %ld %p %p %ld %p\n", DeviceInfoSet, DeviceInfoData,
2680 Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
2681 RequiredSize);
2682
2683 if (!DeviceInfoSet || DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2684 SetLastError(ERROR_INVALID_HANDLE);
2685 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2686 SetLastError(ERROR_INVALID_HANDLE);
2687 else if (!DeviceInfoData)
2688 SetLastError(ERROR_INVALID_PARAMETER);
2689 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2690 SetLastError(ERROR_INVALID_USER_BUFFER);
2691 else if (Property >= SPDRP_MAXIMUM_PROPERTY)
2692 SetLastError(ERROR_INVALID_PARAMETER);
2693 else
2694 {
2695 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
2696 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
2697
2698 switch (Property)
2699 {
2700 case SPDRP_CAPABILITIES:
2701 case SPDRP_CLASS:
2702 case SPDRP_CLASSGUID:
2703 case SPDRP_COMPATIBLEIDS:
2704 case SPDRP_CONFIGFLAGS:
2705 case SPDRP_DEVICEDESC:
2706 case SPDRP_DRIVER:
2707 case SPDRP_FRIENDLYNAME:
2708 case SPDRP_HARDWAREID:
2709 case SPDRP_LOCATION_INFORMATION:
2710 case SPDRP_LOWERFILTERS:
2711 case SPDRP_MFG:
2712 case SPDRP_SECURITY:
2713 case SPDRP_SERVICE:
2714 case SPDRP_UI_NUMBER:
2715 case SPDRP_UI_NUMBER_DESC_FORMAT:
2716 case SPDRP_UPPERFILTERS:
2717 {
2718 LPCWSTR RegistryPropertyName;
2719 DWORD BufferSize;
2720
2721 switch (Property)
2722 {
2723 case SPDRP_CAPABILITIES:
2724 RegistryPropertyName = REGSTR_VAL_CAPABILITIES; break;
2725 case SPDRP_CLASS:
2726 RegistryPropertyName = REGSTR_VAL_CLASS; break;
2727 case SPDRP_CLASSGUID:
2728 RegistryPropertyName = REGSTR_VAL_CLASSGUID; break;
2729 case SPDRP_COMPATIBLEIDS:
2730 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS; break;
2731 case SPDRP_CONFIGFLAGS:
2732 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS; break;
2733 case SPDRP_DEVICEDESC:
2734 RegistryPropertyName = REGSTR_VAL_DEVDESC; break;
2735 case SPDRP_DRIVER:
2736 RegistryPropertyName = REGSTR_VAL_DRIVER; break;
2737 case SPDRP_FRIENDLYNAME:
2738 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME; break;
2739 case SPDRP_HARDWAREID:
2740 RegistryPropertyName = REGSTR_VAL_HARDWAREID; break;
2741 case SPDRP_LOCATION_INFORMATION:
2742 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION; break;
2743 case SPDRP_LOWERFILTERS:
2744 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS; break;
2745 case SPDRP_MFG:
2746 RegistryPropertyName = REGSTR_VAL_MFG; break;
2747 case SPDRP_SECURITY:
2748 RegistryPropertyName = REGSTR_SECURITY; break;
2749 case SPDRP_SERVICE:
2750 RegistryPropertyName = REGSTR_VAL_SERVICE; break;
2751 case SPDRP_UI_NUMBER:
2752 RegistryPropertyName = REGSTR_VAL_UI_NUMBER; break;
2753 case SPDRP_UI_NUMBER_DESC_FORMAT:
2754 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT; break;
2755 case SPDRP_UPPERFILTERS:
2756 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS; break;
2757 default:
2758 /* Should not happen */
2759 RegistryPropertyName = NULL; break;
2760 }
2761
2762 /* Open registry key name */
2763 rc = RegOpenKeyExW(
2764 list->HKLM,
2765 REGSTR_PATH_SYSTEMENUM,
2766 0, /* Options */
2767 0,
2768 &hEnumKey);
2769 if (rc != ERROR_SUCCESS)
2770 {
2771 SetLastError(rc);
2772 break;
2773 }
2774 rc = RegOpenKeyExW(
2775 hEnumKey,
2776 DevInfo->Data,
2777 0, /* Options */
2778 KEY_QUERY_VALUE,
2779 &hKey);
2780 RegCloseKey(hEnumKey);
2781 if (rc != ERROR_SUCCESS)
2782 {
2783 SetLastError(rc);
2784 break;
2785 }
2786 /* Read registry entry */
2787 BufferSize = PropertyBufferSize;
2788 rc = RegQueryValueExW(
2789 hKey,
2790 RegistryPropertyName,
2791 NULL, /* Reserved */
2792 PropertyRegDataType,
2793 PropertyBuffer,
2794 &BufferSize);
2795 if (RequiredSize)
2796 *RequiredSize = BufferSize;
2797 switch(rc) {
2798 case ERROR_SUCCESS:
2799 if (PropertyBuffer != NULL || BufferSize == 0)
2800 ret = TRUE;
2801 else
2802 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2803 break;
2804 case ERROR_MORE_DATA:
2805 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2806 break;
2807 default:
2808 SetLastError(rc);
2809 }
2810 RegCloseKey(hKey);
2811 break;
2812 }
2813
2814 case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME:
2815 {
2816 DWORD required = (strlenW(DevInfo->Data) + 1) * sizeof(WCHAR);
2817
2818 if (PropertyRegDataType)
2819 *PropertyRegDataType = REG_SZ;
2820 if (RequiredSize)
2821 *RequiredSize = required;
2822 if (PropertyBufferSize >= required)
2823 {
2824 strcpyW((LPWSTR)PropertyBuffer, DevInfo->Data);
2825 ret = TRUE;
2826 }
2827 else
2828 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2829 break;
2830 }
2831
2832 /*case SPDRP_BUSTYPEGUID:
2833 case SPDRP_LEGACYBUSTYPE:
2834 case SPDRP_BUSNUMBER:
2835 case SPDRP_ENUMERATOR_NAME:
2836 case SPDRP_SECURITY_SDS:
2837 case SPDRP_DEVTYPE:
2838 case SPDRP_EXCLUSIVE:
2839 case SPDRP_CHARACTERISTICS:
2840 case SPDRP_ADDRESS:
2841 case SPDRP_DEVICE_POWER_DATA:*/
2842 #if (WINVER >= 0x501)
2843 /*case SPDRP_REMOVAL_POLICY:
2844 case SPDRP_REMOVAL_POLICY_HW_DEFAULT:
2845 case SPDRP_REMOVAL_POLICY_OVERRIDE:
2846 case SPDRP_INSTALL_STATE:*/
2847 #endif
2848
2849 default:
2850 {
2851 ERR("Property 0x%lx not implemented\n", Property);
2852 SetLastError(ERROR_NOT_SUPPORTED);
2853 }
2854 }
2855 }
2856
2857 TRACE("Returning %d\n", ret);
2858 return ret;
2859 }
2860
2861 /***********************************************************************
2862 * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
2863 */
2864 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
2865 IN HDEVINFO DeviceInfoSet,
2866 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2867 IN DWORD Property,
2868 IN CONST BYTE *PropertyBuffer,
2869 IN DWORD PropertyBufferSize)
2870 {
2871 FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2872 Property, PropertyBuffer, PropertyBufferSize);
2873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2874 return FALSE;
2875 }
2876
2877 /***********************************************************************
2878 * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
2879 */
2880 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
2881 IN HDEVINFO DeviceInfoSet,
2882 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
2883 IN DWORD Property,
2884 IN const BYTE *PropertyBuffer,
2885 IN DWORD PropertyBufferSize)
2886 {
2887 struct DeviceInfoSet *list;
2888 BOOL ret = FALSE;
2889
2890 TRACE("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
2891 Property, PropertyBuffer, PropertyBufferSize);
2892
2893 if (!DeviceInfoSet)
2894 SetLastError(ERROR_INVALID_HANDLE);
2895 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
2896 SetLastError(ERROR_INVALID_HANDLE);
2897 else if (!DeviceInfoData)
2898 SetLastError(ERROR_INVALID_HANDLE);
2899 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2900 SetLastError(ERROR_INVALID_USER_BUFFER);
2901 else
2902 {
2903 switch (Property)
2904 {
2905 case SPDRP_COMPATIBLEIDS:
2906 case SPDRP_CONFIGFLAGS:
2907 case SPDRP_FRIENDLYNAME:
2908 case SPDRP_HARDWAREID:
2909 case SPDRP_LOCATION_INFORMATION:
2910 case SPDRP_LOWERFILTERS:
2911 case SPDRP_SECURITY:
2912 case SPDRP_SERVICE:
2913 case SPDRP_UI_NUMBER_DESC_FORMAT:
2914 case SPDRP_UPPERFILTERS:
2915 {
2916 LPCWSTR RegistryPropertyName;
2917 DWORD RegistryDataType;
2918 HKEY hKey;
2919 LONG rc;
2920
2921 switch (Property)
2922 {
2923 case SPDRP_COMPATIBLEIDS:
2924 RegistryPropertyName = REGSTR_VAL_COMPATIBLEIDS;
2925 RegistryDataType = REG_MULTI_SZ;
2926 break;
2927 case SPDRP_CONFIGFLAGS:
2928 RegistryPropertyName = REGSTR_VAL_CONFIGFLAGS;
2929 RegistryDataType = REG_DWORD;
2930 break;
2931 case SPDRP_FRIENDLYNAME:
2932 RegistryPropertyName = REGSTR_VAL_FRIENDLYNAME;
2933 RegistryDataType = REG_SZ;
2934 break;
2935 case SPDRP_HARDWAREID:
2936 RegistryPropertyName = REGSTR_VAL_HARDWAREID;
2937 RegistryDataType = REG_MULTI_SZ;
2938 break;
2939 case SPDRP_LOCATION_INFORMATION:
2940 RegistryPropertyName = REGSTR_VAL_LOCATION_INFORMATION;
2941 RegistryDataType = REG_SZ;
2942 break;
2943 case SPDRP_LOWERFILTERS:
2944 RegistryPropertyName = REGSTR_VAL_LOWERFILTERS;
2945 RegistryDataType = REG_MULTI_SZ;
2946 break;
2947 case SPDRP_SECURITY:
2948 RegistryPropertyName = REGSTR_SECURITY;
2949 RegistryDataType = REG_BINARY;
2950 break;
2951 case SPDRP_SERVICE:
2952 RegistryPropertyName = REGSTR_VAL_SERVICE;
2953 RegistryDataType = REG_SZ;
2954 break;
2955 case SPDRP_UI_NUMBER_DESC_FORMAT:
2956 RegistryPropertyName = REGSTR_UI_NUMBER_DESC_FORMAT;
2957 RegistryDataType = REG_SZ;
2958 break;
2959 case SPDRP_UPPERFILTERS:
2960 RegistryPropertyName = REGSTR_VAL_UPPERFILTERS;
2961 RegistryDataType = REG_MULTI_SZ;
2962 break;
2963 default:
2964 /* Should not happen */
2965 RegistryPropertyName = NULL;
2966 RegistryDataType = REG_BINARY;
2967 break;
2968 }
2969 /* Open device registry key */
2970 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
2971 if (hKey != INVALID_HANDLE_VALUE)
2972 {
2973 /* Write new data */
2974 rc = RegSetValueExW(
2975 hKey,
2976 RegistryPropertyName,
2977 0, /* Reserved */
2978 RegistryDataType,
2979 PropertyBuffer,
2980 PropertyBufferSize);
2981 if (rc == ERROR_SUCCESS)
2982 ret = TRUE;
2983 else
2984 SetLastError(rc);
2985 RegCloseKey(hKey);
2986 }
2987 break;
2988 }
2989
2990 /*case SPDRP_CHARACTERISTICS:
2991 case SPDRP_DEVTYPE:
2992 case SPDRP_EXCLUSIVE:*/
2993 #if (WINVER >= 0x501)
2994 //case SPDRP_REMOVAL_POLICY_OVERRIDE:
2995 #endif
2996 //case SPDRP_SECURITY_SDS:
2997
2998 default:
2999 {
3000 ERR("Property 0x%lx not implemented\n", Property);
3001 SetLastError(ERROR_NOT_SUPPORTED);
3002 }
3003 }
3004 }
3005
3006 TRACE("Returning %d\n", ret);
3007 return ret;
3008 }
3009
3010
3011 /***********************************************************************
3012 * SetupDiInstallClassA (SETUPAPI.@)
3013 */
3014 BOOL WINAPI SetupDiInstallClassA(
3015 IN HWND hwndParent OPTIONAL,
3016 IN PCSTR InfFileName,
3017 IN DWORD Flags,
3018 IN HSPFILEQ FileQueue OPTIONAL)
3019 {
3020 return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3021 }
3022
3023
3024 /***********************************************************************
3025 * SetupDiInstallClassW (SETUPAPI.@)
3026 */
3027 BOOL WINAPI SetupDiInstallClassW(
3028 IN HWND hwndParent OPTIONAL,
3029 IN PCWSTR InfFileName,
3030 IN DWORD Flags,
3031 IN HSPFILEQ FileQueue OPTIONAL)
3032 {
3033 return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3034 }
3035
3036
3037 /***********************************************************************
3038 * SetupDiInstallClassExA (SETUPAPI.@)
3039 */
3040 BOOL WINAPI SetupDiInstallClassExA(
3041 IN HWND hwndParent OPTIONAL,
3042 IN PCSTR InfFileName OPTIONAL,
3043 IN DWORD Flags,
3044 IN HSPFILEQ FileQueue OPTIONAL,
3045 IN const GUID* InterfaceClassGuid OPTIONAL,
3046 IN PVOID Reserved1,
3047 IN PVOID Reserved2)
3048 {
3049 PWSTR InfFileNameW = NULL;
3050 BOOL Result;
3051
3052 if (InfFileName)
3053 {
3054 InfFileNameW = MultiByteToUnicode(InfFileName, CP_ACP);
3055 if (InfFileNameW == NULL)
3056 {
3057 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3058 return FALSE;
3059 }
3060 }
3061
3062 Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3063 FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3064
3065 MyFree(InfFileNameW);
3066
3067 return Result;
3068 }
3069
3070
3071 static HKEY CreateClassKey(HINF hInf)
3072 {
3073 WCHAR FullBuffer[MAX_PATH];
3074 WCHAR Buffer[MAX_PATH];
3075 DWORD RequiredSize;
3076 HKEY hClassKey;
3077
3078 Buffer[0] = '\\';
3079 if (!SetupGetLineTextW(NULL,
3080 hInf,
3081 Version,
3082 ClassGUID,
3083 &Buffer[1],
3084 MAX_PATH - 1,
3085 &RequiredSize))
3086 {
3087 return INVALID_HANDLE_VALUE;
3088 }
3089
3090 lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3091 lstrcatW(FullBuffer, Buffer);
3092
3093
3094 if (!SetupGetLineTextW(NULL,
3095 hInf,
3096 Version,
3097 Class,
3098 Buffer,
3099 MAX_PATH,
3100 &RequiredSize))
3101 {
3102 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3103 return INVALID_HANDLE_VALUE;
3104 }
3105
3106 if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_LOCAL_MACHINE,
3107 FullBuffer,
3108 0,
3109 NULL,
3110 REG_OPTION_NON_VOLATILE,
3111 KEY_SET_VALUE,
3112 NULL,
3113 &hClassKey,
3114 NULL))
3115 {
3116 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3117 return INVALID_HANDLE_VALUE;
3118 }
3119
3120 if (ERROR_SUCCESS != RegSetValueExW(hClassKey,
3121 Class,
3122 0,
3123 REG_SZ,
3124 (LPBYTE)Buffer,
3125 RequiredSize * sizeof(WCHAR)))
3126 {
3127 RegCloseKey(hClassKey);
3128 RegDeleteKeyW(HKEY_LOCAL_MACHINE, FullBuffer);
3129 return INVALID_HANDLE_VALUE;
3130 }
3131
3132 return hClassKey;
3133 }
3134
3135
3136 /***********************************************************************
3137 * SetupDiInstallClassExW (SETUPAPI.@)
3138 */
3139 BOOL WINAPI SetupDiInstallClassExW(
3140 IN HWND hwndParent OPTIONAL,
3141 IN PCWSTR InfFileName OPTIONAL,
3142 IN DWORD Flags,
3143 IN HSPFILEQ FileQueue OPTIONAL,
3144 IN const GUID* InterfaceClassGuid OPTIONAL,
3145 IN PVOID Reserved1,
3146 IN PVOID Reserved2)
3147 {
3148 BOOL ret = FALSE;
3149
3150 TRACE("%p %s 0x%lx %p %s %p %p\n", hwndParent, debugstr_w(InfFileName), Flags,
3151 FileQueue, debugstr_guid(InterfaceClassGuid), Reserved1, Reserved2);
3152
3153 if (!InfFileName)
3154 {
3155 FIXME("Case not implemented: InfFileName NULL\n");
3156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3157 }
3158 else if (Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL))
3159 {
3160 TRACE("Unknown flags: 0x%08lx\n", Flags & ~(DI_NOVCP | DI_NOBROWSE | DI_FORCECOPY | DI_QUIETINSTALL));
3161 SetLastError(ERROR_INVALID_FLAGS);
3162 }
3163 else if ((Flags & DI_NOVCP) && FileQueue == NULL)
3164 SetLastError(ERROR_INVALID_PARAMETER);
3165 else if (Reserved1 != NULL)
3166 SetLastError(ERROR_INVALID_PARAMETER);
3167 else if (Reserved2 != NULL)
3168 SetLastError(ERROR_INVALID_PARAMETER);
3169 else
3170 {
3171 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3172 SP_DEVINSTALL_PARAMS_W InstallParams;
3173 WCHAR SectionName[MAX_PATH];
3174 HINF hInf = INVALID_HANDLE_VALUE;
3175 HKEY hRootKey = INVALID_HANDLE_VALUE;
3176 PVOID callback_context = NULL;
3177
3178 hDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
3179
3180 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3181 if (!SetupDiGetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
3182 goto cleanup;
3183 InstallParams.Flags &= ~(DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
3184 InstallParams.Flags |= Flags & (DI_NOVCP | DI_NOBROWSE | DI_QUIETINSTALL);
3185 if (Flags & DI_NOVCP)
3186 InstallParams.FileQueue = FileQueue;
3187 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, NULL, &InstallParams))
3188 goto cleanup;
3189
3190 /* Open the .inf file */
3191 hInf = SetupOpenInfFileW(
3192 InfFileName,
3193 NULL,
3194 INF_STYLE_WIN4,
3195 NULL);
3196 if (hInf == INVALID_HANDLE_VALUE)
3197 goto cleanup;
3198
3199 /* Try to append a layout file */
3200 ret = SetupOpenAppendInfFileW(NULL, hInf, NULL);
3201 if (!ret)
3202 goto cleanup;
3203
3204 if (InterfaceClassGuid)
3205 {
3206 /* Retrieve the actual section name */
3207 ret = SetupDiGetActualSectionToInstallW(
3208 hInf,
3209 InterfaceInstall32,
3210 SectionName,
3211 MAX_PATH,
3212 NULL,
3213 NULL);
3214 if (!ret)
3215 goto cleanup;
3216
3217 /* Open registry key related to this interface */
3218 /* FIXME: What happens if the key doesn't exist? */
3219 hRootKey = SetupDiOpenClassRegKeyExW(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, DIOCR_INTERFACE, NULL, NULL);
3220 if (hRootKey == INVALID_HANDLE_VALUE)
3221 goto cleanup;
3222
3223 /* SetupDiCreateDeviceInterface??? */
3224 FIXME("Installing an interface is not implemented\n");
3225 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3226 }
3227 else
3228 {
3229 /* Create or open the class registry key 'HKLM\CurrentControlSet\Class\{GUID}' */
3230 hRootKey = CreateClassKey(hInf);
3231 if (hRootKey == INVALID_HANDLE_VALUE)
3232 goto cleanup;
3233
3234 /* Retrieve the actual section name */
3235 ret = SetupDiGetActualSectionToInstallW(
3236 hInf,
3237 ClassInstall32,
3238 SectionName,
3239 MAX_PATH - strlenW(DotServices),
3240 NULL,
3241 NULL);
3242 if (!ret)
3243 goto cleanup;
3244
3245 callback_context = SetupInitDefaultQueueCallback(hwndParent);
3246 if (!callback_context)
3247 goto cleanup;
3248
3249 ret = SetupInstallFromInfSectionW(
3250 hwndParent,
3251 hInf,
3252 SectionName,
3253 SPINST_REGISTRY | SPINST_FILES | SPINST_BITREG | SPINST_INIFILES | SPINST_INI2REG,
3254 hRootKey,
3255 NULL, /* SourceRootPath */
3256 !(Flags & DI_NOVCP) && (Flags & DI_FORCECOPY) ? SP_COPY_FORCE_IN_USE : 0, /* CopyFlags */
3257 SetupDefaultQueueCallbackW,
3258 callback_context,
3259 hDeviceInfo,
3260 NULL);
3261 if (!ret)
3262 goto cleanup;
3263
3264 /* Install .Services section */
3265 lstrcatW(SectionName, DotServices);
3266 ret = SetupInstallServicesFromInfSectionExW(
3267 hInf,
3268 SectionName,
3269 0,
3270 hDeviceInfo,
3271 NULL,
3272 NULL,
3273 NULL);
3274 if (!ret)
3275 goto cleanup;
3276
3277 ret = TRUE;
3278 }
3279
3280 cleanup:
3281 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3282 SetupDiDestroyDeviceInfoList(hDeviceInfo);
3283 if (hInf != INVALID_HANDLE_VALUE)
3284 SetupCloseInfFile(hInf);
3285 if (hRootKey != INVALID_HANDLE_VALUE)
3286 RegCloseKey(hRootKey);
3287 SetupTermDefaultQueueCallback(callback_context);
3288 }
3289
3290 TRACE("Returning %d\n", ret);
3291 return ret;
3292 }
3293
3294
3295 /***********************************************************************
3296 * SetupDiOpenClassRegKey (SETUPAPI.@)
3297 */
3298 HKEY WINAPI SetupDiOpenClassRegKey(
3299 const GUID* ClassGuid,
3300 REGSAM samDesired)
3301 {
3302 return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3303 DIOCR_INSTALLER, NULL, NULL);
3304 }
3305
3306
3307 /***********************************************************************
3308 * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3309 */
3310 HKEY WINAPI SetupDiOpenClassRegKeyExA(
3311 const GUID* ClassGuid OPTIONAL,
3312 REGSAM samDesired,
3313 DWORD Flags,
3314 PCSTR MachineName OPTIONAL,
3315 PVOID Reserved)
3316 {
3317 PWSTR MachineNameW = NULL;
3318 HKEY hKey;
3319
3320 TRACE("\n");
3321
3322 if (MachineName)
3323 {
3324 MachineNameW = MultiByteToUnicode(MachineName, CP_ACP);
3325 if (MachineNameW == NULL)
3326 return INVALID_HANDLE_VALUE;
3327 }
3328
3329 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3330 Flags, MachineNameW, Reserved);
3331
3332 if (MachineNameW)
3333 MyFree(MachineNameW);
3334
3335 return hKey;
3336 }
3337
3338
3339 /***********************************************************************
3340 * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3341 */
3342 HKEY WINAPI SetupDiOpenClassRegKeyExW(
3343 const GUID* ClassGuid OPTIONAL,
3344 REGSAM samDesired,
3345 DWORD Flags,
3346 PCWSTR MachineName OPTIONAL,
3347 PVOID Reserved)
3348 {
3349 LPWSTR lpGuidString;
3350 LPWSTR lpFullGuidString;
3351 DWORD dwLength;
3352 HKEY HKLM;
3353 HKEY hClassesKey;
3354 HKEY hClassKey;
3355 DWORD rc;
3356 LPCWSTR lpKeyName;
3357
3358 TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3359 Flags, debugstr_w(MachineName), Reserved);
3360
3361 if (Flags == DIOCR_INSTALLER)
3362 {
3363 lpKeyName = REGSTR_PATH_CLASS_NT;
3364 }
3365 else if (Flags == DIOCR_INTERFACE)
3366 {
3367 lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3368 }
3369 else
3370 {
3371 ERR("Invalid Flags parameter!\n");
3372 SetLastError(ERROR_INVALID_FLAGS);
3373 return INVALID_HANDLE_VALUE;
3374 }
3375
3376 if (MachineName != NULL)
3377 {
3378 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3379 if (rc != ERROR_SUCCESS)
3380 {
3381 SetLastError(rc);
3382 return INVALID_HANDLE_VALUE;
3383 }
3384 }
3385 else
3386 HKLM = HKEY_LOCAL_MACHINE;
3387
3388 rc = RegOpenKeyExW(HKLM,
3389 lpKeyName,
3390 0,
3391 ClassGuid ? 0 : samDesired,
3392 &hClassesKey);
3393 if (MachineName != NULL) RegCloseKey(HKLM);
3394 if (rc != ERROR_SUCCESS)
3395 {
3396 SetLastError(rc);
3397 return INVALID_HANDLE_VALUE;
3398 }
3399
3400 if (ClassGuid == NULL)
3401 return hClassesKey;
3402
3403 if (UuidToStringW((UUID*)ClassGuid, &lpGuidString) != RPC_S_OK)
3404 {
3405 SetLastError(ERROR_GEN_FAILURE);
3406 RegCloseKey(hClassesKey);
3407 return INVALID_HANDLE_VALUE;
3408 }
3409
3410 dwLength = lstrlenW(lpGuidString);
3411 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (dwLength + 3) * sizeof(WCHAR));
3412 if (!lpFullGuidString)
3413 {
3414 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3415 RpcStringFreeW(&lpGuidString);
3416 return INVALID_HANDLE_VALUE;
3417 }
3418 lpFullGuidString[0] = '{';
3419 memcpy(&lpFullGuidString[1], lpGuidString, dwLength * sizeof(WCHAR));
3420 lpFullGuidString[dwLength + 1] = '}';
3421 lpFullGuidString[dwLength + 2] = '\0';
3422 RpcStringFreeW(&lpGuidString);
3423
3424 rc = RegOpenKeyExW(hClassesKey,
3425 lpFullGuidString,
3426 0,
3427 samDesired,
3428 &hClassKey);
3429 if (rc != ERROR_SUCCESS)
3430 {
3431 SetLastError(rc);
3432 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
3433 RegCloseKey(hClassesKey);
3434 return INVALID_HANDLE_VALUE;
3435 }
3436
3437 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
3438 RegCloseKey(hClassesKey);
3439
3440 return hClassKey;
3441 }
3442
3443 /***********************************************************************
3444 * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3445 */
3446 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
3447 HDEVINFO DeviceInfoSet,
3448 PCWSTR DevicePath,
3449 DWORD OpenFlags,
3450 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3451 {
3452 FIXME("%p %s %08lx %p\n",
3453 DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3454 return FALSE;
3455 }
3456
3457 /***********************************************************************
3458 * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3459 */
3460 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
3461 HDEVINFO DeviceInfoSet,
3462 PCSTR DevicePath,
3463 DWORD OpenFlags,
3464 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3465 {
3466 LPWSTR DevicePathW = NULL;
3467 BOOL bResult;
3468
3469 TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3470
3471 DevicePathW = MultiByteToUnicode(DevicePath, CP_ACP);
3472 if (DevicePathW == NULL)
3473 return FALSE;
3474
3475 bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
3476 DevicePathW, OpenFlags, DeviceInterfaceData);
3477
3478 MyFree(DevicePathW);
3479
3480 return bResult;
3481 }
3482
3483 /***********************************************************************
3484 * SetupDiSetClassInstallParamsA (SETUPAPI.@)
3485 */
3486 BOOL WINAPI SetupDiSetClassInstallParamsA(
3487 HDEVINFO DeviceInfoSet,
3488 PSP_DEVINFO_DATA DeviceInfoData,
3489 PSP_CLASSINSTALL_HEADER ClassInstallParams,
3490 DWORD ClassInstallParamsSize)
3491 {
3492 FIXME("%p %p %x %lu\n",DeviceInfoSet, DeviceInfoData,
3493 ClassInstallParams->InstallFunction, ClassInstallParamsSize);
3494 return FALSE;
3495 }
3496
3497 /***********************************************************************
3498 * SetupDiSetClassInstallParamsW (SETUPAPI.@)
3499 */
3500 BOOL WINAPI SetupDiSetClassInstallParamsW(
3501 IN HDEVINFO DeviceInfoSet,
3502 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
3503 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3504 IN DWORD ClassInstallParamsSize)
3505 {
3506 struct DeviceInfoSet *list;
3507 BOOL ret = FALSE;
3508
3509 TRACE("%p %p %p %lu\n", DeviceInfoSet, DeviceInfoData,
3510 ClassInstallParams, ClassInstallParamsSize);
3511
3512 if (!DeviceInfoSet)
3513 SetLastError(ERROR_INVALID_PARAMETER);
3514 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3515 SetLastError(ERROR_INVALID_HANDLE);
3516 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3517 SetLastError(ERROR_INVALID_HANDLE);
3518 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3519 SetLastError(ERROR_INVALID_USER_BUFFER);
3520 else if (ClassInstallParams && ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))
3521 SetLastError(ERROR_INVALID_USER_BUFFER);
3522 else if (ClassInstallParams && ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER))
3523 SetLastError(ERROR_INVALID_PARAMETER);
3524 else if (!ClassInstallParams && ClassInstallParamsSize != 0)
3525 SetLastError(ERROR_INVALID_PARAMETER);
3526 else
3527 {
3528 SP_DEVINSTALL_PARAMS_W InstallParams;
3529 BOOL Result;
3530
3531 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
3532 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3533 if (!Result)
3534 goto done;
3535
3536 if (ClassInstallParams)
3537 {
3538 /* Check parameters in ClassInstallParams */
3539 if (ClassInstallParams->InstallFunction < DIF_SELECTDEVICE
3540 || ClassInstallParams->InstallFunction - DIF_SELECTDEVICE >= sizeof(UpdateClassInstallParamHandlers)/sizeof(UpdateClassInstallParamHandlers[0]))
3541 {
3542 SetLastError(ERROR_INVALID_USER_BUFFER);
3543 goto done;
3544 }
3545 else if (UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE] == NULL)
3546 {
3547 FIXME("InstallFunction %u is valid, but has no associated update handler\n", ClassInstallParams->InstallFunction);
3548 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3549 goto done;
3550 }
3551 ret = UpdateClassInstallParamHandlers[ClassInstallParams->InstallFunction - DIF_SELECTDEVICE](DeviceInfoSet, DeviceInfoData, ClassInstallParams, ClassInstallParamsSize);
3552 if (!ret)
3553 goto done;
3554 InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
3555 }
3556 else
3557 {
3558 InstallParams.Flags &= ~DI_CLASSINSTALLPARAMS;
3559 }
3560
3561 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3562 }
3563
3564 done:
3565 TRACE("Returning %d\n", ret);
3566 return ret;
3567 }
3568
3569 static BOOL PropertyChangeHandler(
3570 IN HDEVINFO DeviceInfoSet,
3571 IN PSP_DEVINFO_DATA DeviceInfoData,
3572 IN PSP_CLASSINSTALL_HEADER ClassInstallParams OPTIONAL,
3573 IN DWORD ClassInstallParamsSize)
3574 {
3575 PSP_PROPCHANGE_PARAMS PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
3576 BOOL ret = FALSE;
3577
3578 if (!DeviceInfoData)
3579 SetLastError(ERROR_INVALID_PARAMETER);
3580 else if (ClassInstallParamsSize != sizeof(SP_PROPCHANGE_PARAMS))
3581 SetLastError(ERROR_INVALID_PARAMETER);
3582 else if (PropChangeParams && PropChangeParams->StateChange != DICS_ENABLE
3583 && PropChangeParams->StateChange != DICS_DISABLE && PropChangeParams->StateChange != DICS_PROPCHANGE
3584 && PropChangeParams->StateChange != DICS_START && PropChangeParams->StateChange != DICS_STOP)
3585 SetLastError(ERROR_INVALID_FLAGS);
3586 else if (PropChangeParams && PropChangeParams->Scope != DICS_FLAG_GLOBAL
3587 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3588 SetLastError(ERROR_INVALID_FLAGS);
3589 else if (PropChangeParams
3590 && (PropChangeParams->StateChange == DICS_START || PropChangeParams->StateChange == DICS_STOP)
3591 && PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)
3592 SetLastError(ERROR_INVALID_USER_BUFFER);
3593 else
3594 {
3595 PSP_PROPCHANGE_PARAMS *CurrentPropChangeParams;
3596 if (!DeviceInfoData)
3597 {
3598 struct DeviceInfoSet *list = (struct DeviceInfoSet *)DeviceInfoSet;
3599 CurrentPropChangeParams = &list->ClassInstallParams.PropChange;
3600 }
3601 else
3602 {
3603 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
3604 CurrentPropChangeParams = &deviceInfo->ClassInstallParams.PropChange;
3605 }
3606 if (*CurrentPropChangeParams)
3607 {
3608 MyFree(*CurrentPropChangeParams);
3609 *CurrentPropChangeParams = NULL;
3610 }
3611 if (PropChangeParams)
3612 {
3613 *CurrentPropChangeParams = MyMalloc(sizeof(SP_PROPCHANGE_PARAMS));
3614 if (!*CurrentPropChangeParams)
3615 {
3616 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3617 goto done;
3618 }
3619 memcpy(*CurrentPropChangeParams, PropChangeParams, sizeof(SP_PROPCHANGE_PARAMS));
3620 }
3621 ret = TRUE;
3622 }
3623
3624 done:
3625 return ret;
3626 }
3627
3628 static DWORD
3629 GetFunctionPointer(
3630 IN PWSTR InstallerName,
3631 OUT HMODULE* ModulePointer,
3632 OUT PVOID* FunctionPointer)
3633 {
3634 HMODULE hModule = NULL;
3635 LPSTR FunctionNameA = NULL;
3636 PWCHAR Comma;
3637 DWORD rc;
3638
3639 *ModulePointer = NULL;
3640 *FunctionPointer = NULL;
3641
3642 Comma = strchrW(InstallerName, ',');
3643 if (!Comma)
3644 {
3645 rc = ERROR_INVALID_PARAMETER;
3646 goto cleanup;
3647 }
3648
3649 /* Load library */
3650 *Comma = '\0';
3651 hModule = LoadLibraryW(InstallerName);
3652 *Comma = ',';
3653 if (!hModule)
3654 {
3655 rc = GetLastError();
3656 goto cleanup;
3657 }
3658
3659 /* Skip comma spaces */
3660 while (*Comma == ',' || isspaceW(*Comma))
3661 Comma++;
3662
3663 /* W->A conversion for function name */
3664 FunctionNameA = UnicodeToMultiByte(Comma, CP_ACP);
3665 if (!FunctionNameA)
3666 {
3667 rc = GetLastError();
3668 goto cleanup;
3669 }
3670
3671 /* Search function */
3672 *FunctionPointer = GetProcAddress(hModule, FunctionNameA);
3673 if (!*FunctionPointer)
3674 {
3675 rc = GetLastError();
3676 goto cleanup;
3677 }
3678
3679 *ModulePointer = hModule;
3680 rc = ERROR_SUCCESS;
3681
3682 cleanup:
3683 if (rc != ERROR_SUCCESS && hModule)
3684 FreeLibrary(hModule);
3685 MyFree(FunctionNameA);
3686 return rc;
3687 }
3688
3689 static DWORD
3690 FreeFunctionPointer(
3691 IN HMODULE ModulePointer,
3692 IN PVOID FunctionPointer)
3693 {
3694 if (ModulePointer == NULL)
3695 return ERROR_SUCCESS;
3696 if (FreeLibrary(ModulePointer))
3697 return ERROR_SUCCESS;
3698 else
3699 return GetLastError();
3700 }
3701
3702 static BOOL WINAPI
3703 IntSetupDiRegisterDeviceInfo(
3704 IN HDEVINFO DeviceInfoSet,
3705 IN OUT PSP_DEVINFO_DATA DeviceInfoData)
3706 {
3707 return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
3708 }
3709
3710 /***********************************************************************
3711 * SetupDiCallClassInstaller (SETUPAPI.@)
3712 */
3713 BOOL WINAPI SetupDiCallClassInstaller(
3714 IN DI_FUNCTION InstallFunction,
3715 IN HDEVINFO DeviceInfoSet,
3716 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
3717 {
3718 BOOL ret = FALSE;
3719
3720 TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
3721
3722 if (!DeviceInfoSet)
3723 SetLastError(ERROR_INVALID_PARAMETER);
3724 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
3725 SetLastError(ERROR_INVALID_HANDLE);
3726 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
3727 SetLastError(ERROR_INVALID_HANDLE);
3728 else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
3729 SetLastError(ERROR_INVALID_HANDLE);
3730 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3731 SetLastError(ERROR_INVALID_USER_BUFFER);
3732 else
3733 {
3734 SP_DEVINSTALL_PARAMS_W InstallParams;
3735 #define CLASS_COINSTALLER 0x1
3736 #define DEVICE_COINSTALLER 0x2
3737 #define CLASS_INSTALLER 0x4
3738 UCHAR CanHandle = 0;
3739 DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
3740
3741 switch (InstallFunction)
3742 {
3743 case DIF_ADDPROPERTYPAGE_ADVANCED:
3744 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3745 break;
3746 case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
3747 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3748 break;
3749 case DIF_ALLOW_INSTALL:
3750 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3751 break;
3752 case DIF_DETECT:
3753 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3754 break;
3755 case DIF_DESTROYPRIVATEDATA:
3756 CanHandle = CLASS_INSTALLER;
3757 break;
3758 case DIF_INSTALLDEVICE:
3759 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3760 DefaultHandler = SetupDiInstallDevice;
3761 break;
3762 case DIF_INSTALLDEVICEFILES:
3763 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3764 DefaultHandler = SetupDiInstallDriverFiles;
3765 break;
3766 case DIF_INSTALLINTERFACES:
3767 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3768 DefaultHandler = SetupDiInstallDeviceInterfaces;
3769 break;
3770 case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
3771 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3772 break;
3773 case DIF_NEWDEVICEWIZARD_POSTANALYZE:
3774 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3775 break;
3776 case DIF_NEWDEVICEWIZARD_PREANALYZE:
3777 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3778 break;
3779 case DIF_NEWDEVICEWIZARD_PRESELECT:
3780 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3781 break;
3782 case DIF_NEWDEVICEWIZARD_SELECT:
3783 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3784 break;
3785 case DIF_POWERMESSAGEWAKE:
3786 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3787 break;
3788 case DIF_PROPERTYCHANGE:
3789 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3790 DefaultHandler = SetupDiChangeState;
3791 break;
3792 case DIF_REGISTER_COINSTALLERS:
3793 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3794 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
3795 break;
3796 case DIF_REGISTERDEVICE:
3797 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3798 DefaultHandler = IntSetupDiRegisterDeviceInfo;
3799 break;
3800 case DIF_REMOVE:
3801 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3802 DefaultHandler = SetupDiRemoveDevice;
3803 break;
3804 case DIF_SELECTBESTCOMPATDRV:
3805 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3806 DefaultHandler = SetupDiSelectBestCompatDrv;
3807 break;
3808 case DIF_SELECTDEVICE:
3809 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
3810 DefaultHandler = SetupDiSelectBestCompatDrv;
3811 break;
3812 case DIF_TROUBLESHOOTER:
3813 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3814 break;
3815 case DIF_UNREMOVE:
3816 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
3817 DefaultHandler = SetupDiUnremoveDevice;
3818 break;
3819 default:
3820 ERR("Install function %u not supported\n", InstallFunction);
3821 SetLastError(ERROR_NOT_SUPPORTED);
3822 }
3823
3824 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
3825 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
3826 /* Don't process this call, as a parameter is invalid */
3827 CanHandle = 0;
3828
3829 if (CanHandle != 0)
3830 {
3831 LIST_ENTRY ClassCoInstallersListHead;
3832 LIST_ENTRY DeviceCoInstallersListHead;
3833 HMODULE ClassInstallerLibrary = NULL;
3834 CLASS_INSTALL_PROC ClassInstaller = NULL;
3835 COINSTALLER_CONTEXT_DATA Context;
3836 PLIST_ENTRY ListEntry;
3837 HKEY hKey;
3838 DWORD dwRegType, dwLength;
3839 DWORD rc = NO_ERROR;
3840
3841 InitializeListHead(&ClassCoInstallersListHead);
3842 InitializeListHead(&DeviceCoInstallersListHead);
3843
3844 if (CanHandle & DEVICE_COINSTALLER)
3845 {
3846 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
3847 if (hKey != INVALID_HANDLE_VALUE)
3848 {
3849 rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
3850 if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
3851 {
3852 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
3853 if (KeyBuffer != NULL)
3854 {
3855 rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
3856 if (rc == ERROR_SUCCESS)
3857 {
3858 LPWSTR ptr;
3859 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
3860 {
3861 /* Add coinstaller to DeviceCoInstallersListHead list */
3862 struct CoInstallerElement *coinstaller;
3863 TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
3864 coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
3865 if (!coinstaller)
3866 continue;
3867 memset(coinstaller, 0, sizeof(struct CoInstallerElement));
3868 if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
3869 InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
3870 else
3871 HeapFree(GetProcessHeap(), 0, coinstaller);
3872 }
3873 }
3874 HeapFree(GetProcessHeap(), 0, KeyBuffer);
3875 }
3876 }
3877 RegCloseKey(hKey);
3878 }
3879 }
3880 if (CanHandle & CLASS_COINSTALLER)
3881 {
3882 rc = RegOpenKeyEx(
3883 HKEY_LOCAL_MACHINE,
3884 REGSTR_PATH_CODEVICEINSTALLERS,
3885 0, /* Options */
3886 KEY_QUERY_VALUE,
3887 &hKey);
3888 if (rc == ERROR_SUCCESS)
3889 {
3890 LPWSTR lpGuidString;
3891 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
3892 {
3893 rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
3894 if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
3895 {
3896 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
3897 if (KeyBuffer != NULL)
3898 {
3899 rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
3900 if (rc == ERROR_SUCCESS)
3901 {
3902 LPWSTR ptr;
3903 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
3904 {
3905 /* Add coinstaller to ClassCoInstallersListHead list */
3906 struct CoInstallerElement *coinstaller;
3907 TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
3908 coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
3909 if (!coinstaller)
3910 continue;
3911 memset(coinstaller, 0, sizeof(struct CoInstallerElement));
3912 if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
3913 InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
3914 else
3915 HeapFree(GetProcessHeap(), 0, coinstaller);
3916 }
3917 }
3918 HeapFree(GetProcessHeap(), 0, KeyBuffer);
3919 }
3920 }
3921 RpcStringFreeW(&lpGuidString);
3922 }
3923 RegCloseKey(hKey);
3924 }
3925 }
3926 if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
3927 {
3928 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
3929 if (hKey != INVALID_HANDLE_VALUE)
3930 {
3931 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
3932 if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
3933 {
3934 LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
3935 if (KeyBuffer != NULL)
3936 {
3937 rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
3938 if (rc == ERROR_SUCCESS)
3939 {
3940 /* Get ClassInstaller function pointer */
3941 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
3942 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
3943 {
3944 InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
3945 SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
3946 }
3947 }
3948 HeapFree(GetProcessHeap(), 0, KeyBuffer);
3949 }
3950 }
3951 RegCloseKey(hKey);
3952 }
3953 }
3954
3955 /* Call Class co-installers */
3956 Context.PostProcessing = FALSE;
3957 rc = NO_ERROR;
3958 ListEntry = ClassCoInstallersListHead.Flink;
3959 while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
3960 {
3961 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3962 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3963 coinstaller->PrivateData = Context.PrivateData;
3964 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
3965 {
3966 coinstaller->DoPostProcessing = TRUE;
3967 rc = NO_ERROR;
3968 }
3969 ListEntry = ListEntry->Flink;
3970 }
3971
3972 /* Call Device co-installers */
3973 ListEntry = DeviceCoInstallersListHead.Flink;
3974 while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
3975 {
3976 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
3977 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
3978 coinstaller->PrivateData = Context.PrivateData;
3979 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
3980 {
3981 coinstaller->DoPostProcessing = TRUE;
3982 rc = NO_ERROR;
3983 }
3984 ListEntry = ListEntry->Flink;
3985 }
3986
3987 /* Call Class installer */
3988 if (ClassInstaller)
3989 {
3990 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
3991 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
3992 }
3993 else
3994 rc = ERROR_DI_DO_DEFAULT;
3995
3996 /* Call default handler */
3997 if (rc == ERROR_DI_DO_DEFAULT)
3998 {
3999 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4000 {
4001 if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4002 rc = NO_ERROR;
4003 else
4004 rc = GetLastError();
4005 }
4006 else
4007 rc = NO_ERROR;
4008 }
4009
4010 /* Call Class co-installers that required postprocessing */
4011 Context.PostProcessing = TRUE;
4012 ListEntry = ClassCoInstallersListHead.Flink;
4013 while (ListEntry != &ClassCoInstallersListHead)
4014 {
4015 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
4016 if (coinstaller->DoPostProcessing)
4017 {
4018 Context.InstallResult = rc;
4019 Context.PrivateData = coinstaller->PrivateData;
4020 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4021 }
4022 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4023 ListEntry = ListEntry->Flink;
4024 }
4025
4026 /* Call Device co-installers that required postprocessing */
4027 ListEntry = DeviceCoInstallersListHead.Flink;
4028 while (ListEntry != &DeviceCoInstallersListHead)
4029 {
4030 struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
4031 if (coinstaller->DoPostProcessing)
4032 {
4033 Context.InstallResult = rc;
4034 Context.PrivateData = coinstaller->PrivateData;
4035 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4036 }
4037 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4038 ListEntry = ListEntry->Flink;
4039 }
4040
4041 /* Free allocated memory */
4042 while (!IsListEmpty(&ClassCoInstallersListHead))
4043 {
4044 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4045 HeapFree(GetProcessHeap(), 0, ListEntry);
4046 }
4047 while (!IsListEmpty(&DeviceCoInstallersListHead))
4048 {
4049 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4050 HeapFree(GetProcessHeap(), 0, ListEntry);
4051 }
4052
4053 ret = (rc == NO_ERROR);
4054 }
4055 }
4056
4057 TRACE("Returning %d\n", ret);
4058 return ret;
4059 }
4060
4061 /***********************************************************************
4062 * SetupDiGetDeviceInfoListClass (SETUPAPI.@)
4063 */
4064 BOOL WINAPI SetupDiGetDeviceInfoListClass(
4065 IN HDEVINFO DeviceInfoSet,
4066 OUT LPGUID ClassGuid)
4067 {
4068 struct DeviceInfoSet *list;
4069 BOOL ret = FALSE;
4070
4071 TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
4072
4073 if (!DeviceInfoSet)
4074 SetLastError(ERROR_INVALID_HANDLE);
4075 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4076 SetLastError(ERROR_INVALID_HANDLE);
4077 else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4078 SetLastError(ERROR_NO_ASSOCIATED_CLASS);
4079 else
4080 {
4081 memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
4082
4083 ret = TRUE;
4084 }
4085
4086 TRACE("Returning %d\n", ret);
4087 return ret;
4088 }
4089
4090 /***********************************************************************
4091 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
4092 */
4093 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
4094 IN HDEVINFO DeviceInfoSet,
4095 OUT PSP_DEVINFO_LIST_DETAIL_DATA_W DeviceInfoListDetailData)
4096 {
4097 struct DeviceInfoSet *list;
4098 BOOL ret = FALSE;
4099
4100 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoListDetailData);
4101
4102 if (!DeviceInfoSet)
4103 SetLastError(ERROR_INVALID_HANDLE);
4104 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4105 SetLastError(ERROR_INVALID_HANDLE);
4106 else if (!DeviceInfoListDetailData)
4107 SetLastError(ERROR_INVALID_PARAMETER);
4108 else if (DeviceInfoListDetailData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
4109 SetLastError(ERROR_INVALID_USER_BUFFER);
4110 else
4111 {
4112 memcpy(
4113 &DeviceInfoListDetailData->ClassGuid,
4114 &list->ClassGuid,
4115 sizeof(GUID));
4116 DeviceInfoListDetailData->RemoteMachineHandle = list->hMachine;
4117 if (list->MachineName)
4118 strcpyW(DeviceInfoListDetailData->RemoteMachineName, list->MachineName + 2);
4119 else
4120 DeviceInfoListDetailData->RemoteMachineName[0] = 0;
4121
4122 ret = TRUE;
4123 }
4124
4125 TRACE("Returning %d\n", ret);
4126 return ret;
4127 }
4128
4129 /***********************************************************************
4130 * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4131 */
4132 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
4133 IN HDEVINFO DeviceInfoSet,
4134 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4135 OUT PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
4136 {
4137 SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4138 BOOL ret = FALSE;
4139
4140 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4141
4142 if (DeviceInstallParams == NULL)
4143 SetLastError(ERROR_INVALID_PARAMETER);
4144 else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4145 SetLastError(ERROR_INVALID_USER_BUFFER);
4146 else
4147 {
4148 deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4149 ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4150
4151 if (ret)
4152 {
4153 /* Do W->A conversion */
4154 memcpy(
4155 DeviceInstallParams,
4156 &deviceInstallParamsW,
4157 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4158 if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4159 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4160 {
4161 DeviceInstallParams->DriverPath[0] = '\0';
4162 ret = FALSE;
4163 }
4164 }
4165 }
4166
4167 TRACE("Returning %d\n", ret);
4168 return ret;
4169 }
4170
4171 /***********************************************************************
4172 * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4173 */
4174 BOOL WINAPI SetupDiGetDeviceInstallParamsW(
4175 IN HDEVINFO DeviceInfoSet,
4176 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4177 OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4178 {
4179 struct DeviceInfoSet *list;
4180 BOOL ret = FALSE;
4181
4182 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4183
4184 if (!DeviceInfoSet)
4185 SetLastError(ERROR_INVALID_HANDLE);
4186 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4187 SetLastError(ERROR_INVALID_HANDLE);
4188 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4189 SetLastError(ERROR_INVALID_USER_BUFFER);
4190 else if (!DeviceInstallParams)
4191 SetLastError(ERROR_INVALID_PARAMETER);
4192 else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4193 SetLastError(ERROR_INVALID_USER_BUFFER);
4194 else
4195 {
4196 PSP_DEVINSTALL_PARAMS_W Source;
4197
4198 if (DeviceInfoData)
4199 Source = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
4200 else
4201 Source = &list->InstallParams;
4202 memcpy(DeviceInstallParams, Source, Source->cbSize);
4203 ret = TRUE;
4204 }
4205
4206 TRACE("Returning %d\n", ret);
4207 return ret;
4208 }
4209
4210 static BOOL
4211 CheckDeviceInstallParameters(
4212 IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4213 {
4214 DWORD SupportedFlags =
4215 DI_NOVCP | /* 0x00000008 */
4216 DI_DIDCOMPAT | /* 0x00000010 */
4217 DI_DIDCLASS | /* 0x00000020 */
4218 DI_NEEDRESTART | /* 0x00000080 */
4219 DI_NEEDREBOOT | /* 0x00000100 */
4220 DI_RESOURCEPAGE_ADDED | /* 0x00002000 */
4221 DI_PROPERTIES_CHANGE | /* 0x00004000 */
4222 DI_ENUMSINGLEINF | /* 0x00010000 */
4223 DI_CLASSINSTALLPARAMS | /* 0x00100000 */
4224 DI_NODI_DEFAULTACTION | /* 0x00200000 */
4225 DI_QUIETINSTALL | /* 0x00800000 */
4226 DI_NOFILECOPY | /* 0x01000000 */
4227 DI_DRIVERPAGE_ADDED; /* 0x04000000 */
4228 DWORD SupportedFlagsEx =
4229 DI_FLAGSEX_CI_FAILED | /* 0x00000004 */
4230 DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
4231 DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
4232 DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
4233 DI_FLAGSEX_NO_DRVREG_MODIFY; /* 0x00008000 */
4234 BOOL ret = FALSE;
4235
4236 /* FIXME: add support for more flags */
4237
4238 /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4239 * It should be checked before accessing to other values
4240 * of the SP_DEVINSTALL_PARAMS structure */
4241
4242 if (DeviceInstallParams->Flags & ~SupportedFlags)
4243 {
4244 FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4245 SetLastError(ERROR_INVALID_FLAGS);
4246 }
4247 else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4248 {
4249 FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4250 SetLastError(ERROR_INVALID_FLAGS);
4251 }
4252 else if ((DeviceInstallParams->Flags & DI_NOVCP)
4253 && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4254 SetLastError(ERROR_INVALID_USER_BUFFER);
4255 else
4256 {
4257 /* FIXME: check Reserved field */
4258 ret = TRUE;
4259 }
4260
4261 return ret;
4262 }
4263
4264 /***********************************************************************
4265 * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4266 */
4267 BOOL WINAPI SetupDiSetDeviceInstallParamsW(
4268 IN HDEVINFO DeviceInfoSet,
4269 IN PSP_DEVINFO_DATA DeviceInfoData,
4270 IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
4271 {
4272 struct DeviceInfoSet *list;
4273 BOOL ret = FALSE;
4274
4275 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4276
4277 if (!DeviceInfoSet)
4278 SetLastError(ERROR_INVALID_HANDLE);
4279 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4280 SetLastError(ERROR_INVALID_HANDLE);
4281 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4282 SetLastError(ERROR_INVALID_USER_BUFFER);
4283 else if (!DeviceInstallParams)
4284 SetLastError(ERROR_INVALID_PARAMETER);
4285 else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4286 SetLastError(ERROR_INVALID_USER_BUFFER);
4287 else if (CheckDeviceInstallParameters(DeviceInstallParams))
4288 {
4289 PSP_DEVINSTALL_PARAMS_W Destination;
4290
4291 if (DeviceInfoData)
4292 Destination = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams;
4293 else
4294 Destination = &list->InstallParams;
4295 memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4296 ret = TRUE;
4297 }
4298
4299 TRACE("Returning %d\n", ret);
4300 return ret;
4301 }
4302
4303 /***********************************************************************
4304 * SetupDiGetDeviceInstanceIdA(SETUPAPI.@)
4305 */
4306 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
4307 IN HDEVINFO DeviceInfoSet,
4308 IN PSP_DEVINFO_DATA DeviceInfoData,
4309 OUT PSTR DeviceInstanceId OPTIONAL,
4310 IN DWORD DeviceInstanceIdSize,
4311 OUT PDWORD RequiredSize OPTIONAL)
4312 {
4313 PWSTR DeviceInstanceIdW = NULL;
4314 BOOL ret = FALSE;
4315
4316 TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
4317 DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
4318
4319 if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
4320 SetLastError(ERROR_INVALID_PARAMETER);
4321 else
4322 {
4323 if (DeviceInstanceIdSize != 0)
4324 {
4325 DeviceInstanceIdW = MyMalloc(DeviceInstanceIdSize * sizeof(WCHAR));
4326 if (DeviceInstanceIdW == NULL)
4327 return FALSE;
4328 }
4329
4330 ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet, DeviceInfoData,
4331 DeviceInstanceIdW, DeviceInstanceIdSize,
4332 RequiredSize);
4333
4334 if (ret && DeviceInstanceIdW != NULL)
4335 {
4336 if (WideCharToMultiByte(CP_ACP, 0, DeviceInstanceIdW, -1,
4337 DeviceInstanceId, DeviceInstanceIdSize, NULL, NULL) == 0)
4338 {
4339 DeviceInstanceId[0] = '\0';
4340 ret = FALSE;
4341 }
4342 }
4343 }
4344
4345 TRACE("Returning %d\n", ret);
4346 return ret;
4347 }
4348
4349 /***********************************************************************
4350 * SetupDiGetDeviceInstanceIdW(SETUPAPI.@)
4351 */
4352 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
4353 IN HDEVINFO DeviceInfoSet,
4354 IN PSP_DEVINFO_DATA DeviceInfoData,
4355 OUT PWSTR DeviceInstanceId OPTIONAL,
4356 IN DWORD DeviceInstanceIdSize,
4357 OUT PDWORD RequiredSize OPTIONAL)
4358 {
4359 BOOL ret = FALSE;
4360
4361 TRACE("%p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
4362 DeviceInstanceId, DeviceInstanceIdSize, RequiredSize);
4363
4364 if (!DeviceInfoSet)
4365 SetLastError(ERROR_INVALID_HANDLE);
4366 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4367 SetLastError(ERROR_INVALID_HANDLE);
4368 else if (!DeviceInfoData)
4369 SetLastError(ERROR_INVALID_PARAMETER);
4370 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4371 SetLastError(ERROR_INVALID_USER_BUFFER);
4372 else if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
4373 SetLastError(ERROR_INVALID_PARAMETER);
4374 else if (DeviceInstanceId && DeviceInstanceIdSize == 0)
4375 SetLastError(ERROR_INVALID_PARAMETER);
4376 else
4377 {
4378 struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4379 DWORD required;
4380
4381 required = (strlenW(DevInfo->DeviceName) + 1) * sizeof(WCHAR);
4382 if (RequiredSize)
4383 *RequiredSize = required;
4384
4385 if (required <= DeviceInstanceIdSize)
4386 {
4387 strcpyW(DeviceInstanceId, DevInfo->DeviceName);
4388 ret = TRUE;
4389 }
4390 else
4391 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4392 }
4393
4394 TRACE("Returning %d\n", ret);
4395 return ret;
4396 }
4397
4398 /***********************************************************************
4399 * SetupDiGetClassDevPropertySheetsA(SETUPAPI.@)
4400 */
4401 BOOL WINAPI SetupDiGetClassDevPropertySheetsA(
4402 IN HDEVINFO DeviceInfoSet,
4403 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4404 IN LPPROPSHEETHEADERA PropertySheetHeader,
4405 IN DWORD PropertySheetHeaderPageListSize,
4406 OUT PDWORD RequiredSize OPTIONAL,
4407 IN DWORD PropertySheetType)
4408 {
4409 PROPSHEETHEADERW psh;
4410 BOOL ret = FALSE;
4411
4412 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
4413 PropertySheetHeader, PropertySheetHeaderPageListSize,
4414 RequiredSize, PropertySheetType);
4415
4416 psh.dwFlags = PropertySheetHeader->dwFlags;
4417 psh.phpage = PropertySheetHeader->phpage;
4418 psh.nPages = PropertySheetHeader->nPages;
4419
4420 ret = SetupDiGetClassDevPropertySheetsW(DeviceInfoSet, DeviceInfoData, PropertySheetHeader ? &psh : NULL,
4421 PropertySheetHeaderPageListSize, RequiredSize,
4422 PropertySheetType);
4423 if (ret)
4424 {
4425 PropertySheetHeader->nPages = psh.nPages;
4426 }
4427
4428 TRACE("Returning %d\n", ret);
4429 return ret;
4430 }
4431
4432 struct ClassDevPropertySheetsData
4433 {
4434 HPROPSHEETPAGE *PropertySheetPages;
4435 DWORD MaximumNumberOfPages;
4436 DWORD NumberOfPages;
4437 };
4438
4439 static BOOL WINAPI GetClassDevPropertySheetsCallback(
4440 IN HPROPSHEETPAGE hPropSheetPage,
4441 IN OUT LPARAM lParam)
4442 {
4443 struct ClassDevPropertySheetsData *PropPageData;
4444
4445 PropPageData = (struct ClassDevPropertySheetsData *)lParam;
4446
4447 if (PropPageData->NumberOfPages < PropPageData->MaximumNumberOfPages)
4448 {
4449 *PropPageData->PropertySheetPages = hPropSheetPage;
4450 PropPageData->PropertySheetPages++;
4451 }
4452
4453 PropPageData->NumberOfPages++;
4454 return TRUE;
4455 }
4456
4457 /***********************************************************************
4458 * SetupDiGetClassDevPropertySheetsW(SETUPAPI.@)
4459 */
4460 BOOL WINAPI SetupDiGetClassDevPropertySheetsW(
4461 IN HDEVINFO DeviceInfoSet,
4462 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
4463 IN OUT LPPROPSHEETHEADERW PropertySheetHeader,
4464 IN DWORD PropertySheetHeaderPageListSize,
4465 OUT PDWORD RequiredSize OPTIONAL,
4466 IN DWORD PropertySheetType)
4467 {
4468 struct DeviceInfoSet *list;
4469 BOOL ret = FALSE;
4470
4471 TRACE("%p %p %p 0%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
4472 PropertySheetHeader, PropertySheetHeaderPageListSize,
4473 RequiredSize, PropertySheetType);
4474
4475 if (!DeviceInfoSet)
4476 SetLastError(ERROR_INVALID_HANDLE);
4477 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4478 SetLastError(ERROR_INVALID_HANDLE);
4479 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4480 SetLastError(ERROR_INVALID_HANDLE);
4481 else if (!PropertySheetHeader)
4482 SetLastError(ERROR_INVALID_PARAMETER);
4483 else if (PropertySheetHeader->dwFlags & PSH_PROPSHEETPAGE)
4484 SetLastError(ERROR_INVALID_FLAGS);
4485 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4486 SetLastError(ERROR_INVALID_USER_BUFFER);
4487 else if (!DeviceInfoData && IsEqualIID(&list->ClassGuid, &GUID_NULL))
4488 SetLastError(ERROR_INVALID_PARAMETER);
4489 else if (!PropertySheetHeader)
4490 SetLastError(ERROR_INVALID_PARAMETER);
4491 else if (PropertySheetType != DIGCDP_FLAG_ADVANCED
4492 && PropertySheetType != DIGCDP_FLAG_BASIC
4493 && PropertySheetType != DIGCDP_FLAG_REMOTE_ADVANCED
4494 && PropertySheetType != DIGCDP_FLAG_REMOTE_BASIC)
4495 SetLastError(ERROR_INVALID_PARAMETER);
4496 else
4497 {
4498 HKEY hKey = INVALID_HANDLE_VALUE;
4499 SP_PROPSHEETPAGE_REQUEST Request;
4500 LPWSTR PropPageProvider = NULL;
4501 HMODULE hModule = NULL;
4502 PROPERTY_PAGE_PROVIDER pPropPageProvider = NULL;
4503 struct ClassDevPropertySheetsData PropPageData;
4504 DWORD dwLength, dwRegType;
4505 DWORD rc;
4506
4507 if (DeviceInfoData)
4508 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
4509 else
4510 {
4511 hKey = SetupDiOpenClassRegKeyExW(&list->ClassGuid, KEY_QUERY_VALUE,
4512 DIOCR_INSTALLER, list->MachineName + 2, NULL);
4513 }
4514 if (hKey == INVALID_HANDLE_VALUE)
4515 goto cleanup;
4516
4517 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, &dwRegType, NULL, &dwLength);
4518 if (rc == ERROR_FILE_NOT_FOUND)
4519 {
4520 /* No registry key. As it is optional, don't say it's a bad error */
4521 if (RequiredSize)
4522 *RequiredSize = 0;
4523 ret = TRUE;
4524 goto cleanup;
4525 }
4526 else if (rc != ERROR_SUCCESS && dwRegType != REG_SZ)
4527 {
4528 SetLastError(rc);
4529 goto cleanup;
4530 }
4531
4532 PropPageProvider = HeapAlloc(GetProcessHeap(), 0, dwLength + sizeof(WCHAR));
4533 if (!PropPageProvider)
4534 {
4535 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4536 goto cleanup;
4537 }
4538 rc = RegQueryValueExW(hKey, REGSTR_VAL_ENUMPROPPAGES_32, NULL, NULL, (LPBYTE)PropPageProvider, &dwLength);
4539 if (rc != ERROR_SUCCESS)
4540 {
4541 SetLastError(rc);
4542 goto cleanup;
4543 }
4544 PropPageProvider[dwLength / sizeof(WCHAR)] = 0;
4545
4546 rc = GetFunctionPointer(PropPageProvider, &hModule, (PVOID*)&pPropPageProvider);
4547 if (rc != ERROR_SUCCESS)
4548 {
4549 SetLastError(ERROR_INVALID_PROPPAGE_PROVIDER);
4550 goto cleanup;
4551 }
4552
4553 Request.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
4554 Request.PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
4555 Request.DeviceInfoSet = DeviceInfoSet;
4556 Request.DeviceInfoData = DeviceInfoData;
4557 PropPageData.PropertySheetPages = &PropertySheetHeader->phpage[PropertySheetHeader->nPages];
4558 PropPageData.MaximumNumberOfPages = PropertySheetHeaderPageListSize - PropertySheetHeader->nPages;
4559 PropPageData.NumberOfPages = 0;
4560 ret = pPropPageProvider(&Request, GetClassDevPropertySheetsCallback, (LPARAM)&PropPageData);
4561 if (!ret)
4562 goto cleanup;
4563
4564 if (RequiredSize)
4565 *RequiredSize = PropPageData.NumberOfPages + PropertySheetHeader->nPages;
4566 if (PropPageData.NumberOfPages <= PropPageData.MaximumNumberOfPages)
4567 {
4568 PropertySheetHeader->nPages += PropPageData.NumberOfPages;
4569 ret = TRUE;
4570 }
4571 else
4572 {
4573 PropertySheetHeader->nPages += PropPageData.MaximumNumberOfPages;
4574 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4575 }
4576
4577 cleanup:
4578 if (hKey != INVALID_HANDLE_VALUE)
4579 RegCloseKey(hKey);
4580 HeapFree(GetProcessHeap(), 0, PropPageProvider);
4581 FreeFunctionPointer(hModule, pPropPageProvider);
4582 }
4583
4584 TRACE("Returning %d\n", ret);
4585 return ret;
4586 }
4587
4588 /***********************************************************************
4589 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
4590 */
4591 HKEY WINAPI SetupDiCreateDevRegKeyA(
4592 IN HDEVINFO DeviceInfoSet,
4593 IN PSP_DEVINFO_DATA DeviceInfoData,
4594 IN DWORD Scope,
4595 IN DWORD HwProfile,
4596 IN DWORD KeyType,
4597 IN HINF InfHandle OPTIONAL,
4598 IN PCSTR InfSectionName OPTIONAL)
4599 {
4600 PCWSTR InfSectionNameW = NULL;
4601 HKEY ret = INVALID_HANDLE_VALUE;
4602
4603 if (InfSectionName)
4604 {
4605 InfSectionNameW = MultiByteToUnicode(InfSectionName, CP_ACP);
4606 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
4607 }
4608
4609 ret = SetupDiCreateDevRegKeyW(DeviceInfoSet,
4610 DeviceInfoData,
4611 Scope,
4612 HwProfile,
4613 KeyType,
4614 InfHandle,
4615 InfSectionNameW);
4616
4617 if (InfSectionNameW != NULL)
4618 MyFree((PVOID)InfSectionNameW);
4619
4620 return ret;
4621 }
4622
4623 static HKEY
4624 OpenHardwareProfileKey(
4625 IN HKEY HKLM,
4626 IN DWORD HwProfile,
4627 IN DWORD samDesired)
4628 {
4629 HKEY hHWProfilesKey = INVALID_HANDLE_VALUE;
4630 HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
4631 HKEY ret = INVALID_HANDLE_VALUE;
4632 LONG rc;
4633
4634 rc = RegOpenKeyExW(HKLM,
4635 REGSTR_PATH_HWPROFILES,
4636 0,
4637 0,
4638 &hHWProfilesKey);
4639 if (rc != ERROR_SUCCESS)
4640 {
4641 SetLastError(rc);
4642 goto cleanup;
4643 }
4644 if (HwProfile == 0)
4645 {
4646 rc = RegOpenKeyExW(
4647 hHWProfilesKey,
4648 REGSTR_KEY_CURRENT,
4649 0,
4650 KEY_CREATE_SUB_KEY,
4651 &hHWProfileKey);
4652 }
4653 else
4654 {
4655 WCHAR subKey[5];
4656 snprintfW(subKey, 4, L"%04lu", HwProfile);
4657 subKey[4] = '\0';
4658 rc = RegOpenKeyExW(
4659 hHWProfilesKey,
4660 subKey,
4661 0,
4662 KEY_CREATE_SUB_KEY,
4663 &hHWProfileKey);
4664 }
4665 if (rc != ERROR_SUCCESS)
4666 {
4667 SetLastError(rc);
4668 goto cleanup;
4669 }
4670 ret = hHWProfileKey;
4671
4672 cleanup:
4673 if (hHWProfilesKey != INVALID_HANDLE_VALUE)
4674 RegCloseKey(hHWProfilesKey);
4675 if (hHWProfileKey != INVALID_HANDLE_VALUE && hHWProfileKey != ret)
4676 RegCloseKey(hHWProfileKey);
4677 return ret;
4678 }
4679
4680 /***********************************************************************
4681 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
4682 */
4683 HKEY WINAPI SetupDiCreateDevRegKeyW(
4684 IN HDEVINFO DeviceInfoSet,
4685 IN PSP_DEVINFO_DATA DeviceInfoData,
4686 IN DWORD Scope,
4687 IN DWORD HwProfile,
4688 IN DWORD KeyType,
4689 IN HINF InfHandle OPTIONAL,
4690 IN PCWSTR InfSectionName OPTIONAL)
4691 {
4692 struct DeviceInfoSet *list;
4693 HKEY ret = INVALID_HANDLE_VALUE;
4694
4695 TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData,
4696 Scope, HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
4697
4698 if (!DeviceInfoSet)
4699 SetLastError(ERROR_INVALID_HANDLE);
4700 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4701 SetLastError(ERROR_INVALID_HANDLE);
4702 else if (!DeviceInfoData)
4703 SetLastError(ERROR_INVALID_PARAMETER);
4704 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4705 SetLastError(ERROR_INVALID_USER_BUFFER);
4706 else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4707 SetLastError(ERROR_INVALID_PARAMETER);
4708 else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4709 SetLastError(ERROR_INVALID_PARAMETER);
4710 else if (InfHandle && !InfSectionName)
4711 SetLastError(ERROR_INVALID_PARAMETER);
4712 else if (!InfHandle && InfSectionName)
4713 SetLastError(ERROR_INVALID_PARAMETER);
4714 else
4715 {
4716 LPWSTR lpGuidString = NULL;
4717 LPWSTR DriverKey = NULL; /* {GUID}\Index */
4718 LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
4719 DWORD Index; /* Index used in the DriverKey name */
4720 DWORD rc;
4721 HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
4722 HKEY hEnumKey = INVALID_HANDLE_VALUE;
4723 HKEY hClassKey = INVALID_HANDLE_VALUE;
4724 HKEY hDeviceKey = INVALID_HANDLE_VALUE;
4725 HKEY hKey = INVALID_HANDLE_VALUE;
4726 HKEY RootKey;
4727
4728 if (Scope == DICS_FLAG_GLOBAL)
4729 RootKey = list->HKLM;
4730 else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
4731 {
4732 hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
4733 if (hHWProfileKey == INVALID_HANDLE_VALUE)
4734 goto cleanup;
4735 RootKey = hHWProfileKey;
4736 }
4737
4738 if (KeyType == DIREG_DEV)
4739 {
4740 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4741
4742 rc = RegCreateKeyExW(
4743 RootKey,
4744 REGSTR_PATH_SYSTEMENUM,
4745 0,
4746 NULL,
4747 REG_OPTION_NON_VOLATILE,
4748 KEY_CREATE_SUB_KEY,
4749 NULL,
4750 &hEnumKey,
4751 NULL);
4752 if (rc != ERROR_SUCCESS)
4753 {
4754 SetLastError(rc);
4755 goto cleanup;
4756 }
4757 rc = RegCreateKeyExW(
4758 hEnumKey,
4759 deviceInfo->DeviceName,
4760 0,
4761 NULL,
4762 REG_OPTION_NON_VOLATILE,
4763 #if _WIN32_WINNT >= 0x502
4764 KEY_READ | KEY_WRITE,
4765 #else
4766 KEY_ALL_ACCESS,
4767 #endif
4768 NULL,
4769 &hKey,
4770 NULL);
4771 if (rc != ERROR_SUCCESS)
4772 {
4773 SetLastError(rc);
4774 goto cleanup;
4775 }
4776 }
4777 else /* KeyType == DIREG_DRV */
4778 {
4779 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
4780 goto cleanup;
4781 /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
4782 DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_STRING));
4783 if (!DriverKey)
4784 {
4785 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4786 goto cleanup;
4787 }
4788 strcpyW(DriverKey, L"{");
4789 strcatW(DriverKey, lpGuidString);
4790 strcatW(DriverKey, L"}\\");
4791 pDeviceInstance = &DriverKey[strlenW(DriverKey)];
4792 rc = RegOpenKeyExW(RootKey,
4793 REGSTR_PATH_CLASS_NT,
4794 0,
4795 KEY_CREATE_SUB_KEY,
4796 &hClassKey);
4797 if (rc != ERROR_SUCCESS)
4798 {
4799 SetLastError(rc);
4800 goto cleanup;
4801 }
4802
4803 /* Try all values for Index between 0 and 9999 */
4804 Index = 0;
4805 while (Index <= 9999)
4806 {
4807 DWORD Disposition;
4808 wsprintf(pDeviceInstance, L"%04lu", Index);
4809 rc = RegCreateKeyEx(hClassKey,
4810 DriverKey,
4811 0,
4812 NULL,
4813 REG_OPTION_NON_VOLATILE,
4814 #if _WIN32_WINNT >= 0x502
4815 KEY_READ | KEY_WRITE,
4816 #else
4817 KEY_ALL_ACCESS,
4818 #endif
4819 NULL,
4820 &hKey,
4821 &Disposition);
4822 if (rc != ERROR_SUCCESS)
4823 {
4824 SetLastError(rc);
4825 goto cleanup;
4826 }
4827 if (Disposition == REG_CREATED_NEW_KEY)
4828 break;
4829 RegCloseKey(hKey);
4830 hKey = INVALID_HANDLE_VALUE;
4831 Index++;
4832 }
4833 if (Index > 9999)
4834 {
4835 /* Unable to create more than 9999 devices within the same class */
4836 SetLastError(ERROR_GEN_FAILURE);
4837 goto cleanup;
4838 }
4839
4840 /* Open device key, to write Driver value */
4841 hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_SET_VALUE);
4842 if (hDeviceKey == INVALID_HANDLE_VALUE)
4843 goto cleanup;
4844 rc = RegSetValueEx(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
4845 if (rc != ERROR_SUCCESS)
4846 {
4847 SetLastError(rc);
4848 goto cleanup;
4849 }
4850 }
4851
4852 /* Do installation of the specified section */
4853 if (InfHandle)
4854 {
4855 FIXME("Need to install section %s in file %p\n",
4856 debugstr_w(InfSectionName), InfHandle);
4857 }
4858 ret = hKey;
4859
4860 cleanup:
4861 if (lpGuidString)
4862 RpcStringFreeW(&lpGuidString);
4863 HeapFree(GetProcessHeap(), 0, DriverKey);
4864 if (hHWProfileKey != INVALID_HANDLE_VALUE)
4865 RegCloseKey(hHWProfileKey);
4866 if (hEnumKey != INVALID_HANDLE_VALUE)
4867 RegCloseKey(hEnumKey);
4868 if (hClassKey != INVALID_HANDLE_VALUE)
4869 RegCloseKey(hClassKey);
4870 if (hDeviceKey != INVALID_HANDLE_VALUE)
4871 RegCloseKey(hDeviceKey);
4872 if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
4873 RegCloseKey(hKey);
4874 }
4875
4876 TRACE("Returning 0x%p\n", ret);
4877 return ret;
4878 }
4879
4880 /***********************************************************************
4881 * SetupDiOpenDevRegKey (SETUPAPI.@)
4882 */
4883 HKEY WINAPI SetupDiOpenDevRegKey(
4884 HDEVINFO DeviceInfoSet,
4885 PSP_DEVINFO_DATA DeviceInfoData,
4886 DWORD Scope,
4887 DWORD HwProfile,
4888 DWORD KeyType,
4889 REGSAM samDesired)
4890 {
4891 struct DeviceInfoSet *list;
4892 HKEY ret = INVALID_HANDLE_VALUE;
4893
4894 TRACE("%p %p %lu %lu %lu 0x%lx\n", DeviceInfoSet, DeviceInfoData,
4895 Scope, HwProfile, KeyType, samDesired);
4896
4897 if (!DeviceInfoSet)
4898 SetLastError(ERROR_INVALID_HANDLE);
4899 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
4900 SetLastError(ERROR_INVALID_HANDLE);
4901 else if (!DeviceInfoData)
4902 SetLastError(ERROR_INVALID_PARAMETER);
4903 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4904 SetLastError(ERROR_INVALID_USER_BUFFER);
4905 else if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
4906 SetLastError(ERROR_INVALID_PARAMETER);
4907 else if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
4908 SetLastError(ERROR_INVALID_PARAMETER);
4909 else
4910 {
4911 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
4912 LPWSTR DriverKey = NULL;
4913 DWORD dwLength = 0;
4914 DWORD dwRegType;
4915 DWORD rc;
4916 HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
4917 HKEY hEnumKey = INVALID_HANDLE_VALUE;
4918 HKEY hKey = INVALID_HANDLE_VALUE;
4919 HKEY RootKey;
4920
4921 if (Scope == DICS_FLAG_GLOBAL)
4922 RootKey = list->HKLM;
4923 else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
4924 {
4925 hHWProfileKey = OpenHardwareProfileKey(list->HKLM, HwProfile, 0);
4926 if (hHWProfileKey == INVALID_HANDLE_VALUE)
4927 goto cleanup;
4928 RootKey = hHWProfileKey;
4929 }
4930
4931 rc = RegOpenKeyExW(
4932 RootKey,
4933 REGSTR_PATH_SYSTEMENUM,
4934 0, /* Options */
4935 0,
4936 &hEnumKey);
4937 if (rc != ERROR_SUCCESS)
4938 {
4939 SetLastError(rc);
4940 goto cleanup;
4941 }
4942 rc = RegOpenKeyExW(
4943 hEnumKey,
4944 deviceInfo->DeviceName,
4945 0, /* Options */
4946 KeyType == DIREG_DEV ? samDesired : KEY_QUERY_VALUE,
4947 &hKey);
4948 RegCloseKey(hEnumKey);
4949 hEnumKey = INVALID_HANDLE_VALUE;
4950 if (rc != ERROR_SUCCESS)
4951 {
4952 SetLastError(rc);
4953 goto cleanup;
4954 }
4955 if (KeyType == DIREG_DEV)
4956 {
4957 /* We're done. Just return the hKey handle */
4958 ret = hKey;
4959 goto cleanup;
4960 }
4961 /* Read the 'Driver' key */
4962 rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
4963 if (rc != ERROR_SUCCESS)
4964 {
4965 SetLastError(rc);
4966 goto cleanup;
4967 }
4968 else if (dwRegType != REG_SZ)
4969 {
4970 SetLastError(ERROR_GEN_FAILURE);
4971 goto cleanup;
4972 }
4973 DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
4974 if (!DriverKey)
4975 {
4976 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4977 goto cleanup;
4978 }
4979 rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
4980 if (rc != ERROR_SUCCESS)
4981 {
4982 SetLastError(rc);
4983 goto cleanup;
4984 }
4985 RegCloseKey(hKey);
4986 hKey = INVALID_HANDLE_VALUE;
4987 /* Need to open the driver key */
4988 rc = RegOpenKeyExW(
4989 RootKey,
4990 REGSTR_PATH_CLASS_NT,
4991 0, /* Options */
4992 0,
4993 &hEnumKey);
4994 if (rc != ERROR_SUCCESS)
4995 {
4996 SetLastError(rc);
4997 goto cleanup;
4998 }
4999 rc = RegOpenKeyExW(
5000 hEnumKey,
5001 DriverKey,
5002 0, /* Options */
5003 samDesired,
5004 &hKey);
5005 if (rc != ERROR_SUCCESS)
5006 {
5007 SetLastError(rc);
5008 goto cleanup;
5009 }
5010 ret = hKey;
5011
5012 cleanup:
5013 if (hHWProfileKey != INVALID_HANDLE_VALUE)
5014 RegCloseKey(hHWProfileKey);
5015 if (hEnumKey != INVALID_HANDLE_VALUE)
5016 RegCloseKey(hEnumKey);
5017 if (hKey != INVALID_HANDLE_VALUE && hKey != ret)
5018 RegCloseKey(hKey);
5019 }
5020
5021 TRACE("Returning 0x%p\n", ret);
5022 return ret;
5023 }
5024
5025 /***********************************************************************
5026 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
5027 */
5028 BOOL WINAPI SetupDiCreateDeviceInfoA(
5029 HDEVINFO DeviceInfoSet,
5030 PCSTR DeviceName,
5031 CONST GUID *ClassGuid,
5032 PCSTR DeviceDescription,
5033 HWND hwndParent,
5034 DWORD CreationFlags,
5035 PSP_DEVINFO_DATA DeviceInfoData)
5036 {
5037 LPWSTR DeviceNameW = NULL;
5038 LPWSTR DeviceDescriptionW = NULL;
5039 BOOL bResult;
5040
5041 TRACE("\n");
5042
5043 if (DeviceName)
5044 {
5045 DeviceNameW = MultiByteToUnicode(DeviceName, CP_ACP);
5046 if (DeviceNameW == NULL) return FALSE;
5047 }
5048 if (DeviceDescription)
5049 {
5050 DeviceDescriptionW = MultiByteToUnicode(DeviceDescription, CP_ACP);
5051 if (DeviceDescriptionW == NULL)
5052 {
5053 if (DeviceNameW) MyFree(DeviceNameW);
5054 return FALSE;
5055 }
5056 }
5057
5058 bResult = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW,
5059 ClassGuid, DeviceDescriptionW,
5060 hwndParent, CreationFlags,
5061 DeviceInfoData);
5062
5063 if (DeviceNameW) MyFree(DeviceNameW);
5064 if (DeviceDescriptionW) MyFree(DeviceDescriptionW);
5065
5066 return bResult;
5067 }
5068
5069 /***********************************************************************
5070 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
5071 */
5072 BOOL WINAPI SetupDiCreateDeviceInfoW(
5073 HDEVINFO DeviceInfoSet,
5074 PCWSTR DeviceName,
5075 CONST GUID *ClassGuid,
5076 PCWSTR DeviceDescription,
5077 HWND hwndParent,
5078 DWORD CreationFlags,
5079 PSP_DEVINFO_DATA DeviceInfoData)
5080 {
5081 struct DeviceInfoSet *list;
5082 BOOL ret = FALSE;
5083
5084 TRACE("%p %s %s %s %p %lx %p\n", DeviceInfoSet, debugstr_w(DeviceName),
5085 debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
5086 hwndParent, CreationFlags, DeviceInfoData);
5087
5088 if (!DeviceInfoSet)
5089 SetLastError(ERROR_INVALID_HANDLE);
5090 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
5091 SetLastError(ERROR_INVALID_HANDLE);
5092 else if (!ClassGuid)
5093 SetLastError(ERROR_INVALID_PARAMETER);
5094 else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, ClassGuid))
5095 SetLastError(ERROR_CLASS_MISMATCH);
5096 else if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
5097 {
5098 TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
5099 SetLastError(ERROR_INVALID_FLAGS);
5100 }
5101 else
5102 {
5103 SP_DEVINFO_DATA DevInfo;
5104
5105 if (CreationFlags & DICD_GENERATE_ID)
5106 {
5107 /* Generate a new unique ID for this device */
5108 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5109 FIXME("not implemented\n");
5110 }
5111 else
5112 {
5113 /* Device name is fully qualified. Try to open it */
5114 BOOL rc;
5115
5116 DevInfo.cbSize = sizeof(SP_DEVINFO_DATA);
5117 rc = SetupDiOpenDeviceInfoW(
5118 DeviceInfoSet,
5119 DeviceName,
5120 NULL, /* hwndParent */
5121 CreationFlags & DICD_INHERIT_CLASSDRVS ? DIOD_INHERIT_CLASSDRVS : 0,
5122 &DevInfo);
5123
5124 if (rc)
5125 {
5126 /* SetupDiOpenDeviceInfoW has already added
5127 * the device info to the device info set
5128 */
5129 SetLastError(ERROR_DEVINST_ALREADY_EXISTS);
5130 }
5131 else if (GetLastError() == ERROR_FILE_NOT_FOUND)
5132 {
5133 struct DeviceInfoElement *deviceInfo;
5134
5135 if (CreateDeviceInfoElement(list, DeviceName, ClassGuid, &deviceInfo))
5136 {
5137 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
5138
5139 if (!DeviceInfoData)
5140 ret = TRUE;
5141 else
5142 {
5143 if (DeviceInfoData->cbSize != sizeof(PSP_DEVINFO_DATA))
5144 {
5145 SetLastError(ERROR_INVALID_USER_BUFFER);
5146 }
5147 else
5148 {
5149 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
5150 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
5151 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
5152 ret = TRUE;
5153 }
5154 }
5155 }
5156 }
5157 }
5158 }
5159
5160 TRACE("Returning %d\n", ret);
5161 return ret;
5162 }
5163
5164 /***********************************************************************
5165 * Helper functions for SetupDiBuildDriverInfoList
5166 */
5167 static BOOL
5168 AddDriverToList(
5169 IN PLIST_ENTRY DriverListHead,
5170 IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
5171 IN LPGUID ClassGuid,
5172 IN INFCONTEXT ContextDevice,
5173 IN struct InfFileDetails *InfFileDetails,
5174 IN LPCWSTR InfFile,
5175 IN LPCWSTR ProviderName,
5176 IN LPCWSTR ManufacturerName,
5177 IN LPCWSTR MatchingId,
5178 FILETIME DriverDate,
5179 DWORDLONG DriverVersion,
5180 IN DWORD Rank)
5181 {
5182 struct DriverInfoElement *driverInfo = NULL;
5183 HANDLE hFile = INVALID_HANDLE_VALUE;
5184 DWORD RequiredSize = 128; /* Initial buffer size */
5185 BOOL Result = FALSE;
5186 PLIST_ENTRY PreviousEntry;
5187 LPWSTR InfInstallSection = NULL;
5188 BOOL ret = FALSE;
5189
5190 driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
5191 if (!driverInfo)
5192 {
5193 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5194 goto cleanup;
5195 }
5196 memset(driverInfo, 0, sizeof(struct DriverInfoElement));
5197
5198 driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
5199 driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
5200
5201 /* Copy InfFileName field */
5202 strncpyW(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
5203 driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
5204
5205 /* Fill InfDate field */
5206 /* FIXME: hFile = CreateFile(driverInfo->Details.InfFileName,
5207 GENERIC_READ, FILE_SHARE_READ,
5208 NULL, OPEN_EXISTING, 0, NULL);
5209 if (hFile == INVALID_HANDLE_VALUE)
5210 goto cleanup;
5211 Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate);
5212 if (!Result)
5213 goto cleanup;*/
5214
5215 /* Fill SectionName field */
5216 Result = SetupGetStringFieldW(
5217 &ContextDevice,
5218 1,
5219 driverInfo->Details.SectionName, LINE_LEN,
5220 NULL);
5221 if (!Result)
5222 goto cleanup;
5223
5224 /* Fill DrvDescription field */
5225 Result = SetupGetStringFieldW(
5226 &ContextDevice,
5227 0, /* Field index */
5228 driverInfo->Details.DrvDescription, LINE_LEN,
5229 NULL);
5230
5231 /* Copy MatchingId information */
5232 if (MatchingId)
5233 {
5234 driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
5235 if (!driverInfo->MatchingId)
5236 {
5237 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5238 goto cleanup;
5239 }
5240 RtlCopyMemory(driverInfo->MatchingId, MatchingId, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
5241 }
5242 else
5243 driverInfo->MatchingId = NULL;
5244
5245 /* Get inf install section */
5246 Result = FALSE;
5247 RequiredSize = 128; /* Initial buffer size */
5248 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5249 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5250 {
5251 HeapFree(GetProcessHeap(), 0, InfInstallSection);
5252 InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5253 if (!InfInstallSection)
5254 goto cleanup;
5255 Result = SetupGetStringFieldW(
5256 &ContextDevice,
5257 1, /* Field index */
5258 InfInstallSection, RequiredSize,
5259 &RequiredSize);
5260 }
5261 if (!Result)
5262 goto cleanup;
5263
5264 TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n",
5265 debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile),
5266 debugstr_w(InfInstallSection), Rank);
5267
5268 driverInfo->DriverRank = Rank;
5269 memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME));
5270 memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
5271 driverInfo->Info.DriverType = DriverType;
5272 driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
5273 strncpyW(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
5274 driverInfo->Info.Description[LINE_LEN - 1] = '\0';
5275 strncpyW(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
5276 driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
5277 if (ProviderName)
5278 {
5279 strncpyW(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
5280 driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
5281 }
5282 else
5283 driverInfo->Info.ProviderName[0] = '\0';
5284 driverInfo->Info.DriverDate = DriverDate;
5285 driverInfo->Info.DriverVersion = DriverVersion;
5286 ReferenceInfFile(InfFileDetails);
5287 driverInfo->InfFileDetails = InfFileDetails;
5288
5289 /* Insert current driver in driver list, according to its rank */
5290 PreviousEntry = DriverListHead->Flink;
5291 while (PreviousEntry != DriverListHead)
5292 {
5293 struct DriverInfoElement *CurrentDriver;
5294 CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry);
5295 if (CurrentDriver->DriverRank > Rank ||
5296 (CurrentDriver->DriverRank == Rank && CurrentDriver->DriverDate.QuadPart > driverInfo->DriverDate.QuadPart))
5297 {
5298 /* Insert before the current item */
5299 InsertHeadList(PreviousEntry, &driverInfo->ListEntry);
5300 break;
5301 }
5302 PreviousEntry = PreviousEntry->Flink;
5303 }
5304 if (PreviousEntry == DriverListHead)
5305 {
5306 /* Insert at the end of the list */
5307 InsertTailList(DriverListHead, &driverInfo->ListEntry);
5308 }
5309
5310 ret = TRUE;
5311
5312 cleanup:
5313 if (!ret)
5314 {
5315 if (driverInfo)
5316 HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
5317 HeapFree(GetProcessHeap(), 0, driverInfo);
5318 }
5319 if (hFile != INVALID_HANDLE_VALUE)
5320 CloseHandle(hFile);
5321 HeapFree(GetProcessHeap(), 0, InfInstallSection);
5322
5323 return ret;
5324 }
5325
5326 static BOOL
5327 GetVersionInformationFromInfFile(
5328 IN HINF hInf,
5329 OUT LPGUID ClassGuid,
5330 OUT LPWSTR* pProviderName,
5331 OUT FILETIME* DriverDate,
5332 OUT DWORDLONG* DriverVersion)
5333 {
5334 DWORD RequiredSize;
5335 WCHAR guidW[MAX_GUID_STRING_LEN + 1];
5336 LPWSTR DriverVer = NULL;
5337 LPWSTR ProviderName = NULL;
5338 LPWSTR pComma; /* Points into DriverVer */
5339 LPWSTR pVersion = NULL; /* Points into DriverVer */
5340 SYSTEMTIME SystemTime;
5341 BOOL Result;
5342 BOOL ret = FALSE; /* Final result */
5343
5344 /* Get class Guid */
5345 if (!SetupGetLineTextW(
5346 NULL, /* Context */
5347 hInf,
5348 Version, ClassGUID,
5349 guidW, sizeof(guidW),
5350 NULL /* Required size */))
5351 {
5352 goto cleanup;
5353 }
5354 guidW[37] = '\0'; /* Replace the } by a NULL character */
5355 if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
5356 {
5357 SetLastError(ERROR_GEN_FAILURE);
5358 goto cleanup;
5359 }
5360
5361 /* Get provider name */
5362 Result = SetupGetLineTextW(
5363 NULL, /* Context */
5364 hInf, Version, INF_PROVIDER,
5365 NULL, 0,
5366 &RequiredSize);
5367 if (Result)
5368 {
5369 /* We know know the needed buffer size */
5370 ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5371 if (!ProviderName)
5372 {
5373 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5374 goto cleanup;
5375 }
5376 Result = SetupGetLineTextW(
5377 NULL, /* Context */
5378 hInf, Version, INF_PROVIDER,
5379 ProviderName, RequiredSize,
5380 &RequiredSize);
5381 }
5382 if (!Result)
5383 goto cleanup;
5384 *pProviderName = ProviderName;
5385
5386 /* Read the "DriverVer" value */
5387 Result = SetupGetLineTextW(
5388 NULL, /* Context */
5389 hInf, Version, INF_DRIVER_VER,
5390 NULL, 0,
5391 &RequiredSize);
5392 if (Result)
5393 {
5394 /* We know know the needed buffer size */
5395 DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5396 if (!DriverVer)
5397 {
5398 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5399 goto cleanup;
5400 }
5401 Result = SetupGetLineTextW(
5402 NULL, /* Context */
5403 hInf, Version, INF_DRIVER_VER,
5404 DriverVer, RequiredSize,
5405 &RequiredSize);
5406 }
5407 if (!Result)
5408 goto cleanup;
5409
5410 /* Get driver date and driver version, by analyzing the "DriverVer" value */
5411 pComma = strchrW(DriverVer, ',');
5412 if (pComma != NULL)
5413 {
5414 *pComma = UNICODE_NULL;
5415 pVersion = pComma + 1;
5416 }
5417 /* Get driver date version. Invalid date = 00/00/00 */
5418 memset(DriverDate, 0, sizeof(FILETIME));
5419 if (strlenW(DriverVer) == 10
5420 && (DriverVer[2] == '-' || DriverVer[2] == '/')
5421 && (DriverVer[5] == '-' || DriverVer[5] == '/'))
5422 {
5423 memset(&SystemTime, 0, sizeof(SYSTEMTIME));
5424 DriverVer[2] = DriverVer[5] = UNICODE_NULL;
5425 SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
5426 SystemTime.wDay = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
5427 SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
5428 SystemTimeToFileTime(&SystemTime, DriverDate);
5429 }
5430 /* Get driver version. Invalid version = 0.0.0.0 */
5431 *DriverVersion = 0;
5432 if (pVersion)
5433 {
5434 WORD Major, Minor = 0, Revision = 0, Build = 0;
5435 LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL;
5436 LARGE_INTEGER fullVersion;
5437
5438 pMinor = strchrW(pVersion, '.');
5439 if (pMinor)
5440 {
5441 *pMinor = 0;
5442 pRevision = strchrW(++pMinor, '.');
5443 Minor = atoiW(pMinor);
5444 }
5445 if (pRevision)
5446 {
5447 *pRevision = 0;
5448 pBuild = strchrW(++pRevision, '.');
5449 Revision = atoiW(pRevision);
5450 }
5451 if (pBuild)
5452 {
5453 *pBuild = 0;
5454 pBuild++;
5455 Build = atoiW(pBuild);
5456 }
5457 Major = atoiW(pVersion);
5458 fullVersion.u.HighPart = Major << 16 | Minor;
5459 fullVersion.u.LowPart = Revision << 16 | Build;
5460 memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER));
5461 }
5462
5463 ret = TRUE;
5464
5465 cleanup:
5466 if (!ret)
5467 HeapFree(GetProcessHeap(), 0, ProviderName);
5468 HeapFree(GetProcessHeap(), 0, DriverVer);
5469
5470 return ret;
5471 }
5472
5473 static BOOL
5474 GetHardwareAndCompatibleIDsLists(
5475 IN HDEVINFO DeviceInfoSet,
5476 IN OUT PSP_DEVINFO_DATA DeviceInfoData,
5477 OUT LPWSTR *pHardwareIDs OPTIONAL,
5478 OUT LPDWORD pHardwareIDsRequiredSize OPTIONAL,
5479 OUT LPWSTR *pCompatibleIDs OPTIONAL,
5480 OUT LPDWORD pCompatibleIDsRequiredSize OPTIONAL)
5481 {
5482 LPWSTR HardwareIDs = NULL;
5483 LPWSTR CompatibleIDs = NULL;
5484 DWORD RequiredSize;
5485 BOOL Result;
5486
5487 /* Get hardware IDs list */
5488 Result = FALSE;
5489 RequiredSize = 512; /* Initial buffer size */
5490 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5491 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5492 {
5493 MyFree(HardwareIDs);
5494 HardwareIDs = MyMalloc(RequiredSize);
5495 if (!HardwareIDs)
5496 {
5497 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5498 goto done;
5499 }
5500 Result = SetupDiGetDeviceRegistryPropertyW(
5501 DeviceInfoSet,
5502 DeviceInfoData,
5503 SPDRP_HARDWAREID,
5504 NULL,
5505 (PBYTE)HardwareIDs,
5506 RequiredSize,
5507 &RequiredSize);
5508 }
5509 if (!Result)
5510 {
5511 if (GetLastError() == ERROR_FILE_NOT_FOUND)
5512 {
5513 /* No hardware ID for this device */
5514 MyFree(HardwareIDs);
5515 HardwareIDs = NULL;
5516 RequiredSize = 0;
5517 }
5518 else
5519 goto done;
5520 }
5521 if (pHardwareIDs)
5522 *pHardwareIDs = HardwareIDs;
5523 if (pHardwareIDsRequiredSize)
5524 *pHardwareIDsRequiredSize = RequiredSize;
5525
5526 /* Get compatible IDs list */
5527 Result = FALSE;
5528 RequiredSize = 512; /* Initial buffer size */
5529 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5530 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5531 {
5532 MyFree(CompatibleIDs);
5533 CompatibleIDs = MyMalloc(RequiredSize);
5534 if (!CompatibleIDs)
5535 {
5536 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5537 goto done;
5538 }
5539 Result = SetupDiGetDeviceRegistryPropertyW(
5540 DeviceInfoSet,
5541 DeviceInfoData,
5542 SPDRP_COMPATIBLEIDS,
5543 NULL,
5544 (PBYTE)CompatibleIDs,
5545 RequiredSize,
5546 &RequiredSize);
5547 }
5548 if (!Result)
5549 {
5550 if (GetLastError() == ERROR_FILE_NOT_FOUND)
5551 {
5552 /* No compatible ID for this device */
5553 MyFree(CompatibleIDs);
5554 CompatibleIDs = NULL;
5555 RequiredSize = 0;
5556 }
5557 else
5558 goto done;
5559 }
5560 if (pCompatibleIDs)
5561 *pCompatibleIDs = CompatibleIDs;
5562 if (pCompatibleIDsRequiredSize)
5563 *pCompatibleIDsRequiredSize = RequiredSize;
5564
5565 Result = TRUE;
5566
5567 done:
5568 if (!Result)
5569 {
5570 MyFree(HardwareIDs);
5571 MyFree(CompatibleIDs);
5572 }
5573 return Result;
5574 }
5575
5576 /***********************************************************************
5577 * SetupDiBuildDriverInfoList (SETUPAPI.@)
5578 */
5579 BOOL WINAPI
5580 SetupDiBuildDriverInfoList(
5581 IN HDEVINFO DeviceInfoSet,
5582 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
5583 IN DWORD DriverType)
5584 {
5585 struct DeviceInfoSet *list;
5586 SP_DEVINSTALL_PARAMS_W InstallParams;
5587 PVOID Buffer = NULL;
5588 struct InfFileDetails *currentInfFileDetails = NULL;
5589 LPWSTR ProviderName = NULL;
5590 LPWSTR ManufacturerName = NULL;
5591 WCHAR ManufacturerSection[LINE_LEN + 1];
5592 LPWSTR HardwareIDs = NULL;
5593 LPWSTR CompatibleIDs = NULL;
5594 LPWSTR FullInfFileName = NULL;
5595 LPWSTR ExcludeFromSelect = NULL;
5596 FILETIME DriverDate;
5597 DWORDLONG DriverVersion = 0;
5598 DWORD RequiredSize;
5599 BOOL ret = FALSE;
5600
5601 TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
5602
5603 if (!DeviceInfoSet)
5604 SetLastError(ERROR_INVALID_HANDLE);
5605 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
5606 SetLastError(ERROR_INVALID_HANDLE);
5607 else if (list->HKLM != HKEY_LOCAL_MACHINE)
5608 SetLastError(ERROR_INVALID_HANDLE);
5609 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
5610 SetLastError(ERROR_INVALID_PARAMETER);
5611 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
5612 SetLastError(ERROR_INVALID_PARAMETER);
5613 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
5614 SetLastError(ERROR_INVALID_USER_BUFFER);
5615 else
5616 {
5617 PLIST_ENTRY pDriverListHead = &list->DriverListHead;
5618 BOOL Result;
5619
5620 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
5621 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5622 if (!Result)
5623 goto done;
5624
5625 if (DeviceInfoData)
5626 {
5627 struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
5628 if (!(devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
5629 pDriverListHead = &devInfo->DriverListHead;
5630 }
5631
5632 if (DriverType == SPDIT_COMPATDRIVER)
5633 {
5634 /* Get hardware and compatible IDs lists */
5635 Result = GetHardwareAndCompatibleIDsLists(
5636 DeviceInfoSet,
5637 DeviceInfoData,
5638 &HardwareIDs,
5639 NULL,
5640 &CompatibleIDs,
5641 NULL);
5642 if (!Result)
5643 goto done;
5644 if (!HardwareIDs && !CompatibleIDs)
5645 {
5646 SetLastError(ERROR_FILE_NOT_FOUND);
5647 goto done;
5648 }
5649 }
5650
5651 if (InstallParams.Flags & DI_ENUMSINGLEINF)
5652 {
5653 /* InstallParams.DriverPath contains the name of a .inf file */
5654 RequiredSize = strlenW(InstallParams.DriverPath) + 2;
5655 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5656 if (!Buffer)
5657 {
5658 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5659 goto done;
5660 }
5661 strcpyW(Buffer, InstallParams.DriverPath);
5662 ((LPWSTR)Buffer)[RequiredSize - 1] = 0;
5663 Result = TRUE;
5664 }
5665 else
5666 {
5667 /* Enumerate .inf files */
5668 Result = FALSE;
5669 RequiredSize = 32768; /* Initial buffer size */
5670 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5671 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5672 {
5673 HeapFree(GetProcessHeap(), 0, Buffer);
5674 Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5675 if (!Buffer)
5676 {
5677 Result = FALSE;
5678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5679 break;
5680 }
5681 Result = SetupGetInfFileListW(
5682 *InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
5683 INF_STYLE_WIN4,
5684 Buffer, RequiredSize,
5685 &RequiredSize);
5686 }
5687 if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
5688 {
5689 /* No .inf file in specified directory. So, we should
5690 * success as we created an empty driver info list.
5691 */
5692 ret = TRUE;
5693 goto done;
5694 }
5695 }
5696 if (Result)
5697 {
5698 LPCWSTR filename;
5699 LPWSTR pFullFilename;
5700
5701 if (InstallParams.Flags & DI_ENUMSINGLEINF)
5702 {
5703 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
5704 if (!FullInfFileName)
5705 goto done;
5706 pFullFilename = &FullInfFileName[0];
5707 }
5708 else if (*InstallParams.DriverPath)
5709 {
5710 DWORD len;
5711 len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL);
5712 if (len == 0)
5713 goto done;
5714 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, len + MAX_PATH);
5715 if (!FullInfFileName)
5716 goto done;
5717 len = GetFullPathNameW(InstallParams.DriverPath, len, FullInfFileName, NULL);
5718 if (len == 0)
5719 goto done;
5720 if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
5721 strcatW(FullInfFileName, L"\\");
5722 pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
5723 }
5724 else
5725 {
5726 FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
5727 if (!FullInfFileName)
5728 goto done;
5729 pFullFilename = &FullInfFileName[0];
5730 }
5731
5732 for (filename = (LPCWSTR)Buffer; *filename; filename += strlenW(filename) + 1)
5733 {
5734 INFCONTEXT ContextManufacturer, ContextDevice;
5735 GUID ClassGuid;
5736
5737 strcpyW(pFullFilename, filename);
5738 TRACE("Opening file %s\n", debugstr_w(FullInfFileName));
5739
5740 currentInfFileDetails = HeapAlloc(
5741 GetProcessHeap(),
5742 0,
5743 FIELD_OFFSET(struct InfFileDetails, FullInfFileName) + strlenW(FullInfFileName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
5744 if (!currentInfFileDetails)
5745 continue;
5746 memset(currentInfFileDetails, 0, sizeof(struct InfFileDetails));
5747 strcpyW(currentInfFileDetails->FullInfFileName, FullInfFileName);
5748
5749 currentInfFileDetails->hInf = SetupOpenInfFileW(FullInfFileName, NULL, INF_STYLE_WIN4, NULL);
5750 ReferenceInfFile(currentInfFileDetails);
5751 if (currentInfFileDetails->hInf == INVALID_HANDLE_VALUE)
5752 {
5753 HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
5754 currentInfFileDetails = NULL;
5755 continue;
5756 }
5757
5758 if (!GetVersionInformationFromInfFile(
5759 currentInfFileDetails->hInf,
5760 &ClassGuid,
5761 &ProviderName,
5762 &DriverDate,
5763 &DriverVersion))
5764 {
5765 SetupCloseInfFile(currentInfFileDetails->hInf);
5766 HeapFree(GetProcessHeap(), 0, currentInfFileDetails->hInf);
5767 currentInfFileDetails = NULL;
5768 continue;
5769 }
5770
5771 if (DriverType == SPDIT_CLASSDRIVER)
5772 {
5773 /* Check if the ClassGuid in this .inf file is corresponding with our needs */
5774 if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
5775 {
5776 goto next;
5777 }
5778 }
5779
5780 if (InstallParams.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS)
5781 {
5782 /* Read ExcludeFromSelect control flags */
5783 /* FIXME */
5784 }
5785 else
5786 FIXME("ExcludeFromSelect list ignored\n");
5787
5788 /* Get the manufacturers list */
5789 Result = SetupFindFirstLineW(currentInfFileDetails->hInf, INF_MANUFACTURER, NULL, &ContextManufacturer);
5790 while (Result)
5791 {
5792 Result = SetupGetStringFieldW(
5793 &ContextManufacturer,
5794 0, /* Field index */
5795 NULL, 0,
5796 &RequiredSize);
5797 if (Result)
5798 {
5799 /* We got the needed size for the buffer */
5800 ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5801 if (!ManufacturerName)
5802 {
5803 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5804 goto done;
5805 }
5806 Result = SetupGetStringFieldW(
5807 &ContextManufacturer,
5808 0, /* Field index */
5809 ManufacturerName, RequiredSize,
5810 &RequiredSize);
5811 }
5812 /* Get manufacturer section name */
5813 Result = SetupGetStringFieldW(
5814 &ContextManufacturer,
5815 1, /* Field index */
5816 ManufacturerSection, LINE_LEN,
5817 &RequiredSize);
5818 if (Result)
5819 {
5820 ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
5821 /* Add (possible) extension to manufacturer section name */
5822 Result = SetupDiGetActualSectionToInstallW(
5823 currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
5824 if (Result)
5825 {
5826 TRACE("Enumerating devices in manufacturer %s\n", debugstr_w(ManufacturerSection));
5827 Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
5828 }
5829 }
5830 while (Result)
5831 {
5832 if (DriverType == SPDIT_CLASSDRIVER)
5833 {
5834 /* FIXME: Check ExcludeFromSelect list */
5835 if (!AddDriverToList(
5836 pDriverListHead,
5837 DriverType,
5838 &ClassGuid,
5839 ContextDevice,
5840 currentInfFileDetails,
5841 filename,
5842 ProviderName,
5843 ManufacturerName,
5844 NULL,
5845 DriverDate, DriverVersion,
5846 0))
5847 {
5848 break;
5849 }
5850 }
5851 else /* DriverType = SPDIT_COMPATDRIVER */
5852 {
5853 /* 1. Get all fields */
5854 DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
5855 DWORD DriverRank;
5856 DWORD i;
5857 LPCWSTR currentId;
5858 BOOL DriverAlreadyAdded;
5859
5860 for (i = 2; i <= FieldCount; i++)
5861 {
5862 LPWSTR DeviceId = NULL;
5863 Result = FALSE;
5864 RequiredSize = 128; /* Initial buffer size */
5865 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5866 while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5867 {
5868 HeapFree(GetProcessHeap(), 0, DeviceId);
5869 DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
5870 if (!DeviceId)
5871 {
5872 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5873 goto done;
5874 }
5875 Result = SetupGetStringFieldW(
5876 &ContextDevice,
5877 i,
5878 DeviceId, RequiredSize,
5879 &RequiredSize);
5880 }
5881 if (!Result)
5882 {
5883 HeapFree(GetProcessHeap(), 0, DeviceId);
5884 goto done;
5885 }
5886 /* FIXME: Check ExcludeFromSelect list */
5887 DriverAlreadyAdded = FALSE;
5888 for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
5889 {
5890 if (wcsicmp(DeviceId, currentId) == 0)
5891 {
5892 AddDriverToList(
5893 pDriverListHead,
5894 DriverType,
5895 &ClassGuid,
5896 ContextDevice,
5897 currentInfFileDetails,
5898 filename,
5899 ProviderName,
5900 ManufacturerName,
5901 currentId,
5902 DriverDate, DriverVersion,
5903 DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
5904 DriverAlreadyAdded = TRUE;
5905 }
5906 }
5907 if (CompatibleIDs)
5908 {
5909 for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
5910 {
5911 if (wcsicmp(DeviceId, currentId) == 0)
5912 {
5913 AddDriverToList(
5914 pDriverListHead,
5915 DriverType,
5916 &ClassGuid,
5917 ContextDevice,
5918 currentInfFileDetails,
5919 filename,
5920 ProviderName,
5921 ManufacturerName,
5922 currentId,
5923 DriverDate, DriverVersion,
5924 DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
5925 DriverAlreadyAdded = TRUE;
5926 }
5927 }
5928 }
5929 HeapFree(GetProcessHeap(), 0, DeviceId);
5930 }
5931 }
5932 Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
5933 }
5934
5935 HeapFree(GetProcessHeap(), 0, ManufacturerName);
5936 ManufacturerName = NULL;
5937 Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
5938 }
5939
5940 ret = TRUE;
5941 next:
5942 HeapFree(GetProcessHeap(), 0, ProviderName);
5943 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
5944 ProviderName = ExcludeFromSelect = NULL;
5945
5946 DereferenceInfFile(currentInfFileDetails);
5947 currentInfFileDetails = NULL;
5948 }
5949 ret = TRUE;
5950 }
5951 }
5952
5953 done:
5954 if (ret)
5955 {
5956 if (DeviceInfoData)
5957 {
5958 InstallParams.Flags |= DI_DIDCOMPAT;
5959 InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
5960 }
5961 else
5962 {
5963 InstallParams.Flags |= DI_DIDCLASS;
5964 InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
5965 }
5966 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
5967 }
5968
5969 HeapFree(GetProcessHeap(), 0, ProviderName);
5970 HeapFree(GetProcessHeap(), 0, ManufacturerName);
5971 MyFree(HardwareIDs);
5972 MyFree(CompatibleIDs);
5973 HeapFree(GetProcessHeap(), 0, FullInfFileName);
5974 HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
5975 if (currentInfFileDetails)
5976 DereferenceInfFile(currentInfFileDetails);
5977 HeapFree(GetProcessHeap(), 0, Buffer);
5978
5979 TRACE("Returning %d\n", ret);
5980 return ret;
5981 }
5982
5983 /***********************************************************************
5984 * SetupDiDeleteDeviceInfo (SETUPAPI.@)
5985 */
5986 BOOL WINAPI
5987 SetupDiDeleteDeviceInfo(
5988 IN HDEVINFO DeviceInfoSet,
5989 IN PSP_DEVINFO_DATA DeviceInfoData)
5990 {
5991 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
5992
5993 FIXME("not implemented\n");
5994 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5995 return FALSE;
5996 }
5997
5998
5999 /***********************************************************************
6000 * SetupDiDestroyDriverInfoList (SETUPAPI.@)
6001 */
6002 BOOL WINAPI
6003 SetupDiDestroyDriverInfoList(
6004 IN HDEVINFO DeviceInfoSet,
6005 IN PSP_DEVINFO_DATA DeviceInfoData,
6006 IN DWORD DriverType)
6007 {
6008 struct DeviceInfoSet *list;
6009 BOOL ret = FALSE;
6010
6011 TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
6012
6013 if (!DeviceInfoSet)
6014 SetLastError(ERROR_INVALID_HANDLE);
6015 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6016 SetLastError(ERROR_INVALID_HANDLE);
6017 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
6018 SetLastError(ERROR_INVALID_PARAMETER);
6019 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
6020 SetLastError(ERROR_INVALID_PARAMETER);
6021 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6022 SetLastError(ERROR_INVALID_USER_BUFFER);
6023 else
6024 {
6025 PLIST_ENTRY ListEntry;
6026 struct DriverInfoElement *driverInfo;
6027 SP_DEVINSTALL_PARAMS_W InstallParams;
6028
6029 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
6030 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
6031 goto done;
6032
6033 if (!DeviceInfoData)
6034 /* Fall back to destroying class driver list */
6035 DriverType = SPDIT_CLASSDRIVER;
6036
6037 if (DriverType == SPDIT_CLASSDRIVER)
6038 {
6039 while (!IsListEmpty(&list->DriverListHead))
6040 {
6041 ListEntry = RemoveHeadList(&list->DriverListHead);
6042 driverInfo = (struct DriverInfoElement *)ListEntry;
6043 DestroyDriverInfoElement(driverInfo);
6044 }
6045 InstallParams.Reserved = 0;
6046 InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
6047 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
6048 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
6049 }
6050 else
6051 {
6052 SP_DEVINSTALL_PARAMS_W InstallParamsSet;
6053 struct DeviceInfoElement *deviceInfo;
6054
6055 InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
6056 if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
6057 goto done;
6058 deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
6059 while (!IsListEmpty(&deviceInfo->DriverListHead))
6060 {
6061 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
6062 driverInfo = (struct DriverInfoElement *)ListEntry;
6063 if ((PVOID)InstallParamsSet.Reserved == driverInfo)
6064 {
6065 InstallParamsSet.Reserved = 0;
6066 SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
6067 }
6068 DestroyDriverInfoElement(driverInfo);
6069 }
6070 InstallParams.Reserved = 0;
6071 InstallParams.Flags &= ~DI_DIDCOMPAT;
6072 InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
6073 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
6074 }
6075 }
6076
6077 done:
6078 TRACE("Returning %d\n", ret);
6079 return ret;
6080 }
6081
6082
6083 /***********************************************************************
6084 * SetupDiOpenDeviceInfoA (SETUPAPI.@)
6085 */
6086 BOOL WINAPI
6087 SetupDiOpenDeviceInfoA(
6088 IN HDEVINFO DeviceInfoSet,
6089 IN PCSTR DeviceInstanceId,
6090 IN HWND hwndParent OPTIONAL,
6091 IN DWORD OpenFlags,
6092 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
6093 {
6094 LPWSTR DeviceInstanceIdW = NULL;
6095 BOOL bResult;
6096
6097 TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
6098
6099 DeviceInstanceIdW = MultiByteToUnicode(DeviceInstanceId, CP_ACP);
6100 if (DeviceInstanceIdW == NULL)
6101 return FALSE;
6102
6103 bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
6104 DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
6105
6106 MyFree(DeviceInstanceIdW);
6107
6108 return bResult;
6109 }
6110
6111
6112 /***********************************************************************
6113 * SetupDiOpenDeviceInfoW (SETUPAPI.@)
6114 */
6115 BOOL WINAPI
6116 SetupDiOpenDeviceInfoW(
6117 IN HDEVINFO DeviceInfoSet,
6118 IN PCWSTR DeviceInstanceId,
6119 IN HWND hwndParent OPTIONAL,
6120 IN DWORD OpenFlags,
6121 OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
6122 {
6123 struct DeviceInfoSet *list;
6124 HKEY hEnumKey, hKey;
6125 DWORD rc;
6126 BOOL ret = FALSE;
6127
6128 TRACE("%p %s %p %lx %p\n",
6129 DeviceInfoSet, debugstr_w(DeviceInstanceId),
6130 hwndParent, OpenFlags, DeviceInfoData);
6131
6132 if (OpenFlags & DIOD_CANCEL_REMOVE)
6133 FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
6134
6135 if (!DeviceInfoSet)
6136 SetLastError(ERROR_INVALID_HANDLE);
6137 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6138 SetLastError(ERROR_INVALID_HANDLE);
6139 else if (!DeviceInstanceId)
6140 SetLastError(ERROR_INVALID_PARAMETER);
6141 else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
6142 {
6143 TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
6144 SetLastError(ERROR_INVALID_FLAGS);
6145 }
6146 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6147 SetLastError(ERROR_INVALID_USER_BUFFER);
6148 else
6149 {
6150 struct DeviceInfoElement *deviceInfo = NULL;
6151 /* Search if device already exists in DeviceInfoSet.
6152 * If yes, return the existing element
6153 * If no, create a new element using informations in registry
6154 */
6155 PLIST_ENTRY ItemList = list->ListHead.Flink;
6156 while (ItemList != &list->ListHead)
6157 {
6158 // TODO
6159 //if (good one)
6160 // break;
6161 FIXME("not implemented\n");
6162 ItemList = ItemList->Flink;
6163 }
6164
6165 if (deviceInfo)
6166 {
6167 /* good one found */
6168 ret = TRUE;
6169 }
6170 else
6171 {
6172 /* Open supposed registry key */
6173 rc = RegOpenKeyExW(
6174 list->HKLM,
6175 REGSTR_PATH_SYSTEMENUM,
6176 0, /* Options */
6177 0,
6178 &hEnumKey);
6179 if (rc != ERROR_SUCCESS)
6180 {
6181 SetLastError(rc);
6182 return FALSE;
6183 }
6184 rc = RegOpenKeyExW(
6185 hEnumKey,
6186 DeviceInstanceId,
6187 0, /* Options */
6188 KEY_QUERY_VALUE,
6189 &hKey);
6190 RegCloseKey(hEnumKey);
6191 if (rc != ERROR_SUCCESS)
6192 {
6193 if (rc == ERROR_FILE_NOT_FOUND)
6194 rc = ERROR_NO_SUCH_DEVINST;
6195 SetLastError(rc);
6196 return FALSE;
6197 }
6198
6199 /* FIXME: try to get ClassGUID from registry, instead of
6200 * sending GUID_NULL to CreateDeviceInfoElement
6201 */
6202 if (!CreateDeviceInfoElement(list, DeviceInstanceId, &GUID_NULL, &deviceInfo))
6203 {
6204 RegCloseKey(hKey);
6205 return FALSE;
6206 }
6207 InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
6208
6209 RegCloseKey(hKey);
6210 ret = TRUE;
6211 }
6212
6213 if (ret && deviceInfo && DeviceInfoData)
6214 {
6215 memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
6216 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
6217 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
6218 }
6219 }
6220
6221 return ret;
6222 }
6223
6224
6225 /***********************************************************************
6226 * SetupDiEnumDriverInfoA (SETUPAPI.@)
6227 */
6228 BOOL WINAPI
6229 SetupDiEnumDriverInfoA(
6230 IN HDEVINFO DeviceInfoSet,
6231 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6232 IN DWORD DriverType,
6233 IN DWORD MemberIndex,
6234 OUT PSP_DRVINFO_DATA_A DriverInfoData)
6235 {
6236 SP_DRVINFO_DATA_V2_W driverInfoData2W;
6237 BOOL ret = FALSE;
6238
6239 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
6240 DriverType, MemberIndex, DriverInfoData);
6241
6242 if (DriverInfoData == NULL)
6243 SetLastError(ERROR_INVALID_PARAMETER);
6244 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
6245 SetLastError(ERROR_INVALID_USER_BUFFER);
6246 else
6247 {
6248 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
6249 ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
6250 DriverType, MemberIndex, &driverInfoData2W);
6251
6252 if (ret)
6253 {
6254 /* Do W->A conversion */
6255 DriverInfoData->DriverType = driverInfoData2W.DriverType;
6256 DriverInfoData->Reserved = driverInfoData2W.Reserved;
6257 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
6258 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
6259 {
6260 DriverInfoData->Description[0] = '\0';
6261 ret = FALSE;
6262 }
6263 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
6264 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
6265 {
6266 DriverInfoData->MfgName[0] = '\0';
6267 ret = FALSE;
6268 }
6269 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
6270 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
6271 {
6272 DriverInfoData->ProviderName[0] = '\0';
6273 ret = FALSE;
6274 }
6275 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
6276 {
6277 /* Copy more fields */
6278 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
6279 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
6280 }
6281 }
6282 }
6283
6284 TRACE("Returning %d\n", ret);
6285 return ret;
6286 }
6287
6288
6289 /***********************************************************************
6290 * SetupDiEnumDriverInfoW (SETUPAPI.@)
6291 */
6292 BOOL WINAPI
6293 SetupDiEnumDriverInfoW(
6294 IN HDEVINFO DeviceInfoSet,
6295 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6296 IN DWORD DriverType,
6297 IN DWORD MemberIndex,
6298 OUT PSP_DRVINFO_DATA_W DriverInfoData)
6299 {
6300 PLIST_ENTRY ListHead;
6301 BOOL ret = FALSE;
6302
6303 TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
6304 DriverType, MemberIndex, DriverInfoData);
6305
6306 if (!DeviceInfoSet || !DriverInfoData)
6307 SetLastError(ERROR_INVALID_PARAMETER);
6308 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
6309 SetLastError(ERROR_INVALID_HANDLE);
6310 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6311 SetLastError(ERROR_INVALID_HANDLE);
6312 else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
6313 SetLastError(ERROR_INVALID_PARAMETER);
6314 else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
6315 SetLastError(ERROR_INVALID_PARAMETER);
6316 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
6317 SetLastError(ERROR_INVALID_USER_BUFFER);
6318 else
6319 {
6320 struct DeviceInfoElement *devInfo = NULL;
6321 PLIST_ENTRY ItemList;
6322 if (DeviceInfoData)
6323 devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
6324 if (!devInfo || (devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
6325 {
6326 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
6327 }
6328 else
6329 {
6330 ListHead = &devInfo->DriverListHead;
6331 }
6332
6333 ItemList = ListHead->Flink;
6334 while (ItemList != ListHead && MemberIndex-- > 0)
6335 ItemList = ItemList->Flink;
6336 if (ItemList == ListHead)
6337 SetLastError(ERROR_NO_MORE_ITEMS);
6338 else
6339 {
6340 struct DriverInfoElement *DrvInfo = (struct DriverInfoElement *)ItemList;
6341
6342 memcpy(
6343 &DriverInfoData->DriverType,
6344 &DrvInfo->Info.DriverType,
6345 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
6346 ret = TRUE;
6347 }
6348 }
6349
6350 TRACE("Returning %d\n", ret);
6351 return ret;
6352 }
6353
6354
6355 /***********************************************************************
6356 * SetupDiGetSelectedDevice (SETUPAPI.@)
6357 */
6358 BOOL WINAPI
6359 SetupDiGetSelectedDevice(
6360 IN HDEVINFO DeviceInfoSet,
6361 OUT PSP_DEVINFO_DATA DeviceInfoData)
6362 {
6363 struct DeviceInfoSet *list;
6364 BOOL ret = FALSE;
6365
6366 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
6367
6368 if (!DeviceInfoSet)
6369 SetLastError(ERROR_INVALID_HANDLE);
6370 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6371 SetLastError(ERROR_INVALID_HANDLE);
6372 else if (list->SelectedDevice == NULL)
6373 SetLastError(ERROR_NO_DEVICE_SELECTED);
6374 else if (!DeviceInfoData)
6375 SetLastError(ERROR_INVALID_PARAMETER);
6376 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6377 SetLastError(ERROR_INVALID_USER_BUFFER);
6378 else
6379 {
6380 memcpy(&DeviceInfoData->ClassGuid,
6381 &list->SelectedDevice->ClassGuid,
6382 sizeof(GUID));
6383 DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
6384 DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
6385 ret = TRUE;
6386 }
6387
6388 TRACE("Returning %d\n", ret);
6389 return ret;
6390 }
6391
6392
6393 /***********************************************************************
6394 * SetupDiGetSelectedDriverA (SETUPAPI.@)
6395 */
6396 BOOL WINAPI
6397 SetupDiGetSelectedDriverA(
6398 IN HDEVINFO DeviceInfoSet,
6399 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6400 OUT PSP_DRVINFO_DATA_A DriverInfoData)
6401 {
6402 SP_DRVINFO_DATA_V2_W driverInfoData2W;
6403 BOOL ret = FALSE;
6404
6405 if (DriverInfoData == NULL)
6406 SetLastError(ERROR_INVALID_PARAMETER);
6407 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
6408 SetLastError(ERROR_INVALID_USER_BUFFER);
6409 else
6410 {
6411 driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
6412
6413 ret = SetupDiGetSelectedDriverW(DeviceInfoSet,
6414 DeviceInfoData,
6415 &driverInfoData2W);
6416
6417 if (ret)
6418 {
6419 /* Do W->A conversion */
6420 DriverInfoData->DriverType = driverInfoData2W.DriverType;
6421 DriverInfoData->Reserved = driverInfoData2W.Reserved;
6422 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
6423 DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
6424 {
6425 DriverInfoData->Description[0] = '\0';
6426 ret = FALSE;
6427 }
6428 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
6429 DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
6430 {
6431 DriverInfoData->MfgName[0] = '\0';
6432 ret = FALSE;
6433 }
6434 if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
6435 DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
6436 {
6437 DriverInfoData->ProviderName[0] = '\0';
6438 ret = FALSE;
6439 }
6440 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
6441 {
6442 /* Copy more fields */
6443 DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
6444 DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
6445 }
6446 }
6447 }
6448
6449 return ret;
6450 }
6451
6452
6453 /***********************************************************************
6454 * SetupDiGetSelectedDriverW (SETUPAPI.@)
6455 */
6456 BOOL WINAPI
6457 SetupDiGetSelectedDriverW(
6458 IN HDEVINFO DeviceInfoSet,
6459 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6460 OUT PSP_DRVINFO_DATA_W DriverInfoData)
6461 {
6462 BOOL ret = FALSE;
6463
6464 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
6465
6466 if (!DeviceInfoSet || !DriverInfoData)
6467 SetLastError(ERROR_INVALID_PARAMETER);
6468 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
6469 SetLastError(ERROR_INVALID_HANDLE);
6470 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6471 SetLastError(ERROR_INVALID_HANDLE);
6472 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6473 SetLastError(ERROR_INVALID_USER_BUFFER);
6474 else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
6475 SetLastError(ERROR_INVALID_USER_BUFFER);
6476 else
6477 {
6478 SP_DEVINSTALL_PARAMS InstallParams;
6479
6480 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
6481 if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
6482 {
6483 struct DriverInfoElement *driverInfo;
6484 driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
6485 if (driverInfo == NULL)
6486 SetLastError(ERROR_NO_DRIVER_SELECTED);
6487 else
6488 {
6489 memcpy(
6490 &DriverInfoData->DriverType,
6491 &driverInfo->Info.DriverType,
6492 DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
6493 ret = TRUE;
6494 }
6495 }
6496 }
6497
6498 TRACE("Returning %d\n", ret);
6499 return ret;
6500 }
6501
6502
6503 /***********************************************************************
6504 * SetupDiSetSelectedDevice (SETUPAPI.@)
6505 */
6506 BOOL WINAPI
6507 SetupDiSetSelectedDevice(
6508 IN HDEVINFO DeviceInfoSet,
6509 IN PSP_DEVINFO_DATA DeviceInfoData)
6510 {
6511 struct DeviceInfoSet *list;
6512 BOOL ret = FALSE;
6513
6514 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
6515
6516 if (!DeviceInfoSet)
6517 SetLastError(ERROR_INVALID_HANDLE);
6518 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6519 SetLastError(ERROR_INVALID_HANDLE);
6520 else if (!DeviceInfoData)
6521 SetLastError(ERROR_INVALID_PARAMETER);
6522 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6523 SetLastError(ERROR_INVALID_USER_BUFFER);
6524 else if (DeviceInfoData->Reserved == 0)
6525 SetLastError(ERROR_INVALID_USER_BUFFER);
6526 else
6527 {
6528 list->SelectedDevice = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
6529 ret = TRUE;
6530 }
6531
6532 TRACE("Returning %d\n", ret);
6533 return ret;
6534 }
6535
6536
6537 /***********************************************************************
6538 * SetupDiSetSelectedDriverA (SETUPAPI.@)
6539 */
6540 BOOL WINAPI
6541 SetupDiSetSelectedDriverA(
6542 IN HDEVINFO DeviceInfoSet,
6543 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6544 IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
6545 {
6546 SP_DRVINFO_DATA_V1_W DriverInfoDataW;
6547 PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
6548 BOOL ret = FALSE;
6549
6550 if (DriverInfoData != NULL)
6551 {
6552 if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
6553 DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A));
6554 {
6555 SetLastError(ERROR_INVALID_PARAMETER);
6556 return FALSE;
6557 }
6558
6559 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
6560 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
6561
6562 if (DriverInfoDataW.Reserved == 0)
6563 {
6564 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
6565
6566 /* convert the strings to unicode */
6567 if (!MultiByteToWideChar(CP_ACP,
6568 0,
6569 DriverInfoData->Description,
6570 LINE_LEN,
6571 DriverInfoDataW.Description,
6572 LINE_LEN) ||
6573 !MultiByteToWideChar(CP_ACP,
6574 0,
6575 DriverInfoData->ProviderName,
6576 LINE_LEN,
6577 DriverInfoDataW.ProviderName,
6578 LINE_LEN))
6579 {
6580 return FALSE;
6581 }
6582 }
6583
6584 pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
6585 }
6586
6587 ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
6588 DeviceInfoData,
6589 pDriverInfoDataW);
6590
6591 if (ret && pDriverInfoDataW != NULL)
6592 {
6593 DriverInfoData->Reserved = DriverInfoDataW.Reserved;
6594 }
6595
6596 return ret;
6597 }
6598
6599
6600 /***********************************************************************
6601 * SetupDiSetSelectedDriverW (SETUPAPI.@)
6602 */
6603 BOOL WINAPI
6604 SetupDiSetSelectedDriverW(
6605 IN HDEVINFO DeviceInfoSet,
6606 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6607 IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
6608 {
6609 BOOL ret = FALSE;
6610
6611 TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
6612
6613 if (!DeviceInfoSet)
6614 SetLastError(ERROR_INVALID_PARAMETER);
6615 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
6616 SetLastError(ERROR_INVALID_HANDLE);
6617 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6618 SetLastError(ERROR_INVALID_HANDLE);
6619 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6620 SetLastError(ERROR_INVALID_USER_BUFFER);
6621 else if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
6622 SetLastError(ERROR_INVALID_USER_BUFFER);
6623 else
6624 {
6625 struct DriverInfoElement **pDriverInfo;
6626 PLIST_ENTRY ListHead, ItemList;
6627
6628 if (DeviceInfoData)
6629 {
6630 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved;
6631 ListHead = &((struct DeviceInfoElement *)DeviceInfoData->Reserved)->DriverListHead;
6632 }
6633 else
6634 {
6635 pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
6636 ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
6637 }
6638
6639 if (!DriverInfoData)
6640 {
6641 *pDriverInfo = NULL;
6642 ret = TRUE;
6643 }
6644 else
6645 {
6646 /* Search selected driver in list */
6647 ItemList = ListHead->Flink;
6648 while (ItemList != ListHead)
6649 {
6650 if (DriverInfoData->Reserved != 0)
6651 {
6652 if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
6653 break;
6654 }
6655 else
6656 {
6657 /* The caller wants to compare only DriverType, Description and ProviderName fields */
6658 struct DriverInfoElement *driverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
6659 if (driverInfo->Info.DriverType == DriverInfoData->DriverType
6660 && strcmpW(driverInfo->Info.Description, DriverInfoData->Description) == 0
6661 && strcmpW(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
6662 {
6663 break;
6664 }
6665 }
6666 ItemList = ItemList->Flink;
6667 }
6668 if (ItemList == ListHead)
6669 SetLastError(ERROR_INVALID_PARAMETER);
6670 else
6671 {
6672 *pDriverInfo = (struct DriverInfoElement *)ItemList;
6673 DriverInfoData->Reserved = (ULONG_PTR)ItemList;
6674 ret = TRUE;
6675 TRACE("Choosing driver whose rank is 0x%lx\n",
6676 ((struct DriverInfoElement *)ItemList)->DriverRank);
6677 if (DeviceInfoData)
6678 memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
6679 }
6680 }
6681 }
6682
6683 TRACE("Returning %d\n", ret);
6684 return ret;
6685 }
6686
6687 /***********************************************************************
6688 * SetupDiGetDriverInfoDetailA (SETUPAPI.@)
6689 */
6690 BOOL WINAPI
6691 SetupDiGetDriverInfoDetailA(
6692 IN HDEVINFO DeviceInfoSet,
6693 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6694 IN PSP_DRVINFO_DATA_A DriverInfoData,
6695 OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
6696 IN DWORD DriverInfoDetailDataSize,
6697 OUT PDWORD RequiredSize OPTIONAL)
6698 {
6699 SP_DRVINFO_DATA_V2_W DriverInfoDataW;
6700 PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
6701 DWORD BufSize = 0;
6702 DWORD HardwareIDLen = 0;
6703 BOOL ret = FALSE;
6704
6705 /* do some sanity checks, the unicode version might do more thorough checks */
6706 if (DriverInfoData == NULL ||
6707 (DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
6708 (DriverInfoDetailData != NULL &&
6709 (DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
6710 DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
6711 {
6712 SetLastError(ERROR_INVALID_PARAMETER);
6713 goto Cleanup;
6714 }
6715
6716 /* make sure we support both versions of the SP_DRVINFO_DATA structure */
6717 if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
6718 {
6719 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
6720 }
6721 else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
6722 {
6723 DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
6724 }
6725 else
6726 {
6727 SetLastError(ERROR_INVALID_PARAMETER);
6728 goto Cleanup;
6729 }
6730 DriverInfoDataW.DriverType = DriverInfoData->DriverType;
6731 DriverInfoDataW.Reserved = DriverInfoData->Reserved;
6732
6733 /* convert the strings to unicode */
6734 if (MultiByteToWideChar(CP_ACP,
6735 0,
6736 DriverInfoData->Description,
6737 LINE_LEN,
6738 DriverInfoDataW.Description,
6739 LINE_LEN) &&
6740 MultiByteToWideChar(CP_ACP,
6741 0,
6742 DriverInfoData->MfgName,
6743 LINE_LEN,
6744 DriverInfoDataW.MfgName,
6745 LINE_LEN) &&
6746 MultiByteToWideChar(CP_ACP,
6747 0,
6748 DriverInfoData->ProviderName,
6749 LINE_LEN,
6750 DriverInfoDataW.ProviderName,
6751 LINE_LEN))
6752 {
6753 if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
6754 {
6755 DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
6756 DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
6757 }
6758
6759 if (DriverInfoDetailData != NULL)
6760 {
6761 /* calculate the unicode buffer size from the ansi buffer size */
6762 HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
6763 BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
6764 (HardwareIDLen * sizeof(WCHAR));
6765
6766 DriverInfoDetailDataW = MyMalloc(BufSize);
6767 if (DriverInfoDetailDataW == NULL)
6768 {
6769 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6770 goto Cleanup;
6771 }
6772
6773 /* initialize the buffer */
6774 ZeroMemory(DriverInfoDetailDataW,
6775 BufSize);
6776 DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
6777 }
6778
6779 /* call the unicode version */
6780 ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
6781 DeviceInfoData,
6782 &DriverInfoDataW,
6783 DriverInfoDetailDataW,
6784 BufSize,
6785 RequiredSize);
6786
6787 if (ret)
6788 {
6789 if (DriverInfoDetailDataW != NULL)
6790 {
6791 /* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
6792 DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
6793 DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
6794 DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
6795 if (WideCharToMultiByte(CP_ACP,
6796 0,
6797 DriverInfoDetailDataW->SectionName,
6798 LINE_LEN,
6799 DriverInfoDetailData->SectionName,
6800 LINE_LEN,
6801 NULL,
6802 NULL) &&
6803 WideCharToMultiByte(CP_ACP,
6804 0,
6805 DriverInfoDetailDataW->InfFileName,
6806 MAX_PATH,
6807 DriverInfoDetailData->InfFileName,
6808 MAX_PATH,
6809 NULL,
6810 NULL) &&
6811 WideCharToMultiByte(CP_ACP,
6812 0,
6813 DriverInfoDetailDataW->DrvDescription,
6814 LINE_LEN,
6815 DriverInfoDetailData->DrvDescription,
6816 LINE_LEN,
6817 NULL,
6818 NULL) &&
6819 WideCharToMultiByte(CP_ACP,
6820 0,
6821 DriverInfoDetailDataW->HardwareID,
6822 HardwareIDLen,
6823 DriverInfoDetailData->HardwareID,
6824 HardwareIDLen,
6825 NULL,
6826 NULL))
6827 {
6828 DWORD len, cnt = 0;
6829 DWORD hwidlen = HardwareIDLen;
6830 CHAR *s = DriverInfoDetailData->HardwareID;
6831
6832 /* count the strings in the list */
6833 while (*s != '\0')
6834 {
6835 len = lstrlenA(s) + 1;
6836 if (hwidlen > len)
6837 {
6838 cnt++;
6839 s += len;
6840 hwidlen -= len;
6841 }
6842 else
6843 {
6844 /* looks like the string list wasn't terminated... */
6845 SetLastError(ERROR_INVALID_USER_BUFFER);
6846 ret = FALSE;
6847 break;
6848 }
6849 }
6850
6851 /* make sure CompatIDsOffset points to the second string in the
6852 list, if present */
6853 if (cnt > 1)
6854 {
6855 DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
6856 DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
6857 DriverInfoDetailData->CompatIDsOffset + 1;
6858 }
6859 else
6860 {
6861 DriverInfoDetailData->CompatIDsOffset = 0;
6862 DriverInfoDetailData->CompatIDsLength = 0;
6863 }
6864 }
6865 else
6866 {
6867 ret = FALSE;
6868 }
6869 }
6870
6871 if (RequiredSize != NULL)
6872 {
6873 *RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
6874 (((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
6875 }
6876 }
6877 }
6878
6879 Cleanup:
6880 if (DriverInfoDetailDataW != NULL)
6881 {
6882 MyFree(DriverInfoDetailDataW);
6883 }
6884
6885 return ret;
6886 }
6887
6888 /***********************************************************************
6889 * SetupDiGetDriverInfoDetailW (SETUPAPI.@)
6890 */
6891 BOOL WINAPI
6892 SetupDiGetDriverInfoDetailW(
6893 IN HDEVINFO DeviceInfoSet,
6894 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
6895 IN PSP_DRVINFO_DATA_W DriverInfoData,
6896 OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
6897 IN DWORD DriverInfoDetailDataSize,
6898 OUT PDWORD RequiredSize OPTIONAL)
6899 {
6900 BOOL ret = FALSE;
6901
6902 TRACE("%p %p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
6903 DriverInfoData, DriverInfoDetailData,
6904 DriverInfoDetailDataSize, RequiredSize);
6905
6906 if (!DeviceInfoSet)
6907 SetLastError(ERROR_INVALID_PARAMETER);
6908 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
6909 SetLastError(ERROR_INVALID_HANDLE);
6910 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
6911 SetLastError(ERROR_INVALID_HANDLE);
6912 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
6913 SetLastError(ERROR_INVALID_USER_BUFFER);
6914 else if (!DriverInfoData)
6915 SetLastError(ERROR_INVALID_PARAMETER);
6916 else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
6917 SetLastError(ERROR_INVALID_PARAMETER);
6918 else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
6919 SetLastError(ERROR_INVALID_PARAMETER);
6920 else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
6921 SetLastError(ERROR_INVALID_USER_BUFFER);
6922 else if (DriverInfoData->Reserved == 0)
6923 SetLastError(ERROR_NO_DRIVER_SELECTED);
6924 else
6925 {
6926 struct DriverInfoElement *driverInfoElement;
6927 LPWSTR HardwareIDs = NULL;
6928 LPWSTR CompatibleIDs = NULL;
6929 LPWSTR pBuffer = NULL;
6930 LPCWSTR DeviceID = NULL;
6931 ULONG HardwareIDsSize, CompatibleIDsSize;
6932 ULONG sizeNeeded, sizeLeft, size;
6933 BOOL Result;
6934
6935 driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
6936
6937 /* Get hardware and compatible IDs lists */
6938 Result = GetHardwareAndCompatibleIDsLists(
6939 DeviceInfoSet,
6940 DeviceInfoData,
6941 &HardwareIDs, &HardwareIDsSize,
6942 &CompatibleIDs, &CompatibleIDsSize);
6943 if (!Result)
6944 goto done;
6945
6946 sizeNeeded = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)
6947 + HardwareIDsSize + CompatibleIDsSize;
6948 if (RequiredSize)
6949 *RequiredSize = sizeNeeded;
6950
6951 if (!DriverInfoDetailData)
6952 {
6953 ret = TRUE;
6954 goto done;
6955 }
6956
6957 memcpy(
6958 DriverInfoDetailData,
6959 &driverInfoElement->Details,
6960 driverInfoElement->Details.cbSize);
6961 DriverInfoDetailData->CompatIDsOffset = 0;
6962 DriverInfoDetailData->CompatIDsLength = 0;
6963
6964 sizeLeft = (DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR);
6965 pBuffer = DriverInfoDetailData->HardwareID;
6966 /* Add as many as possible HardwareIDs in the list */
6967 DeviceID = HardwareIDs;
6968 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
6969 {
6970 TRACE("Adding %S to list\n", DeviceID);
6971 wcscpy(pBuffer, DeviceID);
6972 DeviceID += size + 1;
6973 pBuffer += size + 1;
6974 sizeLeft -= size + 1;
6975 DriverInfoDetailData->CompatIDsOffset += size + 1;
6976 }
6977 if (sizeLeft > 0)
6978 {
6979 *pBuffer = UNICODE_NULL;
6980 sizeLeft--;
6981 DriverInfoDetailData->CompatIDsOffset++;
6982 }
6983 /* Add as many as possible CompatibleIDs in the list */
6984 DeviceID = CompatibleIDs;
6985 while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
6986 {
6987 TRACE("Adding %S to list\n", DeviceID);
6988 wcscpy(pBuffer, DeviceID);
6989 DeviceID += size + 1;
6990 pBuffer += size + 1;
6991 sizeLeft -= size + 1;
6992 DriverInfoDetailData->CompatIDsLength += size + 1;
6993 }
6994 if (sizeLeft > 0)
6995 {
6996 *pBuffer = UNICODE_NULL;
6997 sizeLeft--;
6998 DriverInfoDetailData->CompatIDsLength++;
6999 }
7000
7001 if (sizeNeeded > DriverInfoDetailDataSize)
7002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7003 else
7004 ret = TRUE;
7005
7006 done:
7007 MyFree(HardwareIDs);
7008 MyFree(CompatibleIDs);
7009 }
7010
7011 TRACE("Returning %d\n", ret);
7012 return ret;
7013 }
7014
7015 /* Return the current hardware profile id, or -1 if error */
7016 static DWORD
7017 GetCurrentHwProfile(
7018 IN HDEVINFO DeviceInfoSet)
7019 {
7020 HKEY hKey = INVALID_HANDLE_VALUE;
7021 DWORD dwRegType, dwLength;
7022 DWORD hwProfile;
7023 LONG rc;
7024 DWORD ret = (DWORD)-1;
7025
7026 rc = RegOpenKeyExW(
7027 ((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
7028 REGSTR_PATH_IDCONFIGDB,
7029 0, /* Options */
7030 KEY_QUERY_VALUE,
7031 &hKey);
7032 if (rc != ERROR_SUCCESS)
7033 {
7034 SetLastError(rc);
7035 goto cleanup;
7036 }
7037
7038 dwLength = sizeof(DWORD);
7039 rc = RegQueryValueExW(
7040 hKey,
7041 REGSTR_VAL_CURRENTCONFIG,
7042 NULL,
7043 &dwRegType,
7044 (LPBYTE)&hwProfile, &dwLength);
7045 if (rc != ERROR_SUCCESS)
7046 {
7047 SetLastError(rc);
7048 goto cleanup;
7049 }
7050 else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
7051 {
7052 SetLastError(ERROR_GEN_FAILURE);
7053 goto cleanup;
7054 }
7055
7056 ret = hwProfile;
7057
7058 cleanup:
7059 if (hKey != INVALID_HANDLE_VALUE)
7060 RegCloseKey(hKey);
7061
7062 return hwProfile;
7063 }
7064
7065 static BOOL
7066 ResetDevice(
7067 IN HDEVINFO DeviceInfoSet,
7068 IN PSP_DEVINFO_DATA DeviceInfoData)
7069 {
7070 #ifndef __WINESRC__
7071 PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
7072 struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
7073 NTSTATUS Status;
7074
7075 if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
7076 {
7077 /* At the moment, I only know how to start local devices */
7078 SetLastError(ERROR_INVALID_COMPUTERNAME);
7079 return FALSE;
7080 }
7081
7082 RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, deviceInfo->DeviceName);
7083 Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
7084 SetLastError(RtlNtStatusToDosError(Status));
7085 return NT_SUCCESS(Status);
7086 #else
7087 FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
7088 return TRUE;
7089 #endif
7090 }
7091
7092 static BOOL StopDevice(
7093 IN HDEVINFO DeviceInfoSet,
7094 IN PSP_DEVINFO_DATA DeviceInfoData)
7095 {
7096 FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
7097 return TRUE;
7098 }
7099
7100 /***********************************************************************
7101 * SetupDiChangeState (SETUPAPI.@)
7102 */
7103 BOOL WINAPI
7104 SetupDiChangeState(
7105 IN HDEVINFO DeviceInfoSet,
7106 IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
7107 {
7108 PSP_PROPCHANGE_PARAMS PropChange;
7109 HKEY hKey = INVALID_HANDLE_VALUE;
7110 LPCWSTR RegistryValueName;
7111 DWORD dwConfigFlags, dwLength, dwRegType;
7112 LONG rc;
7113 BOOL ret = FALSE;
7114
7115 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7116
7117 if (!DeviceInfoData)
7118 PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChange;
7119 else
7120 PropChange = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->ClassInstallParams.PropChange;
7121 if (!PropChange)
7122 {
7123 SetLastError(ERROR_INVALID_PARAMETER);
7124 goto cleanup;
7125 }
7126
7127 if (PropChange->Scope == DICS_FLAG_GLOBAL)
7128 RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
7129 else
7130 RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
7131
7132 switch (PropChange->StateChange)
7133 {
7134 case DICS_ENABLE:
7135 case DICS_DISABLE:
7136 {
7137 /* Enable/disable device in registry */
7138 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
7139 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
7140 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
7141 if (hKey == INVALID_HANDLE_VALUE)
7142 break;
7143 dwLength = sizeof(DWORD);
7144 rc = RegQueryValueExW(
7145 hKey,
7146 RegistryValueName,
7147 NULL,
7148 &dwRegType,
7149 (LPBYTE)&dwConfigFlags, &dwLength);
7150 if (rc == ERROR_FILE_NOT_FOUND)
7151 dwConfigFlags = 0;
7152 else if (rc != ERROR_SUCCESS)
7153 {
7154 SetLastError(rc);
7155 goto cleanup;
7156 }
7157 else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
7158 {
7159 SetLastError(ERROR_GEN_FAILURE);
7160 goto cleanup;
7161 }
7162 if (PropChange->StateChange == DICS_ENABLE)
7163 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
7164 else
7165 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
7166 rc = RegSetValueEx(
7167 hKey,
7168 RegistryValueName,
7169 0,
7170 REG_DWORD,
7171 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
7172 if (rc != ERROR_SUCCESS)
7173 {
7174 SetLastError(rc);
7175 goto cleanup;
7176 }
7177
7178 /* Enable/disable device if needed */
7179 if (PropChange->Scope == DICS_FLAG_GLOBAL
7180 || PropChange->HwProfile == 0
7181 || PropChange->HwProfile == GetCurrentHwProfile(DeviceInfoSet))
7182 {
7183 if (PropChange->StateChange == DICS_ENABLE)
7184 ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
7185 else
7186 ret = StopDevice(DeviceInfoSet, DeviceInfoData);
7187 }
7188 else
7189 ret = TRUE;
7190 break;
7191 }
7192 case DICS_PROPCHANGE:
7193 {
7194 ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
7195 break;
7196 }
7197 default:
7198 {
7199 ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
7200 SetLastError(ERROR_NOT_SUPPORTED);
7201 }
7202 }
7203
7204 cleanup:
7205 if (hKey != INVALID_HANDLE_VALUE)
7206 RegCloseKey(hKey);
7207
7208 TRACE("Returning %d\n", ret);
7209 return ret;
7210 }
7211
7212 /***********************************************************************
7213 * SetupDiSelectBestCompatDrv (SETUPAPI.@)
7214 */
7215 BOOL WINAPI
7216 SetupDiSelectBestCompatDrv(
7217 IN HDEVINFO DeviceInfoSet,
7218 IN PSP_DEVINFO_DATA DeviceInfoData)
7219 {
7220 SP_DRVINFO_DATA_W drvInfoData;
7221 BOOL ret;
7222
7223 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7224
7225 /* Drivers are sorted by rank in the driver list, so
7226 * the first driver in the list is the best one.
7227 */
7228 drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
7229 ret = SetupDiEnumDriverInfoW(
7230 DeviceInfoSet,
7231 DeviceInfoData,
7232 SPDIT_COMPATDRIVER,
7233 0, /* Member index */
7234 &drvInfoData);
7235
7236 if (ret)
7237 {
7238 ret = SetupDiSetSelectedDriverW(
7239 DeviceInfoSet,
7240 DeviceInfoData,
7241 &drvInfoData);
7242 }
7243
7244 TRACE("Returning %d\n", ret);
7245 return ret;
7246 }
7247
7248 /***********************************************************************
7249 * SetupDiInstallDriverFiles (SETUPAPI.@)
7250 */
7251 BOOL WINAPI
7252 SetupDiInstallDriverFiles(
7253 IN HDEVINFO DeviceInfoSet,
7254 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
7255 {
7256 BOOL ret = FALSE;
7257
7258 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7259
7260 if (!DeviceInfoSet)
7261 SetLastError(ERROR_INVALID_PARAMETER);
7262 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
7263 SetLastError(ERROR_INVALID_HANDLE);
7264 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
7265 SetLastError(ERROR_INVALID_HANDLE);
7266 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
7267 SetLastError(ERROR_INVALID_USER_BUFFER);
7268 else if (DeviceInfoData && ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
7269 SetLastError(ERROR_NO_DRIVER_SELECTED);
7270 else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
7271 SetLastError(ERROR_NO_DRIVER_SELECTED);
7272 else
7273 {
7274 SP_DEVINSTALL_PARAMS_W InstallParams;
7275 struct DriverInfoElement *SelectedDriver;
7276 WCHAR SectionName[MAX_PATH];
7277 DWORD SectionNameLength = 0;
7278 PVOID InstallMsgHandler;
7279 PVOID InstallMsgHandlerContext;
7280 PVOID Context = NULL;
7281
7282 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
7283 ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7284 if (!ret)
7285 goto done;
7286
7287 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
7288 if (!SelectedDriver)
7289 {
7290 SetLastError(ERROR_NO_DRIVER_SELECTED);
7291 goto done;
7292 }
7293
7294 ret = SetupDiGetActualSectionToInstallW(
7295 SelectedDriver->InfFileDetails->hInf,
7296 SelectedDriver->Details.SectionName,
7297 SectionName, MAX_PATH - strlenW(DotCoInstallers), &SectionNameLength, NULL);
7298 if (!ret)
7299 goto done;
7300
7301 if (InstallParams.InstallMsgHandler)
7302 {
7303 InstallMsgHandler = InstallParams.InstallMsgHandler;
7304 InstallMsgHandlerContext = InstallParams.InstallMsgHandlerContext;
7305 }
7306 else
7307 {
7308 Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
7309 if (!Context)
7310 goto cleanup;
7311 InstallMsgHandler = SetupDefaultQueueCallback;
7312 InstallMsgHandlerContext = Context;
7313 }
7314 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
7315 SelectedDriver->InfFileDetails->hInf, SectionName,
7316 SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
7317 InstallMsgHandler, InstallMsgHandlerContext,
7318 DeviceInfoSet, DeviceInfoData);
7319 if (!ret)
7320 goto done;
7321
7322 /* Install files from .CoInstallers section */
7323 lstrcatW(SectionName, DotCoInstallers);
7324 ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
7325 SelectedDriver->InfFileDetails->hInf, SectionName,
7326 SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
7327 InstallMsgHandler, InstallMsgHandlerContext,
7328 DeviceInfoSet, DeviceInfoData);
7329 if (!ret)
7330 goto done;
7331
7332 /* Set the DI_NOFILECOPY flag to prevent another
7333 * installation during SetupDiInstallDevice */
7334 InstallParams.Flags |= DI_NOFILECOPY;
7335 ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7336
7337 cleanup:
7338 if (Context)
7339 SetupTermDefaultQueueCallback(Context);
7340 }
7341
7342 done:
7343 TRACE("Returning %d\n", ret);
7344 return ret;
7345 }
7346
7347 /***********************************************************************
7348 * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
7349 */
7350 BOOL WINAPI
7351 SetupDiRegisterCoDeviceInstallers(
7352 IN HDEVINFO DeviceInfoSet,
7353 IN PSP_DEVINFO_DATA DeviceInfoData)
7354 {
7355 BOOL ret = FALSE; /* Return value */
7356
7357 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7358
7359 if (!DeviceInfoSet)
7360 SetLastError(ERROR_INVALID_PARAMETER);
7361 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
7362 SetLastError(ERROR_INVALID_HANDLE);
7363 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
7364 SetLastError(ERROR_INVALID_HANDLE);
7365 else if (!DeviceInfoData)
7366 SetLastError(ERROR_INVALID_PARAMETER);
7367 else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
7368 SetLastError(ERROR_INVALID_USER_BUFFER);
7369 else
7370 {
7371 SP_DEVINSTALL_PARAMS_W InstallParams;
7372 struct DriverInfoElement *SelectedDriver;
7373 BOOL Result;
7374 DWORD DoAction;
7375 WCHAR SectionName[MAX_PATH];
7376 DWORD SectionNameLength = 0;
7377 HKEY hKey = INVALID_HANDLE_VALUE;
7378 PVOID Context = NULL;
7379
7380 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
7381 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7382 if (!Result)
7383 goto cleanup;
7384
7385 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
7386 if (SelectedDriver == NULL)
7387 {
7388 SetLastError(ERROR_NO_DRIVER_SELECTED);
7389 goto cleanup;
7390 }
7391
7392 /* Get .CoInstallers section name */
7393 Result = SetupDiGetActualSectionToInstallW(
7394 SelectedDriver->InfFileDetails->hInf,
7395 SelectedDriver->Details.SectionName,
7396 SectionName, MAX_PATH, &SectionNameLength, NULL);
7397 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
7398 goto cleanup;
7399 lstrcatW(SectionName, DotCoInstallers);
7400
7401 /* Open/Create driver key information */
7402 #if _WIN32_WINNT >= 0x502
7403 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
7404 #else
7405 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
7406 #endif
7407 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
7408 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
7409 if (hKey == INVALID_HANDLE_VALUE)
7410 goto cleanup;
7411
7412 /* Install .CoInstallers section */
7413 DoAction = SPINST_REGISTRY;
7414 if (!(InstallParams.Flags & DI_NOFILECOPY))
7415 {
7416 DoAction |= SPINST_FILES;
7417 Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
7418 if (!Context)
7419 goto cleanup;
7420 }
7421 Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
7422 SelectedDriver->InfFileDetails->hInf, SectionName,
7423 DoAction, hKey, NULL, SP_COPY_NEWER,
7424 SetupDefaultQueueCallback, Context,
7425 DeviceInfoSet, DeviceInfoData);
7426 if (!Result)
7427 goto cleanup;
7428
7429 ret = TRUE;
7430
7431 cleanup:
7432 if (Context)
7433 SetupTermDefaultQueueCallback(Context);
7434 if (hKey != INVALID_HANDLE_VALUE)
7435 RegCloseKey(hKey);
7436 }
7437
7438 TRACE("Returning %d\n", ret);
7439 return ret;
7440 }
7441
7442 static BOOL
7443 InstallOneInterface(
7444 IN LPGUID InterfaceGuid,
7445 IN LPCWSTR ReferenceString,
7446 IN LPCWSTR InterfaceSection,
7447 IN UINT InterfaceFlags)
7448 {
7449 if (InterfaceFlags != 0)
7450 {
7451 SetLastError(ERROR_INVALID_PARAMETER);
7452 return FALSE;
7453 }
7454
7455 FIXME("Need to InstallOneInterface(%s %s %s %u)\n", debugstr_guid(InterfaceGuid),
7456 debugstr_w(ReferenceString), debugstr_w(InterfaceSection), InterfaceFlags);
7457 return TRUE;
7458 }
7459
7460 /***********************************************************************
7461 * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
7462 */
7463 BOOL WINAPI
7464 SetupDiInstallDeviceInterfaces(
7465 IN HDEVINFO DeviceInfoSet,
7466 IN PSP_DEVINFO_DATA DeviceInfoData)
7467 {
7468 struct DeviceInfoSet *list = NULL;
7469 BOOL ret = FALSE;
7470
7471 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7472
7473 if (!DeviceInfoSet)
7474 SetLastError(ERROR_INVALID_PARAMETER);
7475 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
7476 SetLastError(ERROR_INVALID_HANDLE);
7477 else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
7478 SetLastError(ERROR_INVALID_HANDLE);
7479 else if (!DeviceInfoData)
7480 SetLastError(ERROR_INVALID_PARAMETER);
7481 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
7482 SetLastError(ERROR_INVALID_USER_BUFFER);
7483 else
7484 {
7485 struct DriverInfoElement *SelectedDriver;
7486 SP_DEVINSTALL_PARAMS_W InstallParams;
7487 WCHAR SectionName[MAX_PATH];
7488 DWORD SectionNameLength = 0;
7489 INFCONTEXT ContextInterface;
7490 LPWSTR InterfaceGuidString = NULL;
7491 LPWSTR ReferenceString = NULL;
7492 LPWSTR InterfaceSection = NULL;
7493 INT InterfaceFlags;
7494 GUID InterfaceGuid;
7495 BOOL Result;
7496
7497 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
7498 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7499 if (!Result)
7500 goto cleanup;
7501
7502 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
7503 if (SelectedDriver == NULL)
7504 {
7505 SetLastError(ERROR_NO_DRIVER_SELECTED);
7506 ret = FALSE;
7507 goto cleanup;
7508 }
7509
7510 /* Get .Interfaces section name */
7511 Result = SetupDiGetActualSectionToInstallW(
7512 SelectedDriver->InfFileDetails->hInf,
7513 SelectedDriver->Details.SectionName,
7514 SectionName, MAX_PATH, &SectionNameLength, NULL);
7515 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotInterfaces) - 1)
7516 goto cleanup;
7517 strcatW(SectionName, DotInterfaces);
7518
7519 ret = TRUE;
7520 Result = SetupFindFirstLineW(
7521 SelectedDriver->InfFileDetails->hInf,
7522 SectionName,
7523 AddInterface,
7524 &ContextInterface);
7525 while (ret && Result)
7526 {
7527 ret = GetStringField(&ContextInterface, 1, &InterfaceGuidString);
7528 if (!ret)
7529 goto cleanup;
7530 else if (strlenW(InterfaceGuidString) != MAX_GUID_STRING_LEN - 1)
7531 {
7532 SetLastError(ERROR_INVALID_PARAMETER);
7533 ret = FALSE;
7534 goto cleanup;
7535 }
7536
7537 InterfaceGuidString[MAX_GUID_STRING_LEN - 2] = '\0'; /* Replace the } by a NULL character */
7538 if (UuidFromStringW(&InterfaceGuidString[1], &InterfaceGuid) != RPC_S_OK)
7539 {
7540 /* Bad GUID, skip the entry */
7541 SetLastError(ERROR_INVALID_PARAMETER);
7542 ret = FALSE;
7543 goto cleanup;
7544 }
7545
7546 ret = GetStringField(&ContextInterface, 2, &ReferenceString);
7547 if (!ret)
7548 goto cleanup;
7549
7550 ret = GetStringField(&ContextInterface, 3, &InterfaceSection);
7551 if (!ret)
7552 goto cleanup;
7553
7554 ret = SetupGetIntField(
7555 &ContextInterface,
7556 4, /* Field index */
7557 &InterfaceFlags);
7558 if (!ret)
7559 {
7560 if (GetLastError() == ERROR_INVALID_PARAMETER)
7561 {
7562 /* The field may be empty. Ignore the error */
7563 InterfaceFlags = 0;
7564 ret = TRUE;
7565 }
7566 else
7567 goto cleanup;
7568 }
7569
7570 /* Install Interface */
7571 ret = InstallOneInterface(&InterfaceGuid, ReferenceString, InterfaceSection, InterfaceFlags);
7572
7573 cleanup:
7574 MyFree(InterfaceGuidString);
7575 MyFree(ReferenceString);
7576 MyFree(InterfaceSection);
7577 InterfaceGuidString = ReferenceString = InterfaceSection = NULL;
7578 Result = SetupFindNextMatchLineW(&ContextInterface, AddInterface, &ContextInterface);
7579 }
7580 }
7581
7582 TRACE("Returning %d\n", ret);
7583 return ret;
7584 }
7585
7586 BOOL
7587 InfIsFromOEMLocation(
7588 IN PCWSTR FullName,
7589 OUT LPBOOL IsOEMLocation)
7590 {
7591 PWCHAR last;
7592
7593 last = strrchrW(FullName, '\\');
7594 if (!last)
7595 {
7596 /* No directory specified */
7597 *IsOEMLocation = FALSE;
7598 }
7599 else
7600 {
7601 WCHAR Windir[MAX_PATH];
7602 UINT ret;
7603
7604 ret = GetWindowsDirectory(Windir, MAX_PATH);
7605 if (ret == 0 || ret >= MAX_PATH)
7606 {
7607 SetLastError(ERROR_GEN_FAILURE);
7608 return FALSE;
7609 }
7610
7611 if (strncmpW(FullName, Windir, last - FullName) == 0)
7612 {
7613 /* The path is %WINDIR%\Inf */
7614 *IsOEMLocation = FALSE;
7615 }
7616 else
7617 {
7618 /* The file is in another place */
7619 *IsOEMLocation = TRUE;
7620 }
7621 }
7622 return TRUE;
7623 }
7624
7625 /***********************************************************************
7626 * SetupDiInstallDevice (SETUPAPI.@)
7627 */
7628 BOOL WINAPI
7629 SetupDiInstallDevice(
7630 IN HDEVINFO DeviceInfoSet,
7631 IN PSP_DEVINFO_DATA DeviceInfoData)
7632 {
7633 SP_DEVINSTALL_PARAMS_W InstallParams;
7634 struct DriverInfoElement *SelectedDriver;
7635 SYSTEMTIME DriverDate;
7636 WCHAR SectionName[MAX_PATH];
7637 WCHAR Buffer[32];
7638 DWORD SectionNameLength = 0;
7639 BOOL Result = FALSE;
7640 ULONG DoAction;
7641 DWORD RequiredSize;
7642 LPWSTR pSectionName = NULL;
7643 WCHAR ClassName[MAX_CLASS_NAME_LEN];
7644 GUID ClassGuid;
7645 LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
7646 BOOL RebootRequired = FALSE;
7647 HKEY hKey = INVALID_HANDLE_VALUE;
7648 HKEY hClassKey = INVALID_HANDLE_VALUE;
7649 BOOL NeedtoCopyFile;
7650 LARGE_INTEGER fullVersion;
7651 LONG rc;
7652 PVOID Context = NULL;
7653 BOOL ret = FALSE; /* Return value */
7654
7655 TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
7656
7657 if (!DeviceInfoSet)
7658 SetLastError(ERROR_INVALID_PARAMETER);
7659 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
7660 SetLastError(ERROR_INVALID_HANDLE);
7661 else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
7662 SetLastError(ERROR_INVALID_HANDLE);
7663 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
7664 SetLastError(ERROR_INVALID_USER_BUFFER);
7665 else
7666 Result = TRUE;
7667
7668 if (!Result)
7669 {
7670 /* One parameter is bad */
7671 goto cleanup;
7672 }
7673
7674 InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
7675 Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7676 if (!Result)
7677 goto cleanup;
7678
7679 if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
7680 {
7681 /* Set FAILEDINSTALL in ConfigFlags registry value */
7682 DWORD ConfigFlags, regType;
7683 Result = SetupDiGetDeviceRegistryPropertyW(
7684 DeviceInfoSet,
7685 DeviceInfoData,
7686 SPDRP_CONFIGFLAGS,
7687 &regType,
7688 (PBYTE)&ConfigFlags,
7689 sizeof(ConfigFlags),
7690 NULL);
7691 if (!Result || regType != REG_DWORD)
7692 {
7693 SetLastError(ERROR_GEN_FAILURE);
7694 goto cleanup;
7695 }
7696 ConfigFlags |= DNF_DISABLED;
7697 Result = SetupDiSetDeviceRegistryPropertyW(
7698 DeviceInfoSet,
7699 DeviceInfoData,
7700 SPDRP_CONFIGFLAGS,
7701 (PBYTE)&ConfigFlags,
7702 sizeof(ConfigFlags));
7703 if (!Result)
7704 {
7705 SetLastError(ERROR_GEN_FAILURE);
7706 goto cleanup;
7707 }
7708
7709 ret = TRUE;
7710 goto cleanup;
7711 }
7712
7713 SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
7714 if (SelectedDriver == NULL)
7715 {
7716 SetLastError(ERROR_NO_DRIVER_SELECTED);
7717 goto cleanup;
7718 }
7719
7720 FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
7721
7722 Result = SetupDiGetActualSectionToInstallW(
7723 SelectedDriver->InfFileDetails->hInf,
7724 SelectedDriver->Details.SectionName,
7725 SectionName, MAX_PATH, &SectionNameLength, NULL);
7726 if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
7727 goto cleanup;
7728 pSectionName = &SectionName[strlenW(SectionName)];
7729
7730 /* Get information from [Version] section */
7731 if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
7732 goto cleanup;
7733 /* Format ClassGuid to a string */
7734 if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
7735 goto cleanup;
7736 RequiredSize = lstrlenW(lpGuidString);
7737 lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
7738 if (!lpFullGuidString)
7739 {
7740 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
7741 goto cleanup;
7742 }
7743 lpFullGuidString[0] = '{';
7744 memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
7745 lpFullGuidString[RequiredSize + 1] = '}';
7746 lpFullGuidString[RequiredSize + 2] = '\0';
7747
7748 /* Open/Create driver key information */
7749 #if _WIN32_WINNT >= 0x502
7750 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
7751 #else
7752 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
7753 #endif
7754 if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
7755 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
7756 if (hKey == INVALID_HANDLE_VALUE)
7757 goto cleanup;
7758
7759 /* Install main section */
7760 DoAction = 0;
7761 if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
7762 DoAction |= SPINST_REGISTRY;
7763 if (!(InstallParams.Flags & DI_NOFILECOPY))
7764 {
7765 DoAction |= SPINST_FILES;
7766 Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
7767 if (!Context)
7768 goto cleanup;
7769 }
7770 *pSectionName = '\0';
7771 Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
7772 SelectedDriver->InfFileDetails->hInf, SectionName,
7773 DoAction, hKey, NULL, SP_COPY_NEWER,
7774 SetupDefaultQueueCallback, Context,
7775 DeviceInfoSet, DeviceInfoData);
7776 if (!Result)
7777 goto cleanup;
7778 InstallParams.Flags |= DI_NOFILECOPY;
7779 SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
7780
7781 /* Write information to driver key */
7782 *pSectionName = UNICODE_NULL;
7783 memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
7784 TRACE("Write information to driver key\n");
7785 TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
7786 TRACE("DriverDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
7787 TRACE("DriverVersion : '%u.%u.%u.%u'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
7788 TRACE("InfPath : '%s'\n", debugstr_w(SelectedDriver->Details.InfFileName));
7789 TRACE("InfSection : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
7790 TRACE("InfSectionExt : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
7791 TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
7792 TRACE("ProviderName : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
7793 swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
7794 rc = RegSetValueEx(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
7795 if (rc == ERROR_SUCCESS)
7796 rc = RegSetValueEx(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
7797 if (rc == ERROR_SUCCESS)
7798 rc = RegSetValueEx(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
7799 if (rc == ERROR_SUCCESS)
7800 {
7801 swprintf(Buffer, L"%u.%u.%u.%u", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
7802 rc = RegSetValueEx(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
7803 }
7804 if (rc == ERROR_SUCCESS)
7805 rc = RegSetValueEx(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.InfFileName, (strlenW(SelectedDriver->Details.InfFileName) + 1) * sizeof(WCHAR));
7806 if (rc == ERROR_SUCCESS)
7807 rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
7808 if (rc == ERROR_SUCCESS)
7809 rc = RegSetValueEx(hKey, REGSTR_VAL_INFSECTIONEXT, 0, REG_SZ, (const BYTE *)&SectionName[strlenW(SelectedDriver->Details.SectionName)], (strlenW(SectionName) - strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
7810 if (rc == ERROR_SUCCESS)
7811 rc = RegSetValueEx(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
7812 if (rc == ERROR_SUCCESS)
7813 rc = RegSetValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
7814 if (rc != ERROR_SUCCESS)
7815 {
7816 SetLastError(rc);
7817 goto cleanup;
7818 }
7819 RegCloseKey(hKey);
7820 hKey = INVALID_HANDLE_VALUE;
7821
7822 /* FIXME: Process .LogConfigOverride section */
7823
7824 /* Install .Services section */
7825 strcpyW(pSectionName, DotServices);
7826 Result = SetupInstallServicesFromInfSectionExW(
7827 SelectedDriver->InfFileDetails->hInf,
7828 SectionName,
7829 0,
7830 DeviceInfoSet,
7831 DeviceInfoData,
7832 NULL,
7833 NULL);
7834 if (!Result)
7835 goto cleanup;
7836 if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
7837 RebootRequired = TRUE;
7838
7839 /* Copy .inf file to Inf\ directory (if needed) */
7840 Result = InfIsFromOEMLocation(SelectedDriver->InfFileDetails->FullInfFileName, &NeedtoCopyFile);
7841 if (!Result)
7842 goto cleanup;
7843 if (NeedtoCopyFile)
7844 {
7845 Result = SetupCopyOEMInfW(
7846 SelectedDriver->InfFileDetails->FullInfFileName,
7847 NULL,
7848 SPOST_NONE,
7849 SP_COPY_NOOVERWRITE,
7850 NULL, 0,
7851 NULL,
7852 NULL);
7853 if (!Result)
7854 goto cleanup;
7855 /* FIXME: create a new struct InfFileDetails, and set it to SelectedDriver->InfFileDetails,
7856 * to release use of current InfFile */
7857 }
7858
7859 /* Open device registry key */
7860 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
7861 if (hKey == INVALID_HANDLE_VALUE)
7862 goto cleanup;
7863
7864 /* Install .HW section */
7865 DoAction = 0;
7866 if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
7867 DoAction |= SPINST_REGISTRY;
7868 strcpyW(pSectionName, DotHW);
7869 Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
7870 SelectedDriver->InfFileDetails->hInf, SectionName,
7871 DoAction, hKey, NULL, 0,
7872 NULL, NULL,
7873 DeviceInfoSet, DeviceInfoData);
7874 if (!Result)
7875 goto cleanup;
7876
7877 /* Write information to enum key */
7878 TRACE("Write information to enum key\n");
7879 TRACE("Class : '%s'\n", debugstr_w(ClassName));
7880 TRACE("ClassGUID : '%s'\n", debugstr_w(lpFullGuidString));
7881 TRACE("DeviceDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
7882 TRACE("Mfg : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
7883 rc = RegSetValueEx(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
7884 if (rc == ERROR_SUCCESS)
7885 rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
7886 if (rc == ERROR_SUCCESS)
7887 rc = RegSetValueEx(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
7888 if (rc == ERROR_SUCCESS)
7889 rc = RegSetValueEx(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
7890 if (rc != ERROR_SUCCESS)
7891 {
7892 SetLastError(rc);
7893 goto cleanup;
7894 }
7895
7896 /* Start the device */
7897 if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
7898 ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
7899 else
7900 ret = TRUE;
7901
7902 cleanup:
7903 /* End of installation */
7904 if (hClassKey != INVALID_HANDLE_VALUE)
7905 RegCloseKey(hClassKey);
7906 if (hKey != INVALID_HANDLE_VALUE)
7907 RegCloseKey(hKey);
7908 if (lpGuidString)
7909 RpcStringFreeW(&lpGuidString);
7910 HeapFree(GetProcessHeap(), 0, lpFullGuidString);
7911 if (Context)
7912 SetupTermDefaultQueueCallback(Context);
7913 TRACE("Returning %d\n", ret);
7914 return ret;
7915 }