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