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