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