[SETUPAPI] Do not use SetupDiOpenDevRegKey in other SetupDi functions. Use SETUPDI_Op...
[reactos.git] / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "setupapi_private.h"
23
24 /* Unicode constants */
25 static const WCHAR BackSlash[] = {'\\',0};
26 static const WCHAR DateFormat[] = {'%','u','-','%','u','-','%','u',0};
27 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
28 static const WCHAR DotHW[] = {'.','H','W',0};
29 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
30 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
31 static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
32 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
33 static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
34
35 static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
36 static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
37 static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
38 static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
39 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};
40
41 typedef DWORD
42 (CALLBACK* CLASS_INSTALL_PROC) (
43 IN DI_FUNCTION InstallFunction,
44 IN HDEVINFO DeviceInfoSet,
45 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
46 typedef BOOL
47 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
48 IN HDEVINFO DeviceInfoSet,
49 IN OUT PSP_DEVINFO_DATA DeviceInfoData);
50 typedef DWORD
51 (CALLBACK* COINSTALLER_PROC) (
52 IN DI_FUNCTION InstallFunction,
53 IN HDEVINFO DeviceInfoSet,
54 IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
55 IN OUT PCOINSTALLER_CONTEXT_DATA Context);
56
57 struct CoInstallerElement
58 {
59 LIST_ENTRY ListEntry;
60
61 HMODULE Module;
62 COINSTALLER_PROC Function;
63 BOOL DoPostProcessing;
64 PVOID PrivateData;
65 };
66
67 struct GetSectionCallbackInfo
68 {
69 PSP_ALTPLATFORM_INFO PlatformInfo;
70 BYTE ProductType;
71 WORD SuiteMask;
72 DWORD PrefixLength;
73 WCHAR BestSection[LINE_LEN + 1];
74 DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
75 };
76
77
78
79 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
80 {
81 static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
82 '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
83 'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
84 '0','2','X','}',0};
85
86 sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
87 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
88 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
89 }
90
91 static DWORD
92 GetErrorCodeFromCrCode(const IN CONFIGRET cr)
93 {
94 switch (cr)
95 {
96 case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
97 case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER;
98 case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
99 case CR_FAILURE: return ERROR_GEN_FAILURE;
100 case CR_INVALID_DATA: return ERROR_INVALID_USER_BUFFER;
101 case CR_INVALID_DEVICE_ID: return ERROR_INVALID_PARAMETER;
102 case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
103 case CR_INVALID_DEVNODE: return ERROR_INVALID_PARAMETER;
104 case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS;
105 case CR_INVALID_POINTER: return ERROR_INVALID_PARAMETER;
106 case CR_INVALID_PROPERTY: return ERROR_INVALID_PARAMETER;
107 case CR_NO_SUCH_DEVNODE: return ERROR_FILE_NOT_FOUND;
108 case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
109 case CR_NO_SUCH_VALUE: return ERROR_FILE_NOT_FOUND;
110 case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
111 case CR_REGISTRY_ERROR: return ERROR_GEN_FAILURE;
112 case CR_ALREADY_SUCH_DEVINST: return ERROR_DEVINST_ALREADY_EXISTS;
113 case CR_SUCCESS: return ERROR_SUCCESS;
114 default: return ERROR_GEN_FAILURE;
115 }
116
117 /* Does not happen */
118 }
119
120 /* Lower scores are best ones */
121 static BOOL
122 CheckSectionValid(
123 IN LPCWSTR SectionName,
124 IN PSP_ALTPLATFORM_INFO PlatformInfo,
125 IN BYTE ProductType,
126 IN WORD SuiteMask,
127 OUT PDWORD ScorePlatform,
128 OUT PDWORD ScoreMajorVersion,
129 OUT PDWORD ScoreMinorVersion,
130 OUT PDWORD ScoreProductType,
131 OUT PDWORD ScoreSuiteMask)
132 {
133 LPWSTR Section = NULL;
134 //LPCWSTR pExtensionPlatform;
135 LPCWSTR pExtensionArchitecture;
136 LPWSTR Fields[6];
137 DWORD i;
138 BOOL ret = FALSE;
139
140 //static const WCHAR ExtensionPlatformNone[] = {'.',0};
141 static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
142 static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
143
144 static const WCHAR ExtensionArchitectureNone[] = {0};
145 static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
146 static const WCHAR ExtensionArchitectureamd64[] = {'A','M','D','6','4',0};
147 static const WCHAR ExtensionArchitectureia64[] = {'I','A','6','4',0};
148 static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
149 static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
150 static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
151
152 TRACE("%s %p 0x%x 0x%x\n",
153 debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
154
155 *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
156
157 Section = pSetupDuplicateString(SectionName);
158 if (!Section)
159 {
160 TRACE("pSetupDuplicateString() failed\n");
161 goto cleanup;
162 }
163
164 /* Set various extensions values */
165 switch (PlatformInfo->Platform)
166 {
167 case VER_PLATFORM_WIN32_WINDOWS:
168 //pExtensionPlatform = ExtensionPlatformWindows;
169 break;
170 case VER_PLATFORM_WIN32_NT:
171 //pExtensionPlatform = ExtensionPlatformNT;
172 break;
173 default:
174 ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
175 //pExtensionPlatform = ExtensionPlatformNone;
176 break;
177 }
178 switch (PlatformInfo->ProcessorArchitecture)
179 {
180 case PROCESSOR_ARCHITECTURE_ALPHA:
181 pExtensionArchitecture = ExtensionArchitecturealpha;
182 break;
183 case PROCESSOR_ARCHITECTURE_AMD64:
184 pExtensionArchitecture = ExtensionArchitectureamd64;
185 break;
186 case PROCESSOR_ARCHITECTURE_IA64:
187 pExtensionArchitecture = ExtensionArchitectureia64;
188 break;
189 case PROCESSOR_ARCHITECTURE_INTEL:
190 pExtensionArchitecture = ExtensionArchitecturex86;
191 break;
192 case PROCESSOR_ARCHITECTURE_MIPS:
193 pExtensionArchitecture = ExtensionArchitecturemips;
194 break;
195 case PROCESSOR_ARCHITECTURE_PPC:
196 pExtensionArchitecture = ExtensionArchitectureppc;
197 break;
198 default:
199 ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
200 case PROCESSOR_ARCHITECTURE_UNKNOWN:
201 pExtensionArchitecture = ExtensionArchitectureNone;
202 break;
203 }
204
205 /*
206 * Field[0] Platform
207 * Field[1] Architecture
208 * Field[2] Major version
209 * Field[3] Minor version
210 * Field[4] Product type
211 * Field[5] Suite mask
212 * Remark: these fields may be NULL if the information is not provided
213 */
214 Fields[0] = Section;
215 if (Fields[0] == NULL)
216 {
217 TRACE("No extension found\n");
218 *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
219 ret = TRUE;
220 goto cleanup;
221 }
222 Fields[1] = Fields[0] + 1;
223 Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
224 for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
225 {
226 Fields[i] = wcschr(Fields[i - 1], '.');
227 if (Fields[i])
228 {
229 Fields[i]++;
230 *(Fields[i] - 1) = UNICODE_NULL;
231 }
232 }
233 /* Take care of first 2 fields */
234 if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
235 {
236 if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
237 {
238 TRACE("Mismatch on platform field\n");
239 goto cleanup;
240 }
241 Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
242 }
243 else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
244 {
245 if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
246 {
247 TRACE("Mismatch on platform field\n");
248 goto cleanup;
249 }
250 Fields[1] += wcslen(ExtensionPlatformNT) - 1;
251 }
252 else
253 {
254 /* No platform specified */
255 *ScorePlatform |= 0x02;
256 }
257 if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
258 {
259 /* No architecture specified */
260 *ScorePlatform |= 0x01;
261 }
262 else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
263 {
264 TRACE("Mismatch on architecture field ('%s' and '%s')\n",
265 debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
266 goto cleanup;
267 }
268
269 /* Check if informations are matching */
270 if (Fields[2] && *Fields[2])
271 {
272 DWORD MajorVersion, MinorVersion = 0;
273 MajorVersion = strtoulW(Fields[2], NULL, 0);
274 if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
275 (errno == ERANGE || errno == EINVAL))
276 {
277 TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
278 goto cleanup;
279 }
280 if (Fields[3] && *Fields[3])
281 {
282 MinorVersion = strtoulW(Fields[3], NULL, 0);
283 if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
284 (errno == ERANGE || errno == EINVAL))
285 {
286 TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
287 goto cleanup;
288 }
289 }
290 if (PlatformInfo->MajorVersion < MajorVersion ||
291 (PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
292 {
293 TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
294 MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
295 goto cleanup;
296 }
297 *ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
298 if (MajorVersion == PlatformInfo->MajorVersion)
299 *ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
300 else
301 *ScoreMinorVersion = MinorVersion;
302 }
303 else if (Fields[3] && *Fields[3])
304 {
305 TRACE("Minor version found without major version\n");
306 goto cleanup;
307 }
308 else
309 {
310 *ScoreMajorVersion = PlatformInfo->MajorVersion;
311 *ScoreMinorVersion = PlatformInfo->MinorVersion;
312 }
313
314 if (Fields[4] && *Fields[4])
315 {
316 DWORD CurrentProductType;
317 CurrentProductType = strtoulW(Fields[4], NULL, 0);
318 if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
319 (errno == ERANGE || errno == EINVAL))
320 {
321 TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
322 goto cleanup;
323 }
324 if (CurrentProductType != ProductType)
325 {
326 TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
327 CurrentProductType, ProductType);
328 goto cleanup;
329 }
330 }
331 else
332 *ScoreProductType = 1;
333
334 if (Fields[5] && *Fields[5])
335 {
336 DWORD CurrentSuiteMask;
337 CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
338 if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
339 (errno == ERANGE || errno == EINVAL))
340 {
341 TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
342 goto cleanup;
343 }
344 if ((CurrentSuiteMask & ~SuiteMask) != 0)
345 {
346 TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
347 CurrentSuiteMask, SuiteMask);
348 goto cleanup;
349 }
350 *ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
351 }
352 else
353 *ScoreSuiteMask = SuiteMask;
354
355 ret = TRUE;
356
357 cleanup:
358 MyFree(Section);
359 return ret;
360 }
361
362 static BOOL
363 GetSectionCallback(
364 IN LPCWSTR SectionName,
365 IN PVOID Context)
366 {
367 struct GetSectionCallbackInfo *info = Context;
368 DWORD Score1, Score2, Score3, Score4, Score5;
369 BOOL ret;
370
371 if (SectionName[info->PrefixLength] != '.')
372 return TRUE;
373
374 ret = CheckSectionValid(
375 &SectionName[info->PrefixLength],
376 info->PlatformInfo,
377 info->ProductType,
378 info->SuiteMask,
379 &Score1, &Score2, &Score3, &Score4, &Score5);
380 if (!ret)
381 {
382 TRACE("Section %s not compatible\n", debugstr_w(SectionName));
383 return TRUE;
384 }
385 if (Score1 > info->BestScore1) goto done;
386 if (Score1 < info->BestScore1) goto bettersection;
387 if (Score2 > info->BestScore2) goto done;
388 if (Score2 < info->BestScore2) goto bettersection;
389 if (Score3 > info->BestScore3) goto done;
390 if (Score3 < info->BestScore3) goto bettersection;
391 if (Score4 > info->BestScore4) goto done;
392 if (Score4 < info->BestScore4) goto bettersection;
393 if (Score5 > info->BestScore5) goto done;
394 if (Score5 < info->BestScore5) goto bettersection;
395 goto done;
396
397 bettersection:
398 strcpyW(info->BestSection, SectionName);
399 info->BestScore1 = Score1;
400 info->BestScore2 = Score2;
401 info->BestScore3 = Score3;
402 info->BestScore4 = Score4;
403 info->BestScore5 = Score5;
404
405 done:
406 return TRUE;
407 }
408
409 /***********************************************************************
410 * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
411 */
412 BOOL WINAPI
413 SetupDiGetActualSectionToInstallExW(
414 IN HINF InfHandle,
415 IN PCWSTR InfSectionName,
416 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
417 OUT PWSTR InfSectionWithExt OPTIONAL,
418 IN DWORD InfSectionWithExtSize,
419 OUT PDWORD RequiredSize OPTIONAL,
420 OUT PWSTR* Extension OPTIONAL,
421 IN PVOID Reserved)
422 {
423 BOOL ret = FALSE;
424
425 TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
426 AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
427 RequiredSize, Extension, Reserved);
428
429 if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
430 SetLastError(ERROR_INVALID_HANDLE);
431 else if (!InfSectionName)
432 SetLastError(ERROR_INVALID_PARAMETER);
433 else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
434 SetLastError(ERROR_INVALID_USER_BUFFER);
435 else if (Reserved != NULL)
436 SetLastError(ERROR_INVALID_PARAMETER);
437 else
438 {
439 static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
440 static BYTE CurrentProductType = 0;
441 static WORD CurrentSuiteMask = 0;
442 PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
443 struct GetSectionCallbackInfo CallbackInfo;
444 DWORD dwFullLength;
445 BYTE ProductType;
446 WORD SuiteMask;
447
448 /* Fill platform info if needed */
449 if (AlternatePlatformInfo)
450 {
451 pPlatformInfo = AlternatePlatformInfo;
452 ProductType = 0;
453 SuiteMask = 0;
454 }
455 else
456 {
457 if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
458 {
459 /* That's the first time we go here. We need to fill in the structure */
460 SYSTEM_INFO SystemInfo;
461 GetSystemInfo(&SystemInfo);
462 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
463 CurrentPlatform.Platform = OsVersionInfo.dwPlatformId;
464 CurrentPlatform.MajorVersion = OsVersionInfo.dwMajorVersion;
465 CurrentPlatform.MinorVersion = OsVersionInfo.dwMinorVersion;
466 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
467 CurrentPlatform.Reserved = 0;
468 CurrentProductType = OsVersionInfo.wProductType;
469 CurrentSuiteMask = OsVersionInfo.wSuiteMask;
470 }
471 ProductType = CurrentProductType;
472 SuiteMask = CurrentSuiteMask;
473 }
474
475 CallbackInfo.PlatformInfo = pPlatformInfo;
476 CallbackInfo.ProductType = ProductType;
477 CallbackInfo.SuiteMask = SuiteMask;
478 CallbackInfo.PrefixLength = strlenW(InfSectionName);
479 CallbackInfo.BestScore1 = ULONG_MAX;
480 CallbackInfo.BestScore2 = ULONG_MAX;
481 CallbackInfo.BestScore3 = ULONG_MAX;
482 CallbackInfo.BestScore4 = ULONG_MAX;
483 CallbackInfo.BestScore5 = ULONG_MAX;
484 strcpyW(CallbackInfo.BestSection, InfSectionName);
485 TRACE("EnumerateSectionsStartingWith(InfSectionName = %S)\n", InfSectionName);
486 if (!EnumerateSectionsStartingWith(
487 InfHandle,
488 InfSectionName,
489 GetSectionCallback,
490 &CallbackInfo))
491 {
492 SetLastError(ERROR_GEN_FAILURE);
493 goto done;
494 }
495 TRACE("CallbackInfo.BestSection = %S\n", CallbackInfo.BestSection);
496
497 dwFullLength = lstrlenW(CallbackInfo.BestSection);
498 if (RequiredSize != NULL)
499 *RequiredSize = dwFullLength + 1;
500
501 if (InfSectionWithExtSize > 0)
502 {
503 if (InfSectionWithExtSize < dwFullLength + 1)
504 {
505 SetLastError(ERROR_INSUFFICIENT_BUFFER);
506 goto done;
507 }
508 strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
509 if (Extension)
510 {
511 DWORD dwLength = lstrlenW(InfSectionName);
512 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
513 }
514 }
515
516 ret = TRUE;
517 }
518
519 done:
520 TRACE("Returning %d\n", ret);
521 return ret;
522 }
523
524
525 BOOL
526 CreateDeviceInfo(
527 IN struct DeviceInfoSet *list,
528 IN LPCWSTR InstancePath,
529 IN LPCGUID pClassGuid,
530 OUT struct DeviceInfo **pDeviceInfo)
531 {
532 DWORD size;
533 CONFIGRET cr;
534 struct DeviceInfo *deviceInfo;
535
536 *pDeviceInfo = NULL;
537
538 size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
539 deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
540 if (!deviceInfo)
541 {
542 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
543 return FALSE;
544 }
545 ZeroMemory(deviceInfo, size);
546
547 cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
548 if (cr != CR_SUCCESS)
549 {
550 SetLastError(GetErrorCodeFromCrCode(cr));
551 return FALSE;
552 }
553
554 deviceInfo->set = list;
555 deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
556 strcpyW(deviceInfo->Data, InstancePath);
557 deviceInfo->instanceId = deviceInfo->Data;
558 deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
559 deviceInfo->DeviceDescription = NULL;
560 memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
561 deviceInfo->CreationFlags = 0;
562 InitializeListHead(&deviceInfo->DriverListHead);
563 InitializeListHead(&deviceInfo->InterfaceListHead);
564
565 *pDeviceInfo = deviceInfo;
566 return TRUE;
567 }
568
569
570 static BOOL
571 DestroyClassInstallParams(struct ClassInstallParams* installParams)
572 {
573 HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
574 HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
575 return TRUE;
576 }
577
578 static BOOL
579 DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
580 {
581 PLIST_ENTRY ListEntry;
582 struct DriverInfoElement *driverInfo;
583 struct DeviceInterface *deviceInterface;
584
585 while (!IsListEmpty(&deviceInfo->DriverListHead))
586 {
587 ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
588 driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
589 if (!DestroyDriverInfoElement(driverInfo))
590 return FALSE;
591 }
592 while (!IsListEmpty(&deviceInfo->InterfaceListHead))
593 {
594 ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
595 deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
596 if (!DestroyDeviceInterface(deviceInterface))
597 return FALSE;
598 }
599 DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
600 if (deviceInfo->hmodDevicePropPageProvider)
601 FreeLibrary(deviceInfo->hmodDevicePropPageProvider);
602 return HeapFree(GetProcessHeap(), 0, deviceInfo);
603 }
604
605 static BOOL
606 DestroyDeviceInfoSet(struct DeviceInfoSet* list)
607 {
608 PLIST_ENTRY ListEntry;
609 struct DeviceInfo *deviceInfo;
610
611 while (!IsListEmpty(&list->ListHead))
612 {
613 ListEntry = RemoveHeadList(&list->ListHead);
614 deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
615 if (!DestroyDeviceInfo(deviceInfo))
616 return FALSE;
617 }
618 if (list->HKLM != HKEY_LOCAL_MACHINE)
619 RegCloseKey(list->HKLM);
620 CM_Disconnect_Machine(list->hMachine);
621 DestroyClassInstallParams(&list->ClassInstallParams);
622 if (list->hmodClassPropPageProvider)
623 FreeLibrary(list->hmodClassPropPageProvider);
624 return HeapFree(GetProcessHeap(), 0, list);
625 }
626
627 /***********************************************************************
628 * SetupDiBuildClassInfoList (SETUPAPI.@)
629 *
630 * Returns a list of setup class GUIDs that identify the classes
631 * that are installed on a local machine.
632 *
633 * PARAMS
634 * Flags [I] control exclusion of classes from the list.
635 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
636 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
637 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
638 *
639 * RETURNS
640 * Success: TRUE.
641 * Failure: FALSE.
642 */
643 BOOL WINAPI SetupDiBuildClassInfoList(
644 DWORD Flags,
645 LPGUID ClassGuidList,
646 DWORD ClassGuidListSize,
647 PDWORD RequiredSize)
648 {
649 TRACE("\n");
650 return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
651 ClassGuidListSize, RequiredSize,
652 NULL, NULL);
653 }
654
655 /***********************************************************************
656 * SetupDiBuildClassInfoListExA (SETUPAPI.@)
657 *
658 * Returns a list of setup class GUIDs that identify the classes
659 * that are installed on a local or remote machine.
660 *
661 * PARAMS
662 * Flags [I] control exclusion of classes from the list.
663 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
664 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
665 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
666 * MachineName [I] name of a remote machine.
667 * Reserved [I] must be NULL.
668 *
669 * RETURNS
670 * Success: TRUE.
671 * Failure: FALSE.
672 */
673 BOOL WINAPI SetupDiBuildClassInfoListExA(
674 DWORD Flags,
675 LPGUID ClassGuidList,
676 DWORD ClassGuidListSize,
677 PDWORD RequiredSize,
678 LPCSTR MachineName,
679 PVOID Reserved)
680 {
681 LPWSTR MachineNameW = NULL;
682 BOOL bResult;
683
684 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
685 ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
686
687 if (MachineName)
688 {
689 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
690 if (MachineNameW == NULL) return FALSE;
691 }
692
693 bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
694 ClassGuidListSize, RequiredSize,
695 MachineNameW, Reserved);
696
697 MyFree(MachineNameW);
698
699 return bResult;
700 }
701
702 /***********************************************************************
703 * SetupDiBuildClassInfoListExW (SETUPAPI.@)
704 *
705 * Returns a list of setup class GUIDs that identify the classes
706 * that are installed on a local or remote machine.
707 *
708 * PARAMS
709 * Flags [I] control exclusion of classes from the list.
710 * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
711 * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
712 * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
713 * MachineName [I] name of a remote machine.
714 * Reserved [I] must be NULL.
715 *
716 * RETURNS
717 * Success: TRUE.
718 * Failure: FALSE.
719 */
720 BOOL WINAPI SetupDiBuildClassInfoListExW(
721 DWORD Flags,
722 LPGUID ClassGuidList,
723 DWORD ClassGuidListSize,
724 PDWORD RequiredSize,
725 LPCWSTR MachineName,
726 PVOID Reserved)
727 {
728 WCHAR szKeyName[40];
729 HKEY hClassesKey = INVALID_HANDLE_VALUE;
730 HKEY hClassKey;
731 DWORD dwLength;
732 DWORD dwIndex;
733 LONG lError;
734 DWORD dwGuidListIndex = 0;
735
736 TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
737 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
738
739 if (!RequiredSize)
740 {
741 SetLastError(ERROR_INVALID_PARAMETER);
742 return FALSE;
743 }
744 else if (!ClassGuidList && ClassGuidListSize > 0)
745 {
746 SetLastError(ERROR_INVALID_PARAMETER);
747 return FALSE;
748 }
749
750 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
751 KEY_ENUMERATE_SUB_KEYS,
752 DIOCR_INSTALLER,
753 MachineName,
754 Reserved);
755 if (hClassesKey == INVALID_HANDLE_VALUE)
756 {
757 return FALSE;
758 }
759
760 for (dwIndex = 0; ; dwIndex++)
761 {
762 dwLength = 40;
763 lError = RegEnumKeyExW(hClassesKey,
764 dwIndex,
765 szKeyName,
766 &dwLength,
767 NULL,
768 NULL,
769 NULL,
770 NULL);
771 TRACE("RegEnumKeyExW() returns %d\n", lError);
772 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
773 {
774 TRACE("Key name: %s\n", debugstr_w(szKeyName));
775
776 if (RegOpenKeyExW(hClassesKey,
777 szKeyName,
778 0,
779 KEY_QUERY_VALUE,
780 &hClassKey))
781 {
782 RegCloseKey(hClassesKey);
783 return FALSE;
784 }
785
786 if (!RegQueryValueExW(hClassKey,
787 REGSTR_VAL_NOUSECLASS,
788 NULL,
789 NULL,
790 NULL,
791 NULL))
792 {
793 TRACE("'NoUseClass' value found!\n");
794 RegCloseKey(hClassKey);
795 continue;
796 }
797
798 if ((Flags & DIBCI_NOINSTALLCLASS) &&
799 (!RegQueryValueExW(hClassKey,
800 REGSTR_VAL_NOINSTALLCLASS,
801 NULL,
802 NULL,
803 NULL,
804 NULL)))
805 {
806 TRACE("'NoInstallClass' value found!\n");
807 RegCloseKey(hClassKey);
808 continue;
809 }
810
811 if ((Flags & DIBCI_NODISPLAYCLASS) &&
812 (!RegQueryValueExW(hClassKey,
813 REGSTR_VAL_NODISPLAYCLASS,
814 NULL,
815 NULL,
816 NULL,
817 NULL)))
818 {
819 TRACE("'NoDisplayClass' value found!\n");
820 RegCloseKey(hClassKey);
821 continue;
822 }
823
824 RegCloseKey(hClassKey);
825
826 TRACE("Guid: %s\n", debugstr_w(szKeyName));
827 if (dwGuidListIndex < ClassGuidListSize)
828 {
829 if (szKeyName[0] == '{' && szKeyName[37] == '}')
830 {
831 szKeyName[37] = 0;
832 }
833 TRACE("Guid: %p\n", &szKeyName[1]);
834
835 UuidFromStringW(&szKeyName[1],
836 &ClassGuidList[dwGuidListIndex]);
837 }
838
839 dwGuidListIndex++;
840 }
841
842 if (lError != ERROR_SUCCESS)
843 break;
844 }
845
846 RegCloseKey(hClassesKey);
847
848 if (RequiredSize != NULL)
849 *RequiredSize = dwGuidListIndex;
850
851 if (ClassGuidListSize < dwGuidListIndex)
852 {
853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
854 return FALSE;
855 }
856
857 return TRUE;
858 }
859
860 /***********************************************************************
861 * SetupDiClassGuidsFromNameA (SETUPAPI.@)
862 */
863 BOOL WINAPI SetupDiClassGuidsFromNameA(
864 LPCSTR ClassName,
865 LPGUID ClassGuidList,
866 DWORD ClassGuidListSize,
867 PDWORD RequiredSize)
868 {
869 return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
870 ClassGuidListSize, RequiredSize,
871 NULL, NULL);
872 }
873
874 /***********************************************************************
875 * SetupDiClassGuidsFromNameW (SETUPAPI.@)
876 */
877 BOOL WINAPI SetupDiClassGuidsFromNameW(
878 LPCWSTR ClassName,
879 LPGUID ClassGuidList,
880 DWORD ClassGuidListSize,
881 PDWORD RequiredSize)
882 {
883 return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
884 ClassGuidListSize, RequiredSize,
885 NULL, NULL);
886 }
887
888 /***********************************************************************
889 * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
890 */
891 BOOL WINAPI SetupDiClassGuidsFromNameExA(
892 LPCSTR ClassName,
893 LPGUID ClassGuidList,
894 DWORD ClassGuidListSize,
895 PDWORD RequiredSize,
896 LPCSTR MachineName,
897 PVOID Reserved)
898 {
899 LPWSTR ClassNameW = NULL;
900 LPWSTR MachineNameW = NULL;
901 BOOL bResult;
902
903 TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName), ClassGuidList,
904 ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
905
906 if (!ClassName)
907 {
908 SetLastError(ERROR_INVALID_PARAMETER);
909 return FALSE;
910 }
911
912 ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
913 if (ClassNameW == NULL)
914 return FALSE;
915
916 if (MachineName)
917 {
918 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
919 if (MachineNameW == NULL)
920 {
921 MyFree(ClassNameW);
922 return FALSE;
923 }
924 }
925
926 bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
927 ClassGuidListSize, RequiredSize,
928 MachineNameW, Reserved);
929
930 MyFree(MachineNameW);
931 MyFree(ClassNameW);
932
933 return bResult;
934 }
935
936 /***********************************************************************
937 * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
938 */
939 BOOL WINAPI SetupDiClassGuidsFromNameExW(
940 LPCWSTR ClassName,
941 LPGUID ClassGuidList,
942 DWORD ClassGuidListSize,
943 PDWORD RequiredSize,
944 LPCWSTR MachineName,
945 PVOID Reserved)
946 {
947 WCHAR szKeyName[40];
948 WCHAR szClassName[MAX_CLASS_NAME_LEN];
949 HKEY hClassesKey;
950 HKEY hClassKey;
951 DWORD dwLength;
952 DWORD dwIndex;
953 LONG lError;
954 DWORD dwGuidListIndex = 0;
955
956 TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
957 ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
958
959 if (!ClassName || !RequiredSize)
960 {
961 SetLastError(ERROR_INVALID_PARAMETER);
962 return FALSE;
963 }
964 if (!ClassGuidList && ClassGuidListSize > 0)
965 {
966 SetLastError(ERROR_INVALID_PARAMETER);
967 return FALSE;
968 }
969 *RequiredSize = 0;
970
971 hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
972 KEY_ENUMERATE_SUB_KEYS,
973 DIOCR_INSTALLER,
974 MachineName,
975 Reserved);
976 if (hClassesKey == INVALID_HANDLE_VALUE)
977 {
978 return FALSE;
979 }
980
981 for (dwIndex = 0; ; dwIndex++)
982 {
983 dwLength = 40;
984 lError = RegEnumKeyExW(hClassesKey,
985 dwIndex,
986 szKeyName,
987 &dwLength,
988 NULL,
989 NULL,
990 NULL,
991 NULL);
992 TRACE("RegEnumKeyExW() returns %d\n", lError);
993 if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
994 {
995 TRACE("Key name: %p\n", szKeyName);
996
997 if (RegOpenKeyExW(hClassesKey,
998 szKeyName,
999 0,
1000 KEY_QUERY_VALUE,
1001 &hClassKey))
1002 {
1003 RegCloseKey(hClassesKey);
1004 return FALSE;
1005 }
1006
1007 dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
1008 if (!RegQueryValueExW(hClassKey,
1009 REGSTR_VAL_CLASS,
1010 NULL,
1011 NULL,
1012 (LPBYTE)szClassName,
1013 &dwLength))
1014 {
1015 TRACE("Class name: %p\n", szClassName);
1016
1017 if (strcmpiW(szClassName, ClassName) == 0)
1018 {
1019 TRACE("Found matching class name\n");
1020
1021 TRACE("Guid: %p\n", szKeyName);
1022 if (dwGuidListIndex < ClassGuidListSize)
1023 {
1024 if (szKeyName[0] == '{' && szKeyName[37] == '}')
1025 {
1026 szKeyName[37] = 0;
1027 }
1028 TRACE("Guid: %p\n", &szKeyName[1]);
1029
1030 UuidFromStringW(&szKeyName[1],
1031 &ClassGuidList[dwGuidListIndex]);
1032 }
1033
1034 dwGuidListIndex++;
1035 }
1036 }
1037
1038 RegCloseKey(hClassKey);
1039 }
1040
1041 if (lError != ERROR_SUCCESS)
1042 break;
1043 }
1044
1045 RegCloseKey(hClassesKey);
1046
1047 if (RequiredSize != NULL)
1048 *RequiredSize = dwGuidListIndex;
1049
1050 if (ClassGuidListSize < dwGuidListIndex)
1051 {
1052 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1053 return FALSE;
1054 }
1055
1056 return TRUE;
1057 }
1058
1059 /***********************************************************************
1060 * SetupDiClassNameFromGuidA (SETUPAPI.@)
1061 */
1062 BOOL WINAPI SetupDiClassNameFromGuidA(
1063 const GUID* ClassGuid,
1064 PSTR ClassName,
1065 DWORD ClassNameSize,
1066 PDWORD RequiredSize)
1067 {
1068 return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1069 ClassNameSize, RequiredSize,
1070 NULL, NULL);
1071 }
1072
1073 /***********************************************************************
1074 * SetupDiClassNameFromGuidW (SETUPAPI.@)
1075 */
1076 BOOL WINAPI SetupDiClassNameFromGuidW(
1077 const GUID* ClassGuid,
1078 PWSTR ClassName,
1079 DWORD ClassNameSize,
1080 PDWORD RequiredSize)
1081 {
1082 return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1083 ClassNameSize, RequiredSize,
1084 NULL, NULL);
1085 }
1086
1087 /***********************************************************************
1088 * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1089 */
1090 BOOL WINAPI SetupDiClassNameFromGuidExA(
1091 const GUID* ClassGuid,
1092 PSTR ClassName,
1093 DWORD ClassNameSize,
1094 PDWORD RequiredSize,
1095 PCSTR MachineName,
1096 PVOID Reserved)
1097 {
1098 WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1099 LPWSTR MachineNameW = NULL;
1100 BOOL ret;
1101
1102 if (MachineName)
1103 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1104 ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1105 RequiredSize, MachineNameW, Reserved);
1106 if (ret)
1107 {
1108 int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1109 ClassNameSize, NULL, NULL);
1110 if (len == 0 || len > ClassNameSize)
1111 {
1112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1113 ret = FALSE;
1114 }
1115 }
1116 MyFree(MachineNameW);
1117 return ret;
1118 }
1119
1120 /***********************************************************************
1121 * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1122 */
1123 BOOL WINAPI SetupDiClassNameFromGuidExW(
1124 const GUID* ClassGuid,
1125 PWSTR ClassName,
1126 DWORD ClassNameSize,
1127 PDWORD RequiredSize,
1128 PCWSTR MachineName,
1129 PVOID Reserved)
1130 {
1131 HKEY hKey;
1132 DWORD dwLength;
1133 DWORD dwRegType;
1134 LONG rc;
1135 PWSTR Buffer;
1136
1137 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
1138 ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
1139
1140 /* Make sure there's a GUID */
1141 if (ClassGuid == NULL)
1142 {
1143 SetLastError(ERROR_INVALID_CLASS); /* On Vista: ERROR_INVALID_USER_BUFFER */
1144 return FALSE;
1145 }
1146
1147 /* Make sure there's a real buffer when there's a size */
1148 if ((ClassNameSize > 0) && (ClassName == NULL))
1149 {
1150 SetLastError(ERROR_INVALID_PARAMETER); /* On Vista: ERROR_INVALID_USER_BUFFER */
1151 return FALSE;
1152 }
1153
1154 /* Open the key for the GUID */
1155 hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved);
1156
1157 if (hKey == INVALID_HANDLE_VALUE)
1158 return FALSE;
1159
1160 /* Retrieve the class name data and close the key */
1161 rc = QueryRegistryValue(hKey, REGSTR_VAL_CLASS, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
1162 RegCloseKey(hKey);
1163
1164 /* Make sure we got the data */
1165 if (rc != ERROR_SUCCESS)
1166 {
1167 SetLastError(rc);
1168 return FALSE;
1169 }
1170
1171 /* Make sure the data is a string */
1172 if (dwRegType != REG_SZ)
1173 {
1174 MyFree(Buffer);
1175 SetLastError(ERROR_GEN_FAILURE);
1176 return FALSE;
1177 }
1178
1179 /* Determine the length of the class name */
1180 dwLength /= sizeof(WCHAR);
1181
1182 if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
1183 /* Count the null-terminator */
1184 dwLength++;
1185
1186 /* Inform the caller about the class name */
1187 if ((ClassName != NULL) && (dwLength <= ClassNameSize))
1188 {
1189 memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
1190 ClassName[dwLength - 1] = UNICODE_NULL;
1191 }
1192
1193 /* Inform the caller about the required size */
1194 if (RequiredSize != NULL)
1195 *RequiredSize = dwLength;
1196
1197 /* Clean up the buffer */
1198 MyFree(Buffer);
1199
1200 /* Make sure the buffer was large enough */
1201 if ((ClassName == NULL) || (dwLength > ClassNameSize))
1202 {
1203 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1204 return FALSE;
1205 }
1206
1207 return TRUE;
1208 }
1209
1210 /***********************************************************************
1211 * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1212 */
1213 HDEVINFO WINAPI
1214 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
1215 HWND hwndParent)
1216 {
1217 return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1218 }
1219
1220 /***********************************************************************
1221 * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1222 */
1223 HDEVINFO WINAPI
1224 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
1225 HWND hwndParent,
1226 PCSTR MachineName,
1227 PVOID Reserved)
1228 {
1229 LPWSTR MachineNameW = NULL;
1230 HDEVINFO hDevInfo;
1231
1232 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1233 debugstr_a(MachineName), Reserved);
1234
1235 if (MachineName)
1236 {
1237 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1238 if (MachineNameW == NULL)
1239 return INVALID_HANDLE_VALUE;
1240 }
1241
1242 hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1243 MachineNameW, Reserved);
1244
1245 MyFree(MachineNameW);
1246
1247 return hDevInfo;
1248 }
1249
1250 /***********************************************************************
1251 * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1252 *
1253 * Create an empty DeviceInfoSet list.
1254 *
1255 * PARAMS
1256 * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1257 * with this list.
1258 * hwndParent [I] hwnd needed for interface related actions.
1259 * MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1260 * local registry will be used.
1261 * Reserved [I] must be NULL
1262 *
1263 * RETURNS
1264 * Success: empty list.
1265 * Failure: INVALID_HANDLE_VALUE.
1266 */
1267 HDEVINFO WINAPI
1268 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
1269 HWND hwndParent,
1270 PCWSTR MachineName,
1271 PVOID Reserved)
1272 {
1273 struct DeviceInfoSet *list = NULL;
1274 DWORD size = FIELD_OFFSET(struct DeviceInfoSet, szData);
1275 DWORD rc;
1276 CONFIGRET cr;
1277 HDEVINFO ret = INVALID_HANDLE_VALUE;
1278
1279 TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1280 debugstr_w(MachineName), Reserved);
1281
1282 if (MachineName != NULL)
1283 {
1284 SIZE_T len = strlenW(MachineName);
1285 if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
1286 {
1287 SetLastError(ERROR_INVALID_MACHINENAME);
1288 goto cleanup;
1289 }
1290 if(len > 0)
1291 size += (len + 3) * sizeof(WCHAR);
1292 else
1293 MachineName = NULL;
1294 }
1295
1296 if (Reserved != NULL)
1297 {
1298 SetLastError(ERROR_INVALID_PARAMETER);
1299 return INVALID_HANDLE_VALUE;
1300 }
1301
1302 list = MyMalloc(size);
1303 if (!list)
1304 {
1305 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1306 return INVALID_HANDLE_VALUE;
1307 }
1308 ZeroMemory(list, FIELD_OFFSET(struct DeviceInfoSet, szData));
1309
1310 list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
1311 memcpy(&list->ClassGuid,
1312 ClassGuid ? ClassGuid : &GUID_NULL,
1313 sizeof(list->ClassGuid));
1314 list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1315 list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
1316 list->InstallParams.hwndParent = hwndParent;
1317 if (MachineName)
1318 {
1319 rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
1320 if (rc != ERROR_SUCCESS)
1321 {
1322 SetLastError(ERROR_INVALID_MACHINENAME);
1323 goto cleanup;
1324 }
1325
1326 list->szData[0] = list->szData[1] = '\\';
1327 strcpyW(list->szData + 2, MachineName);
1328 list->MachineName = list->szData;
1329 }
1330 else
1331 {
1332 list->HKLM = HKEY_LOCAL_MACHINE;
1333 list->MachineName = NULL;
1334 }
1335 cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
1336 if (cr != CR_SUCCESS)
1337 {
1338 SetLastError(GetErrorCodeFromCrCode(cr));
1339 goto cleanup;
1340 }
1341 InitializeListHead(&list->DriverListHead);
1342 InitializeListHead(&list->ListHead);
1343
1344 return (HDEVINFO)list;
1345
1346 cleanup:
1347 if (ret == INVALID_HANDLE_VALUE)
1348 {
1349 if (list)
1350 {
1351 if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
1352 RegCloseKey(list->HKLM);
1353 MyFree(list);
1354 }
1355 }
1356 return ret;
1357 }
1358
1359 /***********************************************************************
1360 * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1361 */
1362 HKEY WINAPI SetupDiCreateDevRegKeyA(
1363 HDEVINFO DeviceInfoSet,
1364 PSP_DEVINFO_DATA DeviceInfoData,
1365 DWORD Scope,
1366 DWORD HwProfile,
1367 DWORD KeyType,
1368 HINF InfHandle,
1369 PCSTR InfSectionName)
1370 {
1371 PWSTR InfSectionNameW = NULL;
1372 HKEY key;
1373
1374 TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1375 HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1376
1377 if (InfHandle)
1378 {
1379 if (!InfSectionName)
1380 {
1381 SetLastError(ERROR_INVALID_PARAMETER);
1382 return INVALID_HANDLE_VALUE;
1383 }
1384 else
1385 {
1386 InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
1387 if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1388 }
1389 }
1390 key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1391 HwProfile, KeyType, InfHandle, InfSectionNameW);
1392 MyFree(InfSectionNameW);
1393 return key;
1394 }
1395
1396 static HKEY
1397 OpenHardwareProfileKey(
1398 IN HKEY HKLM,
1399 IN DWORD HwProfile,
1400 IN DWORD samDesired);
1401
1402 /***********************************************************************
1403 * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1404 */
1405 HKEY WINAPI SetupDiCreateDevRegKeyW(
1406 HDEVINFO DeviceInfoSet,
1407 PSP_DEVINFO_DATA DeviceInfoData,
1408 DWORD Scope,
1409 DWORD HwProfile,
1410 DWORD KeyType,
1411 HINF InfHandle,
1412 PCWSTR InfSectionName)
1413 {
1414 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1415 struct DeviceInfo *deviceInfo;
1416 HKEY key = INVALID_HANDLE_VALUE;
1417 LPWSTR lpGuidString = NULL;
1418 LPWSTR DriverKey = NULL; /* {GUID}\Index */
1419 LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
1420 DWORD Index; /* Index used in the DriverKey name */
1421 DWORD dwSize;
1422 DWORD Disposition;
1423 DWORD rc;
1424 HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
1425 HKEY hEnumKey = NULL;
1426 HKEY hClassKey = NULL;
1427 HKEY hDeviceKey = INVALID_HANDLE_VALUE;
1428 HKEY hKey = NULL;
1429 HKEY RootKey;
1430
1431 TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1432 HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1433
1434 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1435 {
1436 SetLastError(ERROR_INVALID_HANDLE);
1437 return INVALID_HANDLE_VALUE;
1438 }
1439 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1440 {
1441 SetLastError(ERROR_INVALID_HANDLE);
1442 return INVALID_HANDLE_VALUE;
1443 }
1444 if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1445 || !DeviceInfoData->Reserved)
1446 {
1447 SetLastError(ERROR_INVALID_PARAMETER);
1448 return INVALID_HANDLE_VALUE;
1449 }
1450 if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1451 {
1452 SetLastError(ERROR_INVALID_FLAGS);
1453 return INVALID_HANDLE_VALUE;
1454 }
1455 if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1456 {
1457 SetLastError(ERROR_INVALID_FLAGS);
1458 return INVALID_HANDLE_VALUE;
1459 }
1460 if (InfHandle && !InfSectionName)
1461 {
1462 SetLastError(ERROR_INVALID_PARAMETER);
1463 return INVALID_HANDLE_VALUE;
1464 }
1465 if (!InfHandle && InfSectionName)
1466 {
1467 SetLastError(ERROR_INVALID_PARAMETER);
1468 return INVALID_HANDLE_VALUE;
1469 }
1470
1471 deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1472
1473 if (Scope == DICS_FLAG_GLOBAL)
1474 RootKey = set->HKLM;
1475 else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
1476 {
1477 hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
1478 if (hHWProfileKey == INVALID_HANDLE_VALUE)
1479 goto cleanup;
1480 RootKey = hHWProfileKey;
1481 }
1482
1483 if (KeyType == DIREG_DEV)
1484 {
1485
1486 rc = RegCreateKeyExW(
1487 RootKey,
1488 REGSTR_PATH_SYSTEMENUM,
1489 0,
1490 NULL,
1491 REG_OPTION_NON_VOLATILE,
1492 KEY_CREATE_SUB_KEY,
1493 NULL,
1494 &hEnumKey,
1495 NULL);
1496 if (rc != ERROR_SUCCESS)
1497 {
1498 SetLastError(rc);
1499 goto cleanup;
1500 }
1501 rc = RegCreateKeyExW(
1502 hEnumKey,
1503 deviceInfo->instanceId,
1504 0,
1505 NULL,
1506 REG_OPTION_NON_VOLATILE,
1507 #if _WIN32_WINNT >= 0x502
1508 KEY_READ | KEY_WRITE,
1509 #else
1510 KEY_ALL_ACCESS,
1511 #endif
1512 NULL,
1513 &hKey,
1514 NULL);
1515 if (rc != ERROR_SUCCESS)
1516 {
1517 SetLastError(rc);
1518 goto cleanup;
1519 }
1520
1521 if (Scope == DICS_FLAG_GLOBAL)
1522 {
1523 HKEY hTempKey = hKey;
1524
1525 rc = RegCreateKeyExW(hTempKey,
1526 L"Device Parameters",
1527 0,
1528 NULL,
1529 REG_OPTION_NON_VOLATILE,
1530 #if _WIN32_WINNT >= 0x502
1531 KEY_READ | KEY_WRITE,
1532 #else
1533 KEY_ALL_ACCESS,
1534 #endif
1535 NULL,
1536 &hKey,
1537 NULL);
1538 if (rc == ERROR_SUCCESS)
1539 RegCloseKey(hTempKey);
1540 }
1541 }
1542 else /* KeyType == DIREG_DRV */
1543 {
1544 /* Open device key, to read Driver value */
1545 hDeviceKey = SETUPDI_OpenDevKey(RootKey, deviceInfo, KEY_QUERY_VALUE | KEY_SET_VALUE);
1546 if (hDeviceKey == INVALID_HANDLE_VALUE)
1547 goto cleanup;
1548
1549 rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
1550 if (rc != ERROR_SUCCESS)
1551 {
1552 SetLastError(rc);
1553 goto cleanup;
1554 }
1555
1556 rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
1557 if (rc != ERROR_SUCCESS)
1558 {
1559 /* Create a new driver key */
1560
1561 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
1562 goto cleanup;
1563
1564 /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
1565 DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1566 if (!DriverKey)
1567 {
1568 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1569 goto cleanup;
1570 }
1571
1572 DriverKey[0] = '{';
1573 strcpyW(&DriverKey[1], lpGuidString);
1574 pDeviceInstance = &DriverKey[strlenW(DriverKey)];
1575 *pDeviceInstance++ = '}';
1576 *pDeviceInstance++ = '\\';
1577
1578 /* Try all values for Index between 0 and 9999 */
1579 Index = 0;
1580 while (Index <= 9999)
1581 {
1582 sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
1583 rc = RegCreateKeyExW(hClassKey,
1584 DriverKey,
1585 0,
1586 NULL,
1587 REG_OPTION_NON_VOLATILE,
1588 #if _WIN32_WINNT >= 0x502
1589 KEY_READ | KEY_WRITE,
1590 #else
1591 KEY_ALL_ACCESS,
1592 #endif
1593 NULL,
1594 &hKey,
1595 &Disposition);
1596 if (rc != ERROR_SUCCESS)
1597 {
1598 SetLastError(rc);
1599 goto cleanup;
1600 }
1601 if (Disposition == REG_CREATED_NEW_KEY)
1602 break;
1603 RegCloseKey(hKey);
1604 hKey = NULL;
1605 Index++;
1606 }
1607
1608 if (Index > 9999)
1609 {
1610 /* Unable to create more than 9999 devices within the same class */
1611 SetLastError(ERROR_GEN_FAILURE);
1612 goto cleanup;
1613 }
1614
1615 /* Write the new Driver value */
1616 rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
1617 if (rc != ERROR_SUCCESS)
1618 {
1619 SetLastError(rc);
1620 goto cleanup;
1621 }
1622
1623 }
1624 else
1625 {
1626 /* Open the existing driver key */
1627
1628 DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
1629 if (!DriverKey)
1630 {
1631 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1632 goto cleanup;
1633 }
1634
1635 rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
1636 if (rc != ERROR_SUCCESS)
1637 {
1638 SetLastError(rc);
1639 goto cleanup;
1640 }
1641
1642 rc = RegCreateKeyExW(hClassKey,
1643 DriverKey,
1644 0,
1645 NULL,
1646 REG_OPTION_NON_VOLATILE,
1647 #if _WIN32_WINNT >= 0x502
1648 KEY_READ | KEY_WRITE,
1649 #else
1650 KEY_ALL_ACCESS,
1651 #endif
1652 NULL,
1653 &hKey,
1654 &Disposition);
1655 if (rc != ERROR_SUCCESS)
1656 {
1657 SetLastError(rc);
1658 goto cleanup;
1659 }
1660 }
1661 }
1662
1663 /* Do installation of the specified section */
1664 if (InfHandle)
1665 {
1666 FIXME("Need to install section %s in file %p\n",
1667 debugstr_w(InfSectionName), InfHandle);
1668 }
1669 key = hKey;
1670
1671 cleanup:
1672 if (lpGuidString)
1673 RpcStringFreeW(&lpGuidString);
1674 HeapFree(GetProcessHeap(), 0, DriverKey);
1675 if (hHWProfileKey != INVALID_HANDLE_VALUE)
1676 RegCloseKey(hHWProfileKey);
1677 if (hEnumKey != NULL)
1678 RegCloseKey(hEnumKey);
1679 if (hClassKey != NULL)
1680 RegCloseKey(hClassKey);
1681 if (hDeviceKey != INVALID_HANDLE_VALUE)
1682 RegCloseKey(hDeviceKey);
1683 if (hKey != NULL && hKey != key)
1684 RegCloseKey(hKey);
1685
1686 TRACE("Returning 0x%p\n", key);
1687 return key;
1688 }
1689
1690 /***********************************************************************
1691 * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1692 */
1693 BOOL WINAPI SetupDiCreateDeviceInfoA(
1694 HDEVINFO DeviceInfoSet,
1695 PCSTR DeviceName,
1696 CONST GUID *ClassGuid,
1697 PCSTR DeviceDescription,
1698 HWND hwndParent,
1699 DWORD CreationFlags,
1700 PSP_DEVINFO_DATA DeviceInfoData)
1701 {
1702 BOOL ret;
1703 LPWSTR DeviceNameW = NULL;
1704 LPWSTR DeviceDescriptionW = NULL;
1705
1706 TRACE("\n");
1707
1708 if (DeviceName)
1709 {
1710 DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
1711 if (DeviceNameW == NULL) return FALSE;
1712 }
1713 if (DeviceDescription)
1714 {
1715 DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
1716 if (DeviceDescriptionW == NULL)
1717 {
1718 MyFree(DeviceNameW);
1719 return FALSE;
1720 }
1721 }
1722
1723 ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1724 hwndParent, CreationFlags, DeviceInfoData);
1725
1726 MyFree(DeviceNameW);
1727 MyFree(DeviceDescriptionW);
1728
1729 return ret;
1730 }
1731
1732 /***********************************************************************
1733 * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1734 */
1735 BOOL WINAPI SetupDiCreateDeviceInfoW(
1736 HDEVINFO DeviceInfoSet,
1737 PCWSTR DeviceName,
1738 CONST GUID *ClassGuid,
1739 PCWSTR DeviceDescription,
1740 HWND hwndParent,
1741 DWORD CreationFlags,
1742 PSP_DEVINFO_DATA DeviceInfoData)
1743 {
1744 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1745 struct DeviceInfo *deviceInfo = NULL;
1746 BOOL ret = FALSE;
1747 CONFIGRET cr;
1748 DEVINST RootDevInst;
1749 DEVINST DevInst;
1750 WCHAR GenInstanceId[MAX_DEVICE_ID_LEN];
1751
1752 TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
1753 debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1754 hwndParent, CreationFlags, DeviceInfoData);
1755
1756 if (!DeviceName)
1757 {
1758 SetLastError(ERROR_INVALID_DEVINST_NAME);
1759 return FALSE;
1760 }
1761 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1762 {
1763 SetLastError(ERROR_INVALID_HANDLE);
1764 return FALSE;
1765 }
1766 if (!ClassGuid)
1767 {
1768 SetLastError(ERROR_INVALID_PARAMETER);
1769 return FALSE;
1770 }
1771 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1772 {
1773 SetLastError(ERROR_INVALID_HANDLE);
1774 return FALSE;
1775 }
1776 if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1777 !IsEqualGUID(ClassGuid, &set->ClassGuid))
1778 {
1779 SetLastError(ERROR_CLASS_MISMATCH);
1780 return FALSE;
1781 }
1782 if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
1783 {
1784 TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
1785 SetLastError(ERROR_INVALID_FLAGS);
1786 return FALSE;
1787 }
1788
1789 /* Get the root device instance */
1790 cr = CM_Locate_DevInst_ExW(&RootDevInst,
1791 NULL,
1792 CM_LOCATE_DEVINST_NORMAL,
1793 set->hMachine);
1794 if (cr != CR_SUCCESS)
1795 {
1796 SetLastError(ERROR_INVALID_DATA);
1797 return FALSE;
1798 }
1799
1800 /* Create the new device instance */
1801 cr = CM_Create_DevInst_ExW(&DevInst,
1802 (DEVINSTID)DeviceName,
1803 RootDevInst,
1804 (CreationFlags & DICD_GENERATE_ID) ?
1805 CM_CREATE_DEVINST_GENERATE_ID : 0,
1806 set->hMachine);
1807 if (cr != CR_SUCCESS)
1808 {
1809 SetLastError(GetErrorCodeFromCrCode(cr));
1810 return FALSE;
1811 }
1812
1813 if (CreationFlags & DICD_GENERATE_ID)
1814 {
1815 /* Grab the actual instance ID that was created */
1816 cr = CM_Get_Device_ID_Ex(DevInst,
1817 GenInstanceId,
1818 MAX_DEVICE_ID_LEN,
1819 0,
1820 set->hMachine);
1821 if (cr != CR_SUCCESS)
1822 {
1823 SetLastError(GetErrorCodeFromCrCode(cr));
1824 return FALSE;
1825 }
1826
1827 DeviceName = GenInstanceId;
1828 TRACE("Using generated instance ID: %s\n", debugstr_w(DeviceName));
1829 }
1830
1831 if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
1832 {
1833 InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
1834
1835 if (!DeviceInfoData)
1836 ret = TRUE;
1837 else
1838 {
1839 if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1840 {
1841 SetLastError(ERROR_INVALID_USER_BUFFER);
1842 }
1843 else
1844 {
1845 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
1846 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
1847 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
1848 ret = TRUE;
1849 }
1850 }
1851 }
1852
1853 if (ret == FALSE)
1854 {
1855 if (deviceInfo != NULL)
1856 {
1857 /* Remove deviceInfo from List */
1858 RemoveEntryList(&deviceInfo->ListEntry);
1859
1860 /* Destroy deviceInfo */
1861 DestroyDeviceInfo(deviceInfo);
1862 }
1863 }
1864
1865 TRACE("Returning %d\n", ret);
1866 return ret;
1867 }
1868
1869 /***********************************************************************
1870 * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1871 */
1872 BOOL WINAPI SetupDiRegisterDeviceInfo(
1873 HDEVINFO DeviceInfoSet,
1874 PSP_DEVINFO_DATA DeviceInfoData,
1875 DWORD Flags,
1876 PSP_DETSIG_CMPPROC CompareProc,
1877 PVOID CompareContext,
1878 PSP_DEVINFO_DATA DupDeviceInfoData)
1879 {
1880 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1881 WCHAR DevInstId[MAX_DEVICE_ID_LEN];
1882 DEVINST ParentDevInst;
1883 CONFIGRET cr;
1884 DWORD dwError = ERROR_SUCCESS;
1885
1886 TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
1887 CompareProc, CompareContext, DupDeviceInfoData);
1888
1889 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1890 {
1891 SetLastError(ERROR_INVALID_HANDLE);
1892 return FALSE;
1893 }
1894 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1895 {
1896 SetLastError(ERROR_INVALID_HANDLE);
1897 return FALSE;
1898 }
1899 if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1900 || !DeviceInfoData->Reserved)
1901 {
1902 SetLastError(ERROR_INVALID_PARAMETER);
1903 return FALSE;
1904 }
1905
1906 if (Flags & ~SPRDI_FIND_DUPS)
1907 {
1908 TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
1909 SetLastError(ERROR_INVALID_FLAGS);
1910 return FALSE;
1911 }
1912
1913 if (Flags & SPRDI_FIND_DUPS)
1914 {
1915 FIXME("Unimplemented codepath!\n");
1916 }
1917
1918 CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
1919 DevInstId,
1920 MAX_DEVICE_ID_LEN,
1921 0,
1922 set->hMachine);
1923
1924 CM_Get_Parent_Ex(&ParentDevInst,
1925 DeviceInfoData->DevInst,
1926 0,
1927 set->hMachine);
1928
1929 cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
1930 DevInstId,
1931 ParentDevInst,
1932 CM_CREATE_DEVINST_NORMAL | CM_CREATE_DEVINST_DO_NOT_INSTALL,
1933 set->hMachine);
1934 if (cr != CR_SUCCESS &&
1935 cr != CR_ALREADY_SUCH_DEVINST)
1936 {
1937 dwError = ERROR_NO_SUCH_DEVINST;
1938 }
1939
1940 SetLastError(dwError);
1941
1942 return (dwError == ERROR_SUCCESS);
1943 }
1944
1945 /***********************************************************************
1946 * SetupDiEnumDeviceInfo (SETUPAPI.@)
1947 */
1948 BOOL WINAPI SetupDiEnumDeviceInfo(
1949 HDEVINFO devinfo,
1950 DWORD index,
1951 PSP_DEVINFO_DATA info)
1952 {
1953 BOOL ret = FALSE;
1954
1955 TRACE("%p %d %p\n", devinfo, index, info);
1956
1957 if(info==NULL)
1958 {
1959 SetLastError(ERROR_INVALID_PARAMETER);
1960 return FALSE;
1961 }
1962 if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1963 {
1964 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1965 if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1966 {
1967 if (info->cbSize != sizeof(SP_DEVINFO_DATA))
1968 SetLastError(ERROR_INVALID_USER_BUFFER);
1969 else
1970 {
1971 PLIST_ENTRY ItemList = list->ListHead.Flink;
1972 while (ItemList != &list->ListHead && index-- > 0)
1973 ItemList = ItemList->Flink;
1974 if (ItemList == &list->ListHead)
1975 SetLastError(ERROR_NO_MORE_ITEMS);
1976 else
1977 {
1978 struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
1979 memcpy(&info->ClassGuid,
1980 &DevInfo->ClassGuid,
1981 sizeof(GUID));
1982 info->DevInst = DevInfo->dnDevInst;
1983 info->Reserved = (ULONG_PTR)DevInfo;
1984 ret = TRUE;
1985 }
1986 }
1987 }
1988 else
1989 SetLastError(ERROR_INVALID_HANDLE);
1990 }
1991 else
1992 SetLastError(ERROR_INVALID_HANDLE);
1993 return ret;
1994 }
1995
1996 /***********************************************************************
1997 * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1998 */
1999 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
2000 HDEVINFO DeviceInfoSet,
2001 PSP_DEVINFO_DATA DeviceInfoData,
2002 PSTR DeviceInstanceId,
2003 DWORD DeviceInstanceIdSize,
2004 PDWORD RequiredSize)
2005 {
2006 BOOL ret = FALSE;
2007 DWORD size;
2008 PWSTR instanceId;
2009
2010 TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
2011 DeviceInstanceIdSize, RequiredSize);
2012
2013 if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
2014 {
2015 SetLastError(ERROR_INVALID_PARAMETER);
2016 return FALSE;
2017 }
2018
2019 ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
2020 DeviceInfoData,
2021 NULL,
2022 0,
2023 &size);
2024 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2025 return FALSE;
2026 instanceId = MyMalloc(size * sizeof(WCHAR));
2027 if (instanceId)
2028 {
2029 ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
2030 DeviceInfoData,
2031 instanceId,
2032 size,
2033 &size);
2034 if (ret)
2035 {
2036 int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
2037 DeviceInstanceId,
2038 DeviceInstanceIdSize, NULL, NULL);
2039
2040 if (!len)
2041 ret = FALSE;
2042 else
2043 {
2044 if (len > DeviceInstanceIdSize)
2045 {
2046 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2047 ret = FALSE;
2048 }
2049 if (RequiredSize)
2050 *RequiredSize = len;
2051 }
2052 }
2053 MyFree(instanceId);
2054 }
2055 else
2056 {
2057 if (RequiredSize)
2058 *RequiredSize = size;
2059 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2060 ret = FALSE;
2061 }
2062 return ret;
2063 }
2064
2065 /***********************************************************************
2066 * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
2067 */
2068 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
2069 HDEVINFO DeviceInfoSet,
2070 PSP_DEVINFO_DATA DeviceInfoData,
2071 PWSTR DeviceInstanceId,
2072 DWORD DeviceInstanceIdSize,
2073 PDWORD RequiredSize)
2074 {
2075 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2076 struct DeviceInfo *devInfo;
2077
2078 TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
2079 DeviceInstanceIdSize, RequiredSize);
2080
2081 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2082 {
2083 SetLastError(ERROR_INVALID_HANDLE);
2084 return FALSE;
2085 }
2086 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2087 {
2088 SetLastError(ERROR_INVALID_HANDLE);
2089 return FALSE;
2090 }
2091 if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2092 || !DeviceInfoData->Reserved)
2093 {
2094 SetLastError(ERROR_INVALID_PARAMETER);
2095 return FALSE;
2096 }
2097 devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2098 if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
2099 {
2100 SetLastError(ERROR_INVALID_PARAMETER);
2101 return FALSE;
2102 }
2103 if (DeviceInstanceId && DeviceInstanceIdSize == 0)
2104 {
2105 SetLastError(ERROR_INVALID_PARAMETER);
2106 return FALSE;
2107 }
2108 TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
2109 if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
2110 {
2111 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2112 if (RequiredSize)
2113 *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
2114 return FALSE;
2115 }
2116 lstrcpyW(DeviceInstanceId, devInfo->instanceId);
2117 if (RequiredSize)
2118 *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
2119 return TRUE;
2120 }
2121
2122 /***********************************************************************
2123 * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
2124 */
2125 BOOL WINAPI SetupDiGetActualSectionToInstallA(
2126 HINF InfHandle,
2127 PCSTR InfSectionName,
2128 PSTR InfSectionWithExt,
2129 DWORD InfSectionWithExtSize,
2130 PDWORD RequiredSize,
2131 PSTR *Extension)
2132 {
2133 return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
2134 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
2135 Extension, NULL);
2136 }
2137
2138 /***********************************************************************
2139 * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2140 */
2141 BOOL WINAPI SetupDiGetActualSectionToInstallW(
2142 HINF InfHandle,
2143 PCWSTR InfSectionName,
2144 PWSTR InfSectionWithExt,
2145 DWORD InfSectionWithExtSize,
2146 PDWORD RequiredSize,
2147 PWSTR *Extension)
2148 {
2149 return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
2150 NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
2151 Extension, NULL);
2152 }
2153
2154 /***********************************************************************
2155 * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
2156 */
2157 BOOL WINAPI
2158 SetupDiGetActualSectionToInstallExA(
2159 IN HINF InfHandle,
2160 IN PCSTR InfSectionName,
2161 IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
2162 OUT PSTR InfSectionWithExt OPTIONAL,
2163 IN DWORD InfSectionWithExtSize,
2164 OUT PDWORD RequiredSize OPTIONAL,
2165 OUT PSTR* Extension OPTIONAL,
2166 IN PVOID Reserved)
2167 {
2168 LPWSTR InfSectionNameW = NULL;
2169 LPWSTR InfSectionWithExtW = NULL;
2170 PWSTR ExtensionW;
2171 BOOL bResult = FALSE;
2172
2173 TRACE("\n");
2174
2175 if (InfSectionName)
2176 {
2177 InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2178 if (InfSectionNameW == NULL)
2179 goto cleanup;
2180 }
2181 if (InfSectionWithExt)
2182 {
2183 InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
2184 if (InfSectionWithExtW == NULL)
2185 goto cleanup;
2186 }
2187
2188 bResult = SetupDiGetActualSectionToInstallExW(
2189 InfHandle, InfSectionNameW, AlternatePlatformInfo,
2190 InfSectionWithExt ? InfSectionWithExtW : NULL,
2191 InfSectionWithExtSize,
2192 RequiredSize,
2193 Extension ? &ExtensionW : NULL,
2194 Reserved);
2195
2196 if (bResult && InfSectionWithExt)
2197 {
2198 bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
2199 InfSectionWithExtSize, NULL, NULL) != 0;
2200 }
2201 if (bResult && Extension)
2202 {
2203 if (ExtensionW == NULL)
2204 *Extension = NULL;
2205 else
2206 *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
2207 }
2208
2209 cleanup:
2210 MyFree(InfSectionNameW);
2211 MyFree(InfSectionWithExtW);
2212
2213 return bResult;
2214 }
2215
2216 /***********************************************************************
2217 * SetupDiGetClassDescriptionA (SETUPAPI.@)
2218 */
2219 BOOL WINAPI SetupDiGetClassDescriptionA(
2220 const GUID* ClassGuid,
2221 PSTR ClassDescription,
2222 DWORD ClassDescriptionSize,
2223 PDWORD RequiredSize)
2224 {
2225 return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2226 ClassDescriptionSize,
2227 RequiredSize, NULL, NULL);
2228 }
2229
2230 /***********************************************************************
2231 * SetupDiGetClassDescriptionW (SETUPAPI.@)
2232 */
2233 BOOL WINAPI SetupDiGetClassDescriptionW(
2234 const GUID* ClassGuid,
2235 PWSTR ClassDescription,
2236 DWORD ClassDescriptionSize,
2237 PDWORD RequiredSize)
2238 {
2239 return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2240 ClassDescriptionSize,
2241 RequiredSize, NULL, NULL);
2242 }
2243
2244 /***********************************************************************
2245 * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2246 */
2247 BOOL WINAPI SetupDiGetClassDescriptionExA(
2248 const GUID* ClassGuid,
2249 PSTR ClassDescription,
2250 DWORD ClassDescriptionSize,
2251 PDWORD RequiredSize,
2252 PCSTR MachineName,
2253 PVOID Reserved)
2254 {
2255 PWCHAR ClassDescriptionW = NULL;
2256 LPWSTR MachineNameW = NULL;
2257 BOOL ret = FALSE;
2258
2259 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
2260 ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
2261
2262 if (ClassDescriptionSize > 0)
2263 {
2264 ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
2265 if (!ClassDescriptionW)
2266 {
2267 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2268 goto cleanup;
2269 }
2270 }
2271
2272 if (MachineName)
2273 {
2274 MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
2275 if (!MachineNameW)
2276 {
2277 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2278 goto cleanup;
2279 }
2280 }
2281
2282 ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
2283 ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
2284 if (ret)
2285 {
2286 DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
2287 ClassDescriptionSize, NULL, NULL);
2288 if (len == 0 || len > ClassDescriptionSize)
2289 {
2290 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2291 ret = FALSE;
2292 }
2293 }
2294
2295 cleanup:
2296 MyFree(ClassDescriptionW);
2297 MyFree(MachineNameW);
2298 return ret;
2299 }
2300
2301 /***********************************************************************
2302 * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2303 */
2304 BOOL WINAPI SetupDiGetClassDescriptionExW(
2305 const GUID* ClassGuid,
2306 PWSTR ClassDescription,
2307 DWORD ClassDescriptionSize,
2308 PDWORD RequiredSize,
2309 PCWSTR MachineName,
2310 PVOID Reserved)
2311 {
2312 HKEY hKey;
2313 DWORD dwLength;
2314 DWORD dwRegType;
2315 LONG rc;
2316 PWSTR Buffer;
2317
2318 TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
2319 ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
2320
2321 /* Make sure there's a GUID */
2322 if (!ClassGuid)
2323 {
2324 SetLastError(ERROR_INVALID_PARAMETER);
2325 return FALSE;
2326 }
2327
2328 /* Make sure there's a real buffer when there's a size */
2329 if (!ClassDescription && ClassDescriptionSize > 0)
2330 {
2331 SetLastError(ERROR_INVALID_PARAMETER);
2332 return FALSE;
2333 }
2334
2335 /* Open the key for the GUID */
2336 hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2337 KEY_QUERY_VALUE,
2338 DIOCR_INSTALLER,
2339 MachineName,
2340 Reserved);
2341 if (hKey == INVALID_HANDLE_VALUE)
2342 return FALSE;
2343
2344 /* Retrieve the class description data and close the key */
2345 rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
2346 RegCloseKey(hKey);
2347
2348 /* Make sure we got the data */
2349 if (rc != ERROR_SUCCESS)
2350 {
2351 SetLastError(rc);
2352 return FALSE;
2353 }
2354
2355 /* Make sure the data is a string */
2356 if (dwRegType != REG_SZ)
2357 {
2358 MyFree(Buffer);
2359 SetLastError(ERROR_GEN_FAILURE);
2360 return FALSE;
2361 }
2362
2363 /* Determine the length of the class description */
2364 dwLength /= sizeof(WCHAR);
2365
2366 /* Count the null-terminator if none is present */
2367 if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
2368 dwLength++;
2369
2370 /* Inform the caller about the class description */
2371 if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
2372 {
2373 memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
2374 ClassDescription[dwLength - 1] = UNICODE_NULL;
2375 }
2376
2377 /* Inform the caller about the required size */
2378 if (RequiredSize != NULL)
2379 *RequiredSize = dwLength;
2380
2381 /* Clean up the buffer */
2382 MyFree(Buffer);
2383
2384 /* Make sure the buffer was large enough */
2385 if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
2386 {
2387 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2388 return FALSE;
2389 }
2390
2391 return TRUE;
2392 }
2393
2394 /***********************************************************************
2395 * SetupDiGetClassDevsA (SETUPAPI.@)
2396 */
2397 HDEVINFO WINAPI SetupDiGetClassDevsA(
2398 CONST GUID *class,
2399 LPCSTR enumstr,
2400 HWND parent,
2401 DWORD flags)
2402 {
2403 return SetupDiGetClassDevsExA(class, enumstr, parent,
2404 flags, NULL, NULL, NULL);
2405 }
2406
2407 /***********************************************************************
2408 * SetupDiGetClassDevsExA (SETUPAPI.@)
2409 */
2410 HDEVINFO WINAPI SetupDiGetClassDevsExA(
2411 const GUID *class,
2412 PCSTR enumstr,
2413 HWND parent,
2414 DWORD flags,
2415 HDEVINFO deviceset,
2416 PCSTR machine,
2417 PVOID reserved)
2418 {
2419 HDEVINFO ret;
2420 LPWSTR enumstrW = NULL, machineW = NULL;
2421
2422 if (enumstr)
2423 {
2424 enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
2425 if (!enumstrW)
2426 {
2427 ret = INVALID_HANDLE_VALUE;
2428 goto end;
2429 }
2430 }
2431 if (machine)
2432 {
2433 machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
2434 if (!machineW)
2435 {
2436 MyFree(enumstrW);
2437 ret = INVALID_HANDLE_VALUE;
2438 goto end;
2439 }
2440 }
2441 ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2442 machineW, reserved);
2443 MyFree(enumstrW);
2444 MyFree(machineW);
2445
2446 end:
2447 return ret;
2448 }
2449
2450 /***********************************************************************
2451 * SetupDiGetClassDevsW (SETUPAPI.@)
2452 */
2453 HDEVINFO WINAPI SetupDiGetClassDevsW(
2454 CONST GUID *class,
2455 LPCWSTR enumstr,
2456 HWND parent,
2457 DWORD flags)
2458 {
2459 return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2460 NULL);
2461 }
2462
2463 /***********************************************************************
2464 * SetupDiGetClassDevsExW (SETUPAPI.@)
2465 */
2466 HDEVINFO WINAPI SetupDiGetClassDevsExW(
2467 CONST GUID *class,
2468 PCWSTR enumstr,
2469 HWND parent,
2470 DWORD flags,
2471 HDEVINFO deviceset,
2472 PCWSTR machine,
2473 PVOID reserved)
2474 {
2475 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2476 struct DeviceInfoSet *list;
2477 CONST GUID *pClassGuid;
2478 LONG rc;
2479 HDEVINFO set = INVALID_HANDLE_VALUE;
2480
2481 TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2482 debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2483 reserved);
2484
2485 if (!(flags & DIGCF_ALLCLASSES) && !class)
2486 {
2487 SetLastError(ERROR_INVALID_PARAMETER);
2488 return INVALID_HANDLE_VALUE;
2489 }
2490
2491 /* Create the deviceset if not set */
2492 if (deviceset)
2493 {
2494 list = (struct DeviceInfoSet *)deviceset;
2495 if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2496 {
2497 SetLastError(ERROR_INVALID_HANDLE);
2498 goto cleanup;
2499 }
2500 hDeviceInfo = deviceset;
2501 }
2502 else
2503 {
2504 hDeviceInfo = SetupDiCreateDeviceInfoListExW(
2505 flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
2506 NULL, machine, NULL);
2507 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2508 goto cleanup;
2509 list = (struct DeviceInfoSet *)hDeviceInfo;
2510 }
2511
2512 if (flags & DIGCF_PROFILE)
2513 FIXME(": flag DIGCF_PROFILE ignored\n");
2514
2515 if (flags & DIGCF_DEVICEINTERFACE)
2516 {
2517 if (!class)
2518 {
2519 SetLastError(ERROR_INVALID_PARAMETER);
2520 goto cleanup;
2521 }
2522 rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
2523 }
2524 else
2525 {
2526 /* Determine which class(es) should be included in the deviceset */
2527 if (flags & DIGCF_ALLCLASSES)
2528 {
2529 /* The caller wants all classes. Check if
2530 * the deviceset limits us to one class */
2531 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2532 pClassGuid = NULL;
2533 else
2534 pClassGuid = &list->ClassGuid;
2535 }
2536 else if (class)
2537 {
2538 /* The caller wants one class. Check if it matches deviceset class */
2539 if (IsEqualIID(&list->ClassGuid, class)
2540 || IsEqualIID(&list->ClassGuid, &GUID_NULL))
2541 {
2542 pClassGuid = class;
2543 }
2544 else
2545 {
2546 SetLastError(ERROR_INVALID_PARAMETER);
2547 goto cleanup;
2548 }
2549 }
2550 else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
2551 {
2552 /* No class specified. Try to use the one of the deviceset */
2553 if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2554 pClassGuid = &list->ClassGuid;
2555 else
2556 {
2557 SetLastError(ERROR_INVALID_PARAMETER);
2558 goto cleanup;
2559 }
2560 }
2561 else
2562 {
2563 SetLastError(ERROR_INVALID_PARAMETER);
2564 goto cleanup;
2565 }
2566 rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
2567 }
2568 if (rc != ERROR_SUCCESS)
2569 {
2570 SetLastError(rc);
2571 goto cleanup;
2572 }
2573 set = hDeviceInfo;
2574
2575 cleanup:
2576 if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
2577 SetupDiDestroyDeviceInfoList(hDeviceInfo);
2578 return set;
2579 }
2580
2581 /***********************************************************************
2582 * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2583 */
2584 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
2585 HDEVINFO DeviceInfoSet,
2586 PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2587 {
2588 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2589
2590 TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2591
2592 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2593 {
2594 SetLastError(ERROR_INVALID_HANDLE);
2595 return FALSE;
2596 }
2597 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2598 {
2599 SetLastError(ERROR_INVALID_HANDLE);
2600 return FALSE;
2601 }
2602 if (!DevInfoData ||
2603 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2604 {
2605 SetLastError(ERROR_INVALID_PARAMETER);
2606 return FALSE;
2607 }
2608 memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2609 DevInfoData->RemoteMachineHandle = set->hMachine;
2610 if (set->MachineName)
2611 {
2612 FIXME("Stub\n");
2613 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2614 return FALSE;
2615 }
2616 else
2617 DevInfoData->RemoteMachineName[0] = 0;
2618
2619 return TRUE;
2620 }
2621
2622 /***********************************************************************
2623 * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2624 */
2625 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
2626 HDEVINFO DeviceInfoSet,
2627 PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2628 {
2629 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2630
2631 TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2632
2633 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2634 {
2635 SetLastError(ERROR_INVALID_HANDLE);
2636 return FALSE;
2637 }
2638 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2639 {
2640 SetLastError(ERROR_INVALID_HANDLE);
2641 return FALSE;
2642 }
2643 if (!DevInfoData ||
2644 DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2645 {
2646 SetLastError(ERROR_INVALID_PARAMETER);
2647 return FALSE;
2648 }
2649 memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2650 DevInfoData->RemoteMachineHandle = set->hMachine;
2651 if (set->MachineName)
2652 strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
2653 else
2654 DevInfoData->RemoteMachineName[0] = 0;
2655
2656 return TRUE;
2657 }
2658
2659 /***********************************************************************
2660 * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2661 */
2662 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
2663 HDEVINFO DeviceInfoSet,
2664 PSP_DEVINFO_DATA DeviceInfoData,
2665 const GUID *InterfaceClassGuid,
2666 PCSTR ReferenceString,
2667 DWORD CreationFlags,
2668 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2669 {
2670 BOOL ret;
2671 LPWSTR ReferenceStringW = NULL;
2672
2673 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2674 debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2675 CreationFlags, DeviceInterfaceData);
2676
2677 if (ReferenceString)
2678 {
2679 ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
2680 if (ReferenceStringW == NULL) return FALSE;
2681 }
2682
2683 ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2684 InterfaceClassGuid, ReferenceStringW, CreationFlags,
2685 DeviceInterfaceData);
2686
2687 MyFree(ReferenceStringW);
2688
2689 return ret;
2690 }
2691
2692 /***********************************************************************
2693 * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2694 */
2695 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
2696 HDEVINFO DeviceInfoSet,
2697 PSP_DEVINFO_DATA DeviceInfoData,
2698 const GUID *InterfaceClassGuid,
2699 PCWSTR ReferenceString,
2700 DWORD CreationFlags,
2701 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2702 {
2703 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2704 TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2705 debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2706 CreationFlags, DeviceInterfaceData);
2707
2708 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2709 {
2710 SetLastError(ERROR_INVALID_HANDLE);
2711 return FALSE;
2712 }
2713 if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2714 {
2715 SetLastError(ERROR_INVALID_HANDLE);
2716 return FALSE;
2717 }
2718 if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2719 || !DeviceInfoData->Reserved)
2720 {
2721 SetLastError(ERROR_INVALID_PARAMETER);
2722 return FALSE;
2723 }
2724 if (!InterfaceClassGuid)
2725 {
2726 SetLastError(ERROR_INVALID_USER_BUFFER);
2727 return FALSE;
2728 }
2729
2730 FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2731 debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2732 CreationFlags, DeviceInterfaceData);
2733 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2734 return FALSE;
2735 }
2736
2737 /***********************************************************************
2738 * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2739 */
2740 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
2741 HDEVINFO DeviceInfoSet,
2742 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2743 DWORD Reserved,
2744 REGSAM samDesired,
2745 HINF InfHandle,
2746 PCSTR InfSectionName)
2747 {
2748 HKEY key;
2749 PWSTR InfSectionNameW = NULL;
2750
2751 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2752 samDesired, InfHandle, InfSectionName);
2753 if (InfHandle)
2754 {
2755 if (!InfSectionName)
2756 {
2757 SetLastError(ERROR_INVALID_PARAMETER);
2758 return INVALID_HANDLE_VALUE;
2759 }
2760 InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2761 if (!InfSectionNameW)
2762 return INVALID_HANDLE_VALUE;
2763 }
2764 key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2765 DeviceInterfaceData, Reserved, samDesired, InfHandle,
2766 InfSectionNameW);
2767 MyFree(InfSectionNameW);
2768 return key;
2769 }
2770
2771 /***********************************************************************
2772 * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2773 */
2774 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
2775 HDEVINFO DeviceInfoSet,
2776 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2777 DWORD Reserved,
2778 REGSAM samDesired,
2779 HINF InfHandle,
2780 PCWSTR InfSectionName)
2781 {
2782 HKEY hKey, hDevKey;
2783 LPWSTR SymbolicLink;
2784 DWORD Length, Index;
2785 LONG rc;
2786 WCHAR bracedGuidString[39];
2787 struct DeviceInterface *DevItf;
2788 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2789
2790 TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2791 samDesired, InfHandle, InfSectionName);
2792
2793 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2794 set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2795 {
2796 SetLastError(ERROR_INVALID_HANDLE);
2797 return INVALID_HANDLE_VALUE;
2798 }
2799 if (!DeviceInterfaceData ||
2800 DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2801 !DeviceInterfaceData->Reserved)
2802 {
2803 SetLastError(ERROR_INVALID_PARAMETER);
2804 return INVALID_HANDLE_VALUE;
2805 }
2806 if (InfHandle && !InfSectionName)
2807 {
2808 SetLastError(ERROR_INVALID_PARAMETER);
2809 return INVALID_HANDLE_VALUE;
2810 }
2811
2812 hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
2813 if (hKey == INVALID_HANDLE_VALUE)
2814 {
2815 hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
2816 if (hKey == INVALID_HANDLE_VALUE)
2817 {
2818 SetLastError(ERROR_INVALID_PARAMETER);
2819 return INVALID_HANDLE_VALUE;
2820 }
2821 SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
2822
2823 if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
2824 {
2825 SetLastError(ERROR_INVALID_PARAMETER);
2826 return INVALID_HANDLE_VALUE;
2827 }
2828 RegCloseKey(hKey);
2829 hKey = hDevKey;
2830 }
2831
2832 DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2833
2834 Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
2835 SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
2836 if (!SymbolicLink)
2837 {
2838 RegCloseKey(hKey);
2839 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2840 return INVALID_HANDLE_VALUE;
2841 }
2842
2843 wcscpy(SymbolicLink, DevItf->SymbolicLink);
2844
2845 Index = 0;
2846 while(SymbolicLink[Index])
2847 {
2848 if (SymbolicLink[Index] == L'\\')
2849 {
2850 SymbolicLink[Index] = L'#';
2851 }
2852 Index++;
2853 }
2854
2855 rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
2856
2857 RegCloseKey(hKey);
2858 HeapFree(GetProcessHeap(), 0, SymbolicLink);
2859
2860 if (rc == ERROR_SUCCESS)
2861 {
2862 if (InfHandle && InfSectionName)
2863 {
2864 if (!SetupInstallFromInfSection(NULL /*FIXME */,
2865 InfHandle,
2866 InfSectionName,
2867 SPINST_INIFILES | SPINST_REGISTRY | SPINST_INI2REG | SPINST_FILES | SPINST_BITREG | SPINST_REGSVR | SPINST_UNREGSVR | SPINST_PROFILEITEMS | SPINST_COPYINF,
2868 hDevKey,
2869 NULL,
2870 0,
2871 set->SelectedDevice->InstallParams.InstallMsgHandler,
2872 set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
2873 INVALID_HANDLE_VALUE,
2874 NULL))
2875 {
2876 RegCloseKey(hDevKey);
2877 return INVALID_HANDLE_VALUE;
2878 }
2879 }
2880 }
2881
2882 SetLastError(rc);
2883 return hDevKey;
2884 }
2885
2886 /***********************************************************************
2887 * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2888 */
2889 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
2890 HDEVINFO DeviceInfoSet,
2891 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2892 DWORD Reserved)
2893 {
2894 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2895 BOOL ret = FALSE;
2896
2897 TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2898
2899 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2900 set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2901 {
2902 SetLastError(ERROR_INVALID_HANDLE);
2903 return FALSE;
2904 }
2905 if (!DeviceInterfaceData ||
2906 DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2907 !DeviceInterfaceData->Reserved)
2908 {
2909 SetLastError(ERROR_INVALID_PARAMETER);
2910 return FALSE;
2911 }
2912
2913 FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2915 return ret;
2916 }
2917
2918 /***********************************************************************
2919 * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2920 *
2921 * PARAMS
2922 * DeviceInfoSet [I] Set of devices from which to enumerate
2923 * interfaces
2924 * DeviceInfoData [I] (Optional) If specified, a specific device
2925 * instance from which to enumerate interfaces.
2926 * If it isn't specified, all interfaces for all
2927 * devices in the set are enumerated.
2928 * InterfaceClassGuid [I] The interface class to enumerate.
2929 * MemberIndex [I] An index of the interface instance to enumerate.
2930 * A caller should start with MemberIndex set to 0,
2931 * and continue until the function fails with
2932 * ERROR_NO_MORE_ITEMS.
2933 * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2934 * member must be set to
2935 * sizeof(SP_DEVICE_INTERFACE_DATA).
2936 *
2937 * RETURNS
2938 * Success: non-zero value.
2939 * Failure: FALSE. Call GetLastError() for more info.
2940 */
2941 BOOL WINAPI SetupDiEnumDeviceInterfaces(
2942 HDEVINFO DeviceInfoSet,
2943 PSP_DEVINFO_DATA DeviceInfoData,
2944 CONST GUID * InterfaceClassGuid,
2945 DWORD MemberIndex,
2946 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2947 {
2948 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2949 BOOL ret = FALSE;
2950
2951 TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
2952 debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2953
2954 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2955 set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2956 {
2957 SetLastError(ERROR_INVALID_HANDLE);
2958 return FALSE;
2959 }
2960 if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2961 !DeviceInfoData->Reserved))
2962 {
2963 SetLastError(ERROR_INVALID_PARAMETER);
2964 return FALSE;
2965 }
2966 if (!DeviceInterfaceData ||
2967 DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2968 {
2969 SetLastError(ERROR_INVALID_PARAMETER);
2970 return FALSE;
2971 }
2972 if (DeviceInfoData)
2973 {
2974 struct DeviceInfo *devInfo =
2975 (struct DeviceInfo *)DeviceInfoData->Reserved;
2976 BOOL found = FALSE;
2977 PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2978 while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2979 {
2980 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2981 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2982 {
2983 InterfaceListEntry = InterfaceListEntry->Flink;
2984 continue;
2985 }
2986 if (MemberIndex-- == 0)
2987 {
2988 /* return this item */
2989 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2990 &DevItf->InterfaceClassGuid,
2991 sizeof(GUID));
2992 DeviceInterfaceData->Flags = DevItf->Flags;
2993 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2994 found = TRUE;
2995 ret = TRUE;
2996 }
2997 InterfaceListEntry = InterfaceListEntry->Flink;
2998 }
2999 if (!found)
3000 SetLastError(ERROR_NO_MORE_ITEMS);
3001 }
3002 else
3003 {
3004 BOOL found = FALSE;
3005 PLIST_ENTRY ItemList = set->ListHead.Flink;
3006 while (ItemList != &set->ListHead && !found)
3007 {
3008 PLIST_ENTRY InterfaceListEntry;
3009 struct DeviceInfo *devInfo =
3010 CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3011 InterfaceListEntry = devInfo->InterfaceListHead.Flink;
3012 while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
3013 {
3014 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3015 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
3016 {
3017 InterfaceListEntry = InterfaceListEntry->Flink;
3018 continue;
3019 }
3020 if (MemberIndex-- == 0)
3021 {
3022 /* return this item */
3023 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
3024 &DevItf->InterfaceClassGuid,
3025 sizeof(GUID));
3026 DeviceInterfaceData->Flags = DevItf->Flags;
3027 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
3028 found = TRUE;
3029 ret = TRUE;
3030 }
3031 InterfaceListEntry = InterfaceListEntry->Flink;
3032 }
3033 ItemList = ItemList->Flink;
3034
3035 }
3036 if (!found)
3037 SetLastError(ERROR_NO_MORE_ITEMS);
3038 }
3039 return ret;
3040 }
3041
3042 /***********************************************************************
3043 * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
3044 *
3045 * Destroy a DeviceInfoList and free all used memory of the list.
3046 *
3047 * PARAMS
3048 * devinfo [I] DeviceInfoList pointer to list to destroy
3049 *
3050 * RETURNS
3051 * Success: non zero value.
3052 * Failure: zero value.
3053 */
3054 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
3055 {
3056 BOOL ret = FALSE;
3057
3058 TRACE("%p\n", devinfo);
3059 if (devinfo && devinfo != INVALID_HANDLE_VALUE)
3060 {
3061 struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
3062
3063 if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
3064 {
3065 ret = DestroyDeviceInfoSet(list);
3066 }
3067 }
3068
3069 if (ret == FALSE)
3070 SetLastError(ERROR_INVALID_HANDLE);
3071
3072 return ret;
3073 }
3074
3075 /***********************************************************************
3076 * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
3077 */
3078 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
3079 HDEVINFO DeviceInfoSet,
3080 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3081 PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
3082 DWORD DeviceInterfaceDetailDataSize,
3083 PDWORD RequiredSize,
3084 PSP_DEVINFO_DATA DeviceInfoData)
3085 {
3086 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3087 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
3088 DWORD sizeW = 0, bytesNeeded;
3089 BOOL ret = FALSE;
3090
3091 TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
3092 DeviceInterfaceData, DeviceInterfaceDetailData,
3093 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3094
3095 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3096 set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3097 {
3098 SetLastError(ERROR_INVALID_HANDLE);
3099 return FALSE;
3100 }
3101 if (!DeviceInterfaceData ||
3102 DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3103 !DeviceInterfaceData->Reserved)
3104 {
3105 SetLastError(ERROR_INVALID_PARAMETER);
3106 return FALSE;
3107 }
3108 if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
3109 {
3110 SetLastError(ERROR_INVALID_USER_BUFFER);
3111 return FALSE;
3112 }
3113
3114 if((DeviceInterfaceDetailDataSize != 0) &&
3115 (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
3116 {
3117 SetLastError(ERROR_INVALID_USER_BUFFER);
3118 return FALSE;
3119 }
3120
3121 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3122 {
3123 SetLastError(ERROR_INVALID_USER_BUFFER);
3124 return FALSE;
3125 }
3126
3127
3128 if (DeviceInterfaceDetailData != NULL)
3129 {
3130 sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
3131 + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
3132 DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
3133 if (!DeviceInterfaceDetailDataW)
3134 {
3135 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3136 }
3137 DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
3138 }
3139 if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
3140 {
3141 ret = SetupDiGetDeviceInterfaceDetailW(
3142 DeviceInfoSet,
3143 DeviceInterfaceData,
3144 DeviceInterfaceDetailDataW,
3145 sizeW,
3146 &sizeW,
3147 DeviceInfoData);
3148 bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
3149 + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
3150 if (RequiredSize)
3151 *RequiredSize = bytesNeeded;
3152 if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
3153 {
3154 if (!WideCharToMultiByte(
3155 CP_ACP, 0,
3156 DeviceInterfaceDetailDataW->DevicePath, -1,
3157 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3158 NULL, NULL))
3159 {
3160 ret = FALSE;
3161 }
3162 }
3163 }
3164 MyFree(DeviceInterfaceDetailDataW);
3165
3166 return ret;
3167 }
3168
3169 /***********************************************************************
3170 * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3171 */
3172 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
3173 HDEVINFO DeviceInfoSet,
3174 PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3175 PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
3176 DWORD DeviceInterfaceDetailDataSize,
3177 PDWORD RequiredSize,
3178 PSP_DEVINFO_DATA DeviceInfoData)
3179 {
3180 struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3181 BOOL ret = FALSE;
3182
3183 TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
3184 DeviceInterfaceData, DeviceInterfaceDetailData,
3185 DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3186
3187 if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3188 set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3189 {
3190 SetLastError(ERROR_INVALID_HANDLE);
3191 return FALSE;
3192 }
3193 if (!DeviceInterfaceData ||
3194 DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3195 !DeviceInterfaceData->Reserved)
3196 {
3197 SetLastError(ERROR_INVALID_PARAMETER);
3198 return FALSE;
3199 }
3200 if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
3201 {
3202 SetLastError(ERROR_INVALID_USER_BUFFER);
3203 return FALSE;
3204 }
3205 if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3206 {
3207 SetLastError(ERROR_INVALID_USER_BUFFER);
3208 return FALSE;
3209 }
3210 if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3211 {
3212 SetLastError(ERROR_INVALID_PARAMETER);
3213 return FALSE;
3214 }
3215 if ((DeviceInterfaceDetailData != NULL)
3216 && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
3217 {
3218 SetLastError(ERROR_INVALID_PARAMETER);
3219 return FALSE;
3220 }
3221 else
3222 {
3223 struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
3224 LPCWSTR devName = deviceInterface->SymbolicLink;
3225 DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
3226 (lstrlenW(devName) + 1) * sizeof(WCHAR);
3227
3228 if (sizeRequired > DeviceInterfaceDetailDataSize)
3229 {
3230 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3231 if (RequiredSize)
3232 *RequiredSize = sizeRequired;
3233 }
3234 else
3235 {
3236 strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
3237 TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
3238 if (DeviceInfoData)
3239 {
3240 memcpy(&DeviceInfoData->ClassGuid,
3241 &deviceInterface->DeviceInfo->ClassGuid,
3242 sizeof(GUID));
3243 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
3244 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
3245 }
3246 ret = TRUE;
3247 }
3248 }
3249 return ret;
3250 }
3251
3252 struct PropertyMapEntry
3253 {
3254 DWORD regType;
3255 LPCSTR nameA;
3256 LPCWSTR nameW;
3257 };
3258
3259 static struct PropertyMapEntry PropertyMap[] = {
3260 { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
3261 { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
3262 { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
3263 { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3264 { REG_SZ, "Service", REGSTR_VAL_SERVICE },
3265 { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3266 { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3267 { REG_SZ, "Class", REGSTR_VAL_CLASS },
3268 { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
3269 { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
3270 { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
3271 { REG_SZ, "Mfg", REGSTR_VAL_MFG },
3272 { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
3273 { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
3274 { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3275 { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
3276 { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
3277 { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
3278 { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
3279 { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
3280 { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
3281 { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
3282 { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
3283 { REG_BINARY, "Security", REGSTR_SECURITY },
3284 { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
3285 { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
3286 { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
3287 { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
3288 { 0, NULL, NULL }, /* SPDRP_ADDRESS */
3289 { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },