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