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