ReactOS  0.4.15-dev-5097-g328cc41
devinst.c
Go to the documentation of this file.
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 #include <pseh/pseh2.h>
25 
26 /* Unicode constants */
27 static const WCHAR BackSlash[] = {'\\',0};
28 static const WCHAR DateFormat[] = {'%','u','-','%','u','-','%','u',0};
29 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
30 static const WCHAR DotHW[] = {'.','H','W',0};
31 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
32 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
33 static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
34 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
35 static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
36 
37 static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
38 static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
39 static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
40 static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
41 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[] = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
42 
43 typedef DWORD
45  IN DI_FUNCTION InstallFunction,
48 typedef BOOL
52 typedef DWORD
54  IN DI_FUNCTION InstallFunction,
58 
60 {
62 
67 };
68 
70 {
77 };
78 
79 
80 
82 {
83  static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
84  '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
85  'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
86  '0','2','X','}',0};
87 
88  sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
89  guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
90  guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
91 }
92 
93 DWORD
95 {
96  switch (cr)
97  {
101  case CR_FAILURE: return ERROR_GEN_FAILURE;
115  case CR_SUCCESS: return ERROR_SUCCESS;
116  default: return ERROR_GEN_FAILURE;
117  }
118 
119  /* Does not happen */
120 }
121 
122 /* Lower scores are best ones */
123 static BOOL
125  IN LPCWSTR SectionName,
126  IN PSP_ALTPLATFORM_INFO PlatformInfo,
127  IN BYTE ProductType,
128  IN WORD SuiteMask,
129  OUT PDWORD ScorePlatform,
130  OUT PDWORD ScoreMajorVersion,
131  OUT PDWORD ScoreMinorVersion,
132  OUT PDWORD ScoreProductType,
133  OUT PDWORD ScoreSuiteMask)
134 {
135  LPWSTR Section = NULL;
136  //LPCWSTR pExtensionPlatform;
137  LPCWSTR pExtensionArchitecture;
138  LPWSTR Fields[6];
139  DWORD i;
140  BOOL ret = FALSE;
141 
142  //static const WCHAR ExtensionPlatformNone[] = {'.',0};
143  static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
144  static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
145 
146  static const WCHAR ExtensionArchitectureNone[] = {0};
147  static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
148  static const WCHAR ExtensionArchitectureamd64[] = {'A','M','D','6','4',0};
149  static const WCHAR ExtensionArchitectureia64[] = {'I','A','6','4',0};
150  static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
151  static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
152  static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
153 
154  TRACE("%s(%s %p 0x%x 0x%x)\n",
155  __FUNCTION__, debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
156 
157  *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
158 
159  Section = pSetupDuplicateString(SectionName);
160  if (!Section)
161  {
162  TRACE("pSetupDuplicateString() failed\n");
163  goto cleanup;
164  }
165 
166  /* Set various extensions values */
167  switch (PlatformInfo->Platform)
168  {
170  //pExtensionPlatform = ExtensionPlatformWindows;
171  break;
173  //pExtensionPlatform = ExtensionPlatformNT;
174  break;
175  default:
176  ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
177  //pExtensionPlatform = ExtensionPlatformNone;
178  break;
179  }
180  switch (PlatformInfo->ProcessorArchitecture)
181  {
183  pExtensionArchitecture = ExtensionArchitecturealpha;
184  break;
186  pExtensionArchitecture = ExtensionArchitectureamd64;
187  break;
189  pExtensionArchitecture = ExtensionArchitectureia64;
190  break;
192  pExtensionArchitecture = ExtensionArchitecturex86;
193  break;
195  pExtensionArchitecture = ExtensionArchitecturemips;
196  break;
198  pExtensionArchitecture = ExtensionArchitectureppc;
199  break;
200  default:
201  ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
203  pExtensionArchitecture = ExtensionArchitectureNone;
204  break;
205  }
206 
207  /*
208  * Field[0] Platform
209  * Field[1] Architecture
210  * Field[2] Major version
211  * Field[3] Minor version
212  * Field[4] Product type
213  * Field[5] Suite mask
214  * Remark: these fields may be NULL if the information is not provided
215  */
216  Fields[0] = Section;
217  if (Fields[0] == NULL)
218  {
219  TRACE("No extension found\n");
220  *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
221  ret = TRUE;
222  goto cleanup;
223  }
224  Fields[1] = Fields[0] + 1;
225  Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
226  for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
227  {
228  Fields[i] = wcschr(Fields[i - 1], '.');
229  if (Fields[i])
230  {
231  Fields[i]++;
232  *(Fields[i] - 1) = UNICODE_NULL;
233  }
234  }
235  /* Take care of first 2 fields */
236  if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
237  {
238  if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
239  {
240  TRACE("Mismatch on platform field\n");
241  goto cleanup;
242  }
243  Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
244  }
245  else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
246  {
247  if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
248  {
249  TRACE("Mismatch on platform field\n");
250  goto cleanup;
251  }
252  Fields[1] += wcslen(ExtensionPlatformNT) - 1;
253  }
254  else
255  {
256  /* No platform specified */
257  *ScorePlatform |= 0x02;
258  }
259  if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
260  {
261  /* No architecture specified */
262  *ScorePlatform |= 0x01;
263  }
264  else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
265  {
266  TRACE("Mismatch on architecture field ('%s' and '%s')\n",
267  debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
268  goto cleanup;
269  }
270 
271  /* Check if informations are matching */
272  if (Fields[2] && *Fields[2])
273  {
275  MajorVersion = strtoulW(Fields[2], NULL, 0);
276  if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
277  (errno == ERANGE || errno == EINVAL))
278  {
279  TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
280  goto cleanup;
281  }
282  if (Fields[3] && *Fields[3])
283  {
284  MinorVersion = strtoulW(Fields[3], NULL, 0);
285  if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
286  (errno == ERANGE || errno == EINVAL))
287  {
288  TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
289  goto cleanup;
290  }
291  }
292  if (PlatformInfo->MajorVersion < MajorVersion ||
293  (PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
294  {
295  TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
296  MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
297  goto cleanup;
298  }
299  *ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
300  if (MajorVersion == PlatformInfo->MajorVersion)
301  *ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
302  else
303  *ScoreMinorVersion = MinorVersion;
304  }
305  else if (Fields[3] && *Fields[3])
306  {
307  TRACE("Minor version found without major version\n");
308  goto cleanup;
309  }
310  else
311  {
312  *ScoreMajorVersion = PlatformInfo->MajorVersion;
313  *ScoreMinorVersion = PlatformInfo->MinorVersion;
314  }
315 
316  if (Fields[4] && *Fields[4])
317  {
318  DWORD CurrentProductType;
319  CurrentProductType = strtoulW(Fields[4], NULL, 0);
320  if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
321  (errno == ERANGE || errno == EINVAL))
322  {
323  TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
324  goto cleanup;
325  }
326  if (CurrentProductType != ProductType)
327  {
328  TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
329  CurrentProductType, ProductType);
330  goto cleanup;
331  }
332  }
333  else
334  *ScoreProductType = 1;
335 
336  if (Fields[5] && *Fields[5])
337  {
338  DWORD CurrentSuiteMask;
339  CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
340  if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
341  (errno == ERANGE || errno == EINVAL))
342  {
343  TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
344  goto cleanup;
345  }
346  if ((CurrentSuiteMask & ~SuiteMask) != 0)
347  {
348  TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
349  CurrentSuiteMask, SuiteMask);
350  goto cleanup;
351  }
352  *ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
353  }
354  else
355  *ScoreSuiteMask = SuiteMask;
356 
357  ret = TRUE;
358 
359 cleanup:
360  MyFree(Section);
361  return ret;
362 }
363 
364 static BOOL
366  IN LPCWSTR SectionName,
367  IN PVOID Context)
368 {
370  DWORD Score1, Score2, Score3, Score4, Score5;
371  BOOL ret;
372 
373  if (SectionName[info->PrefixLength] != '.')
374  return TRUE;
375 
377  &SectionName[info->PrefixLength],
378  info->PlatformInfo,
379  info->ProductType,
380  info->SuiteMask,
381  &Score1, &Score2, &Score3, &Score4, &Score5);
382  if (!ret)
383  {
384  TRACE("Section %s not compatible\n", debugstr_w(SectionName));
385  return TRUE;
386  }
387  if (Score1 > info->BestScore1) goto done;
388  if (Score1 < info->BestScore1) goto bettersection;
389  if (Score2 > info->BestScore2) goto done;
390  if (Score2 < info->BestScore2) goto bettersection;
391  if (Score3 > info->BestScore3) goto done;
392  if (Score3 < info->BestScore3) goto bettersection;
393  if (Score4 > info->BestScore4) goto done;
394  if (Score4 < info->BestScore4) goto bettersection;
395  if (Score5 > info->BestScore5) goto done;
396  if (Score5 < info->BestScore5) goto bettersection;
397  goto done;
398 
399 bettersection:
400  strcpyW(info->BestSection, SectionName);
401  info->BestScore1 = Score1;
402  info->BestScore2 = Score2;
403  info->BestScore3 = Score3;
404  info->BestScore4 = Score4;
405  info->BestScore5 = Score5;
406 
407 done:
408  return TRUE;
409 }
410 
411 /***********************************************************************
412  * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
413  */
414 BOOL WINAPI
416  IN HINF InfHandle,
417  IN PCWSTR InfSectionName,
418  IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
419  OUT PWSTR InfSectionWithExt OPTIONAL,
420  IN DWORD InfSectionWithExtSize,
423  IN PVOID Reserved)
424 {
425  BOOL ret = FALSE;
426 
427  TRACE("%s(%p %s %p %p %lu %p %p %p)\n", __FUNCTION__, InfHandle, debugstr_w(InfSectionName),
428  AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
430 
431  if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
433  else if (!InfSectionName)
435  else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
437  else if (Reserved != NULL)
439  else
440  {
441  static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
442  static BYTE CurrentProductType = 0;
443  static WORD CurrentSuiteMask = 0;
444  PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
445  struct GetSectionCallbackInfo CallbackInfo;
446  DWORD dwFullLength;
448  WORD SuiteMask;
449 
450  /* Fill platform info if needed */
451  if (AlternatePlatformInfo)
452  {
453  pPlatformInfo = AlternatePlatformInfo;
454  ProductType = 0;
455  SuiteMask = 0;
456  }
457  else
458  {
459  if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
460  {
461  /* That's the first time we go here. We need to fill in the structure */
462  SYSTEM_INFO SystemInfo;
463  GetSystemInfo(&SystemInfo);
464  CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
465  CurrentPlatform.Platform = OsVersionInfo.dwPlatformId;
466  CurrentPlatform.MajorVersion = OsVersionInfo.dwMajorVersion;
467  CurrentPlatform.MinorVersion = OsVersionInfo.dwMinorVersion;
468  CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
469  CurrentPlatform.Reserved = 0;
470  CurrentProductType = OsVersionInfo.wProductType;
471  CurrentSuiteMask = OsVersionInfo.wSuiteMask;
472  }
473  ProductType = CurrentProductType;
474  SuiteMask = CurrentSuiteMask;
475  }
476 
477  CallbackInfo.PlatformInfo = pPlatformInfo;
478  CallbackInfo.ProductType = ProductType;
479  CallbackInfo.SuiteMask = SuiteMask;
480  CallbackInfo.PrefixLength = strlenW(InfSectionName);
481  CallbackInfo.BestScore1 = ULONG_MAX;
482  CallbackInfo.BestScore2 = ULONG_MAX;
483  CallbackInfo.BestScore3 = ULONG_MAX;
484  CallbackInfo.BestScore4 = ULONG_MAX;
485  CallbackInfo.BestScore5 = ULONG_MAX;
486  strcpyW(CallbackInfo.BestSection, InfSectionName);
487  TRACE("EnumerateSectionsStartingWith(InfSectionName = %S)\n", InfSectionName);
489  InfHandle,
490  InfSectionName,
492  &CallbackInfo))
493  {
495  goto done;
496  }
497  TRACE("CallbackInfo.BestSection = %S\n", CallbackInfo.BestSection);
498 
499  dwFullLength = lstrlenW(CallbackInfo.BestSection);
500  if (RequiredSize != NULL)
501  *RequiredSize = dwFullLength + 1;
502 
503  if (InfSectionWithExtSize > 0)
504  {
505  if (InfSectionWithExtSize < dwFullLength + 1)
506  {
508  goto done;
509  }
510  strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
511  if (Extension)
512  {
513  DWORD dwLength = lstrlenW(InfSectionName);
514  *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
515  }
516  }
517 
518  ret = TRUE;
519  }
520 
521 done:
522  TRACE("Returning %d\n", ret);
523  return ret;
524 }
525 
526 
527 BOOL
529  IN struct DeviceInfoSet *list,
530  IN LPCWSTR InstancePath,
531  IN LPCGUID pClassGuid,
532  OUT struct DeviceInfo **pDeviceInfo)
533 {
534  DWORD size;
535  CONFIGRET cr;
536  struct DeviceInfo *deviceInfo;
537 
538  *pDeviceInfo = NULL;
539 
540  size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
541  deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
542  if (!deviceInfo)
543  {
545  return FALSE;
546  }
547  ZeroMemory(deviceInfo, size);
548 
549  cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
550  if (cr != CR_SUCCESS)
551  {
553  return FALSE;
554  }
555 
556  deviceInfo->set = list;
557  deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
558  strcpyW(deviceInfo->Data, InstancePath);
559  deviceInfo->instanceId = deviceInfo->Data;
560  deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
561  deviceInfo->DeviceDescription = NULL;
562  memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
563  deviceInfo->CreationFlags = 0;
564  InitializeListHead(&deviceInfo->DriverListHead);
566 
567  *pDeviceInfo = deviceInfo;
568  return TRUE;
569 }
570 
571 
572 static BOOL
574 {
575  HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
576  HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
577  return TRUE;
578 }
579 
580 static BOOL
581 DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
582 {
584  struct DriverInfoElement *driverInfo;
585  struct DeviceInterface *deviceInterface;
586 
587  while (!IsListEmpty(&deviceInfo->DriverListHead))
588  {
589  ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
591  if (!DestroyDriverInfoElement(driverInfo))
592  return FALSE;
593  }
594  while (!IsListEmpty(&deviceInfo->InterfaceListHead))
595  {
597  deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
598  if (!DestroyDeviceInterface(deviceInterface))
599  return FALSE;
600  }
602  if (deviceInfo->hmodDevicePropPageProvider)
604  return HeapFree(GetProcessHeap(), 0, deviceInfo);
605 }
606 
607 static BOOL
609 {
611  struct DeviceInfo *deviceInfo;
612 
613  while (!IsListEmpty(&list->ListHead))
614  {
615  ListEntry = RemoveHeadList(&list->ListHead);
616  deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
617  if (!DestroyDeviceInfo(deviceInfo))
618  return FALSE;
619  }
620  if (list->HKLM != HKEY_LOCAL_MACHINE)
621  RegCloseKey(list->HKLM);
622  CM_Disconnect_Machine(list->hMachine);
623  DestroyClassInstallParams(&list->ClassInstallParams);
624  if (list->hmodClassPropPageProvider)
625  FreeLibrary(list->hmodClassPropPageProvider);
626  return HeapFree(GetProcessHeap(), 0, list);
627 }
628 
629 /***********************************************************************
630  * SetupDiBuildClassInfoList (SETUPAPI.@)
631  *
632  * Returns a list of setup class GUIDs that identify the classes
633  * that are installed on a local machine.
634  *
635  * PARAMS
636  * Flags [I] control exclusion of classes from the list.
637  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
638  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
639  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
640  *
641  * RETURNS
642  * Success: TRUE.
643  * Failure: FALSE.
644  */
646  DWORD Flags,
647  LPGUID ClassGuidList,
650 {
651  TRACE("\n");
652  return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
654  NULL, NULL);
655 }
656 
657 /***********************************************************************
658  * SetupDiBuildClassInfoListExA (SETUPAPI.@)
659  *
660  * Returns a list of setup class GUIDs that identify the classes
661  * that are installed on a local or remote machine.
662  *
663  * PARAMS
664  * Flags [I] control exclusion of classes from the list.
665  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
666  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
667  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
668  * MachineName [I] name of a remote machine.
669  * Reserved [I] must be NULL.
670  *
671  * RETURNS
672  * Success: TRUE.
673  * Failure: FALSE.
674  */
676  DWORD Flags,
677  LPGUID ClassGuidList,
681  PVOID Reserved)
682 {
683  LPWSTR MachineNameW = NULL;
684  BOOL bResult;
685 
686  TRACE("%s(0x%lx %p %lu %p %s %p)\n", __FUNCTION__, Flags, ClassGuidList,
688 
689  if (MachineName)
690  {
692  if (MachineNameW == NULL) return FALSE;
693  }
694 
695  bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
697  MachineNameW, Reserved);
698 
699  MyFree(MachineNameW);
700 
701  return bResult;
702 }
703 
704 /***********************************************************************
705  * SetupDiBuildClassInfoListExW (SETUPAPI.@)
706  *
707  * Returns a list of setup class GUIDs that identify the classes
708  * that are installed on a local or remote machine.
709  *
710  * PARAMS
711  * Flags [I] control exclusion of classes from the list.
712  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
713  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
714  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
715  * MachineName [I] name of a remote machine.
716  * Reserved [I] must be NULL.
717  *
718  * RETURNS
719  * Success: TRUE.
720  * Failure: FALSE.
721  */
723  DWORD Flags,
724  LPGUID ClassGuidList,
728  PVOID Reserved)
729 {
730  GUID CurrentClassGuid;
731  HKEY hClassKey;
732  DWORD dwIndex;
733  DWORD dwGuidListIndex = 0;
734  HMACHINE hMachine = NULL;
735  CONFIGRET cr;
736 
737  TRACE("%s(0x%lx %p %lu %p %s %p)\n", __FUNCTION__, Flags, ClassGuidList,
739 
740  if (!RequiredSize)
741  {
743  return FALSE;
744  }
745  else if (!ClassGuidList && ClassGuidListSize > 0)
746  {
748  return FALSE;
749  }
750 
751  if (MachineName)
752  {
753  cr = CM_Connect_MachineW(MachineName, &hMachine);
754  if (cr != CR_SUCCESS)
755  {
757  return FALSE;
758  }
759  }
760 
761  for (dwIndex = 0; ; dwIndex++)
762  {
763  cr = CM_Enumerate_Classes_Ex(dwIndex,
764  &CurrentClassGuid,
765  0,
766  hMachine);
767  if (cr == CR_SUCCESS)
768  {
769  TRACE("Guid: %s\n", debugstr_guid(&CurrentClassGuid));
770  if (CM_Open_Class_Key_ExW(&CurrentClassGuid,
771  NULL,
774  &hClassKey,
776  hMachine) != CR_SUCCESS)
777  {
779  if (hMachine)
780  CM_Disconnect_Machine(hMachine);
781  return FALSE;
782  }
783 
786  NULL,
787  NULL,
788  NULL,
789  NULL))
790  {
791  TRACE("'NoUseClass' value found!\n");
793  continue;
794  }
795 
796  if ((Flags & DIBCI_NOINSTALLCLASS) &&
799  NULL,
800  NULL,
801  NULL,
802  NULL)))
803  {
804  TRACE("'NoInstallClass' value found!\n");
806  continue;
807  }
808 
809  if ((Flags & DIBCI_NODISPLAYCLASS) &&
812  NULL,
813  NULL,
814  NULL,
815  NULL)))
816  {
817  TRACE("'NoDisplayClass' value found!\n");
819  continue;
820  }
821 
823 
824  if (dwGuidListIndex < ClassGuidListSize)
825  {
826  ClassGuidList[dwGuidListIndex] = CurrentClassGuid;
827  }
828 
829  dwGuidListIndex++;
830  }
831 
832  if (cr != ERROR_SUCCESS)
833  break;
834  }
835 
836  if (hMachine)
837  CM_Disconnect_Machine(hMachine);
838 
839  if (RequiredSize != NULL)
840  *RequiredSize = dwGuidListIndex;
841 
842  if (ClassGuidListSize < dwGuidListIndex)
843  {
845  return FALSE;
846  }
847 
848  return TRUE;
849 }
850 
851 /***********************************************************************
852  * SetupDiClassGuidsFromNameA (SETUPAPI.@)
853  */
855  LPCSTR ClassName,
856  LPGUID ClassGuidList,
859 {
860  return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
862  NULL, NULL);
863 }
864 
865 /***********************************************************************
866  * SetupDiClassGuidsFromNameW (SETUPAPI.@)
867  */
869  LPCWSTR ClassName,
870  LPGUID ClassGuidList,
873 {
874  return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
876  NULL, NULL);
877 }
878 
879 /***********************************************************************
880  * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
881  */
883  LPCSTR ClassName,
884  LPGUID ClassGuidList,
888  PVOID Reserved)
889 {
890  LPWSTR ClassNameW = NULL;
891  LPWSTR MachineNameW = NULL;
892  BOOL bResult;
893 
894  TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_a(ClassName), ClassGuidList,
896 
897  if (!ClassName)
898  {
900  return FALSE;
901  }
902 
903  ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
904  if (ClassNameW == NULL)
905  return FALSE;
906 
907  if (MachineName)
908  {
910  if (MachineNameW == NULL)
911  {
912  MyFree(ClassNameW);
913  return FALSE;
914  }
915  }
916 
917  bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
919  MachineNameW, Reserved);
920 
921  MyFree(MachineNameW);
922  MyFree(ClassNameW);
923 
924  return bResult;
925 }
926 
927 /***********************************************************************
928  * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
929  */
931  LPCWSTR ClassName,
932  LPGUID ClassGuidList,
936  PVOID Reserved)
937 {
938  WCHAR szKeyName[40];
940  HKEY hClassesKey;
941  HKEY hClassKey;
942  DWORD dwLength;
943  DWORD dwIndex;
944  LONG lError;
945  DWORD dwGuidListIndex = 0;
946 
947  TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_w(ClassName), ClassGuidList,
949 
950  if (!ClassName || !RequiredSize)
951  {
953  return FALSE;
954  }
955  if (!ClassGuidList && ClassGuidListSize > 0)
956  {
958  return FALSE;
959  }
960  *RequiredSize = 0;
961 
962  hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
965  MachineName,
966  Reserved);
967  if (hClassesKey == INVALID_HANDLE_VALUE)
968  {
969  return FALSE;
970  }
971 
972  for (dwIndex = 0; ; dwIndex++)
973  {
974  dwLength = 40;
975  lError = RegEnumKeyExW(hClassesKey,
976  dwIndex,
977  szKeyName,
978  &dwLength,
979  NULL,
980  NULL,
981  NULL,
982  NULL);
983  TRACE("RegEnumKeyExW() returns %d\n", lError);
984  if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
985  {
986  TRACE("Key name: %p\n", szKeyName);
987 
988  if (RegOpenKeyExW(hClassesKey,
989  szKeyName,
990  0,
992  &hClassKey))
993  {
994  RegCloseKey(hClassesKey);
995  return FALSE;
996  }
997 
998  dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
1001  NULL,
1002  NULL,
1004  &dwLength))
1005  {
1006  TRACE("Class name: %p\n", szClassName);
1007 
1008  if (strcmpiW(szClassName, ClassName) == 0)
1009  {
1010  TRACE("Found matching class name\n");
1011 
1012  TRACE("Guid: %p\n", szKeyName);
1013  if (dwGuidListIndex < ClassGuidListSize)
1014  {
1015  if (szKeyName[0] == '{' && szKeyName[37] == '}')
1016  {
1017  szKeyName[37] = 0;
1018  }
1019  TRACE("Guid: %p\n", &szKeyName[1]);
1020 
1021  UuidFromStringW(&szKeyName[1],
1022  &ClassGuidList[dwGuidListIndex]);
1023  }
1024 
1025  dwGuidListIndex++;
1026  }
1027  }
1028 
1030  }
1031 
1032  if (lError != ERROR_SUCCESS)
1033  break;
1034  }
1035 
1036  RegCloseKey(hClassesKey);
1037 
1038  if (RequiredSize != NULL)
1039  *RequiredSize = dwGuidListIndex;
1040 
1041  if (ClassGuidListSize < dwGuidListIndex)
1042  {
1044  return FALSE;
1045  }
1046 
1047  return TRUE;
1048 }
1049 
1050 /***********************************************************************
1051  * SetupDiClassNameFromGuidA (SETUPAPI.@)
1052  */
1054  const GUID* ClassGuid,
1055  PSTR ClassName,
1056  DWORD ClassNameSize,
1058 {
1059  return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1060  ClassNameSize, RequiredSize,
1061  NULL, NULL);
1062 }
1063 
1064 /***********************************************************************
1065  * SetupDiClassNameFromGuidW (SETUPAPI.@)
1066  */
1068  const GUID* ClassGuid,
1069  PWSTR ClassName,
1070  DWORD ClassNameSize,
1072 {
1073  return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1074  ClassNameSize, RequiredSize,
1075  NULL, NULL);
1076 }
1077 
1078 /***********************************************************************
1079  * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1080  */
1082  const GUID* ClassGuid,
1083  PSTR ClassName,
1084  DWORD ClassNameSize,
1087  PVOID Reserved)
1088 {
1089  WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1090  LPWSTR MachineNameW = NULL;
1091  BOOL ret;
1092 
1093  if (MachineName)
1094  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1096  RequiredSize, MachineNameW, Reserved);
1097  if (ret)
1098  {
1099  int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1100  ClassNameSize, NULL, NULL);
1101  if (len == 0 || len > ClassNameSize)
1102  {
1104  ret = FALSE;
1105  }
1106  }
1107  MyFree(MachineNameW);
1108  return ret;
1109 }
1110 
1111 /***********************************************************************
1112  * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1113  */
1115  const GUID* ClassGuid,
1116  PWSTR ClassName,
1117  DWORD ClassNameSize,
1120  PVOID Reserved)
1121 {
1122  HKEY hKey;
1123  DWORD dwLength;
1124  DWORD dwRegType;
1125  LONG rc;
1126  PWSTR Buffer;
1127 
1128  TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassName,
1129  ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
1130 
1131  /* Make sure there's a GUID */
1132  if (ClassGuid == NULL)
1133  {
1134  SetLastError(ERROR_INVALID_CLASS); /* On Vista: ERROR_INVALID_USER_BUFFER */
1135  return FALSE;
1136  }
1137 
1138  /* Make sure there's a real buffer when there's a size */
1139  if ((ClassNameSize > 0) && (ClassName == NULL))
1140  {
1141  SetLastError(ERROR_INVALID_PARAMETER); /* On Vista: ERROR_INVALID_USER_BUFFER */
1142  return FALSE;
1143  }
1144 
1145  /* Open the key for the GUID */
1147 
1148  if (hKey == INVALID_HANDLE_VALUE)
1149  return FALSE;
1150 
1151  /* Retrieve the class name data and close the key */
1152  rc = QueryRegistryValue(hKey, REGSTR_VAL_CLASS, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
1153  RegCloseKey(hKey);
1154 
1155  /* Make sure we got the data */
1156  if (rc != ERROR_SUCCESS)
1157  {
1158  SetLastError(rc);
1159  return FALSE;
1160  }
1161 
1162  /* Make sure the data is a string */
1163  if (dwRegType != REG_SZ)
1164  {
1165  MyFree(Buffer);
1167  return FALSE;
1168  }
1169 
1170  /* Determine the length of the class name */
1171  dwLength /= sizeof(WCHAR);
1172 
1173  if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
1174  /* Count the null-terminator */
1175  dwLength++;
1176 
1177  /* Inform the caller about the class name */
1178  if ((ClassName != NULL) && (dwLength <= ClassNameSize))
1179  {
1180  memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
1181  ClassName[dwLength - 1] = UNICODE_NULL;
1182  }
1183 
1184  /* Inform the caller about the required size */
1185  if (RequiredSize != NULL)
1187 
1188  /* Clean up the buffer */
1189  MyFree(Buffer);
1190 
1191  /* Make sure the buffer was large enough */
1192  if ((ClassName == NULL) || (dwLength > ClassNameSize))
1193  {
1195  return FALSE;
1196  }
1197 
1198  return TRUE;
1199 }
1200 
1201 /***********************************************************************
1202  * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1203  */
1206  HWND hwndParent)
1207 {
1209 }
1210 
1211 /***********************************************************************
1212  * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1213  */
1216  HWND hwndParent,
1218  PVOID Reserved)
1219 {
1220  LPWSTR MachineNameW = NULL;
1221  HDEVINFO hDevInfo;
1222 
1223  TRACE("%s(%s %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), hwndParent,
1225 
1226  if (MachineName)
1227  {
1228  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1229  if (MachineNameW == NULL)
1230  return INVALID_HANDLE_VALUE;
1231  }
1232 
1234  MachineNameW, Reserved);
1235 
1236  MyFree(MachineNameW);
1237 
1238  return hDevInfo;
1239 }
1240 
1241 /***********************************************************************
1242  * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1243  *
1244  * Create an empty DeviceInfoSet list.
1245  *
1246  * PARAMS
1247  * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1248  * with this list.
1249  * hwndParent [I] hwnd needed for interface related actions.
1250  * MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1251  * local registry will be used.
1252  * Reserved [I] must be NULL
1253  *
1254  * RETURNS
1255  * Success: empty list.
1256  * Failure: INVALID_HANDLE_VALUE.
1257  */
1260  HWND hwndParent,
1262  PVOID Reserved)
1263 {
1264  struct DeviceInfoSet *list = NULL;
1266  DWORD rc;
1267  CONFIGRET cr;
1269 
1270  TRACE("%s(%s %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), hwndParent,
1272 
1273  if (MachineName != NULL)
1274  {
1276  if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
1277  {
1279  goto cleanup;
1280  }
1281  if(len > 0)
1282  size += (len + 3) * sizeof(WCHAR);
1283  else
1284  MachineName = NULL;
1285  }
1286 
1287  if (Reserved != NULL)
1288  {
1290  return INVALID_HANDLE_VALUE;
1291  }
1292 
1293  list = MyMalloc(size);
1294  if (!list)
1295  {
1297  return INVALID_HANDLE_VALUE;
1298  }
1300 
1302  memcpy(&list->ClassGuid,
1304  sizeof(list->ClassGuid));
1305  list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
1306  list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
1307  list->InstallParams.hwndParent = hwndParent;
1308  if (MachineName)
1309  {
1311  if (rc != ERROR_SUCCESS)
1312  {
1314  goto cleanup;
1315  }
1316 
1317  list->szData[0] = list->szData[1] = '\\';
1318  strcpyW(list->szData + 2, MachineName);
1319  list->MachineName = list->szData;
1320  }
1321  else
1322  {
1323  list->HKLM = HKEY_LOCAL_MACHINE;
1324  list->MachineName = NULL;
1325  }
1326  cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
1327  if (cr != CR_SUCCESS)
1328  {
1330  goto cleanup;
1331  }
1332  InitializeListHead(&list->DriverListHead);
1333  InitializeListHead(&list->ListHead);
1334 
1335  return (HDEVINFO)list;
1336 
1337 cleanup:
1338  if (ret == INVALID_HANDLE_VALUE)
1339  {
1340  if (list)
1341  {
1342  if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
1343  RegCloseKey(list->HKLM);
1344  MyFree(list);
1345  }
1346  }
1347  return ret;
1348 }
1349 
1350 /***********************************************************************
1351  * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1352  */
1356  DWORD Scope,
1357  DWORD HwProfile,
1358  DWORD KeyType,
1359  HINF InfHandle,
1360  PCSTR InfSectionName)
1361 {
1362  PWSTR InfSectionNameW = NULL;
1363  HKEY key;
1364 
1365  TRACE("%s(%p %p %d %d %d %p %s)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope,
1366  HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1367 
1368  if (InfHandle)
1369  {
1370  if (!InfSectionName)
1371  {
1373  return INVALID_HANDLE_VALUE;
1374  }
1375  else
1376  {
1377  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
1378  if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1379  }
1380  }
1382  HwProfile, KeyType, InfHandle, InfSectionNameW);
1383  MyFree(InfSectionNameW);
1384  return key;
1385 }
1386 
1387 static HKEY
1389  IN HKEY HKLM,
1390  IN DWORD HwProfile,
1391  IN DWORD samDesired);
1392 
1393 /***********************************************************************
1394  * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1395  */
1399  DWORD Scope,
1400  DWORD HwProfile,
1401  DWORD KeyType,
1402  HINF InfHandle,
1403  PCWSTR InfSectionName)
1404 {
1405  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1406  struct DeviceInfo *deviceInfo;
1408  DWORD rc;
1409  HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
1410  HKEY hKey = NULL;
1411  HKEY RootKey;
1412 
1413  TRACE("%s(%p %p %lu %lu %lu %p %s)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Scope,
1414  HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1415 
1417  {
1419  return INVALID_HANDLE_VALUE;
1420  }
1421  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1422  {
1424  return INVALID_HANDLE_VALUE;
1425  }
1427  || !DeviceInfoData->Reserved)
1428  {
1430  return INVALID_HANDLE_VALUE;
1431  }
1432  if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1433  {
1435  return INVALID_HANDLE_VALUE;
1436  }
1437  if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1438  {
1440  return INVALID_HANDLE_VALUE;
1441  }
1442  if (InfHandle && !InfSectionName)
1443  {
1445  return INVALID_HANDLE_VALUE;
1446  }
1447  if (!InfHandle && InfSectionName)
1448  {
1450  return INVALID_HANDLE_VALUE;
1451  }
1452 
1453  deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1454 
1455  if (Scope == DICS_FLAG_GLOBAL)
1456  RootKey = set->HKLM;
1457  else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
1458  {
1459  hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
1460  if (hHWProfileKey == INVALID_HANDLE_VALUE)
1461  goto cleanup;
1462  RootKey = hHWProfileKey;
1463  }
1464 
1465  if (KeyType == DIREG_DEV)
1466  {
1467 #if _WIN32_WINNT >= 0x502
1469 #else
1471 #endif
1472  if (hKey == INVALID_HANDLE_VALUE)
1473  goto cleanup;
1474 
1475  if (Scope == DICS_FLAG_GLOBAL)
1476  {
1477  HKEY hTempKey = hKey;
1478 
1479  rc = RegCreateKeyExW(hTempKey,
1480  L"Device Parameters",
1481  0,
1482  NULL,
1484 #if _WIN32_WINNT >= 0x502
1485  KEY_READ | KEY_WRITE,
1486 #else
1488 #endif
1489  NULL,
1490  &hKey,
1491  NULL);
1492  if (rc == ERROR_SUCCESS)
1493  RegCloseKey(hTempKey);
1494  }
1495  }
1496  else /* KeyType == DIREG_DRV */
1497  {
1498 #if _WIN32_WINNT >= 0x502
1500 #else
1502 #endif
1503  if (hKey == INVALID_HANDLE_VALUE)
1504  goto cleanup;
1505  }
1506 
1507  /* Do installation of the specified section */
1508  if (InfHandle)
1509  {
1510  FIXME("Need to install section %s in file %p\n",
1511  debugstr_w(InfSectionName), InfHandle);
1512  }
1513  key = hKey;
1514 
1515 cleanup:
1516  if (hHWProfileKey != INVALID_HANDLE_VALUE)
1517  RegCloseKey(hHWProfileKey);
1518  if (hKey != NULL && hKey != key)
1519  RegCloseKey(hKey);
1520 
1521  TRACE("Returning 0x%p\n", key);
1522  return key;
1523 }
1524 
1525 /***********************************************************************
1526  * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1527  */
1530  PCSTR DeviceName,
1531  CONST GUID *ClassGuid,
1533  HWND hwndParent,
1536 {
1537  BOOL ret;
1538  LPWSTR DeviceNameW = NULL;
1539  LPWSTR DeviceDescriptionW = NULL;
1540 
1541  TRACE("\n");
1542 
1543  if (DeviceName)
1544  {
1545  DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
1546  if (DeviceNameW == NULL) return FALSE;
1547  }
1548  if (DeviceDescription)
1549  {
1550  DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
1551  if (DeviceDescriptionW == NULL)
1552  {
1553  MyFree(DeviceNameW);
1554  return FALSE;
1555  }
1556  }
1557 
1558  ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1560 
1561  MyFree(DeviceNameW);
1562  MyFree(DeviceDescriptionW);
1563 
1564  return ret;
1565 }
1566 
1567 /***********************************************************************
1568  * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1569  */
1573  CONST GUID *ClassGuid,
1575  HWND hwndParent,
1578 {
1579  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1580  struct DeviceInfo *deviceInfo = NULL;
1581  BOOL ret = FALSE;
1582  CONFIGRET cr;
1583  DEVINST RootDevInst;
1584  DEVINST DevInst;
1585  WCHAR GenInstanceId[MAX_DEVICE_ID_LEN];
1586  DWORD dwFlags;
1587 
1588  TRACE("%s(%p %s %s %s %p %x %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_w(DeviceName),
1591 
1592  if (!DeviceName)
1593  {
1595  return FALSE;
1596  }
1598  {
1600  return FALSE;
1601  }
1602  if (!ClassGuid)
1603  {
1605  return FALSE;
1606  }
1607  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1608  {
1610  return FALSE;
1611  }
1612  if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1613  !IsEqualGUID(ClassGuid, &set->ClassGuid))
1614  {
1616  return FALSE;
1617  }
1619  {
1620  TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
1622  return FALSE;
1623  }
1624 
1625  /* Get the root device instance */
1626  cr = CM_Locate_DevInst_ExW(&RootDevInst,
1627  NULL,
1629  set->hMachine);
1630  if (cr != CR_SUCCESS)
1631  {
1633  return FALSE;
1634  }
1635 
1639 
1640  /* Create the new device instance */
1641  cr = CM_Create_DevInst_ExW(&DevInst,
1643  RootDevInst,
1644  dwFlags,
1645  set->hMachine);
1646  if (cr != CR_SUCCESS)
1647  {
1649  return FALSE;
1650  }
1651 
1653  {
1654  /* Grab the actual instance ID that was created */
1655  cr = CM_Get_Device_ID_Ex(DevInst,
1656  GenInstanceId,
1658  0,
1659  set->hMachine);
1660  if (cr != CR_SUCCESS)
1661  {
1663  return FALSE;
1664  }
1665 
1666  DeviceName = GenInstanceId;
1667  TRACE("Using generated instance ID: %s\n", debugstr_w(DeviceName));
1668  }
1669 
1670  if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
1671  {
1672  InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
1673 
1674  if (!DeviceInfoData)
1675  ret = TRUE;
1676  else
1677  {
1678  if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1679  {
1681  }
1682  else
1683  {
1685  DeviceInfoData->DevInst = deviceInfo->dnDevInst;
1686  DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
1687  ret = TRUE;
1688  }
1689  }
1690  }
1691 
1692  if (ret == FALSE)
1693  {
1694  if (deviceInfo != NULL)
1695  {
1696  /* Remove deviceInfo from List */
1697  RemoveEntryList(&deviceInfo->ListEntry);
1698 
1699  /* Destroy deviceInfo */
1700  DestroyDeviceInfo(deviceInfo);
1701  }
1702  }
1703 
1704  TRACE("Returning %d\n", ret);
1705  return ret;
1706 }
1707 
1708 /***********************************************************************
1709  * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1710  */
1714  DWORD Flags,
1715  PSP_DETSIG_CMPPROC CompareProc,
1716  PVOID CompareContext,
1717  PSP_DEVINFO_DATA DupDeviceInfoData)
1718 {
1719  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1720  WCHAR DevInstId[MAX_DEVICE_ID_LEN];
1721  DEVINST ParentDevInst;
1722  CONFIGRET cr;
1723  DWORD dwError = ERROR_SUCCESS;
1724 
1725  TRACE("%s(%p %p %08x %p %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Flags,
1726  CompareProc, CompareContext, DupDeviceInfoData);
1727 
1729  {
1731  return FALSE;
1732  }
1733  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1734  {
1736  return FALSE;
1737  }
1739  || !DeviceInfoData->Reserved)
1740  {
1742  return FALSE;
1743  }
1744 
1745  if (Flags & ~SPRDI_FIND_DUPS)
1746  {
1747  TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
1749  return FALSE;
1750  }
1751 
1752  if (Flags & SPRDI_FIND_DUPS)
1753  {
1754  FIXME("Unimplemented codepath!\n");
1755  }
1756 
1758  DevInstId,
1760  0,
1761  set->hMachine);
1762 
1763  CM_Get_Parent_Ex(&ParentDevInst,
1765  0,
1766  set->hMachine);
1767 
1769  DevInstId,
1770  ParentDevInst,
1772  set->hMachine);
1773  if (cr != CR_SUCCESS &&
1775  {
1776  dwError = ERROR_NO_SUCH_DEVINST;
1777  }
1778 
1779  SetLastError(dwError);
1780 
1781  return (dwError == ERROR_SUCCESS);
1782 }
1783 
1784 /***********************************************************************
1785  * SetupDiEnumDeviceInfo (SETUPAPI.@)
1786  */
1788  HDEVINFO devinfo,
1789  DWORD index,
1791 {
1792  BOOL ret = FALSE;
1793 
1794  TRACE("%s(%p %d %p)\n", __FUNCTION__, devinfo, index, info);
1795 
1796  if(info==NULL)
1797  {
1799  return FALSE;
1800  }
1801  if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1802  {
1803  struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1804  if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1805  {
1806  if (info->cbSize != sizeof(SP_DEVINFO_DATA))
1808  else
1809  {
1810  PLIST_ENTRY ItemList = list->ListHead.Flink;
1811  while (ItemList != &list->ListHead && index-- > 0)
1812  ItemList = ItemList->Flink;
1813  if (ItemList == &list->ListHead)
1815  else
1816  {
1817  struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
1818  memcpy(&info->ClassGuid,
1819  &DevInfo->ClassGuid,
1820  sizeof(GUID));
1821  info->DevInst = DevInfo->dnDevInst;
1822  info->Reserved = (ULONG_PTR)DevInfo;
1823  ret = TRUE;
1824  }
1825  }
1826  }
1827  else
1829  }
1830  else
1832  return ret;
1833 }
1834 
1835 /***********************************************************************
1836  * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1837  */
1841  PSTR DeviceInstanceId,
1842  DWORD DeviceInstanceIdSize,
1844 {
1845  BOOL ret = FALSE;
1846  DWORD size;
1847  PWSTR instanceId;
1848 
1849  TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1850  DeviceInstanceIdSize, RequiredSize);
1851 
1852  if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1853  {
1855  return FALSE;
1856  }
1857 
1860  NULL,
1861  0,
1862  &size);
1864  return FALSE;
1865  instanceId = MyMalloc(size * sizeof(WCHAR));
1866  if (instanceId)
1867  {
1870  instanceId,
1871  size,
1872  &size);
1873  if (ret)
1874  {
1875  int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
1876  DeviceInstanceId,
1877  DeviceInstanceIdSize, NULL, NULL);
1878 
1879  if (!len)
1880  ret = FALSE;
1881  else
1882  {
1883  if (len > DeviceInstanceIdSize)
1884  {
1886  ret = FALSE;
1887  }
1888  if (RequiredSize)
1889  *RequiredSize = len;
1890  }
1891  }
1892  MyFree(instanceId);
1893  }
1894  else
1895  {
1896  if (RequiredSize)
1897  *RequiredSize = size;
1899  ret = FALSE;
1900  }
1901  return ret;
1902 }
1903 
1904 /***********************************************************************
1905  * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
1906  */
1910  PWSTR DeviceInstanceId,
1911  DWORD DeviceInstanceIdSize,
1913 {
1914  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1915  struct DeviceInfo *devInfo;
1916 
1917  TRACE("%s(%p %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1918  DeviceInstanceIdSize, RequiredSize);
1919 
1921  {
1923  return FALSE;
1924  }
1925  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1926  {
1928  return FALSE;
1929  }
1931  || !DeviceInfoData->Reserved)
1932  {
1934  return FALSE;
1935  }
1936  devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1937  if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1938  {
1940  return FALSE;
1941  }
1942  if (DeviceInstanceId && DeviceInstanceIdSize == 0)
1943  {
1945  return FALSE;
1946  }
1947  TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
1948  if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
1949  {
1951  if (RequiredSize)
1952  *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1953  return FALSE;
1954  }
1955  lstrcpyW(DeviceInstanceId, devInfo->instanceId);
1956  if (RequiredSize)
1957  *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
1958  return TRUE;
1959 }
1960 
1961 /***********************************************************************
1962  * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
1963  */
1965  HINF InfHandle,
1966  PCSTR InfSectionName,
1967  PSTR InfSectionWithExt,
1968  DWORD InfSectionWithExtSize,
1970  PSTR *Extension)
1971 {
1972  return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
1973  NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1974  Extension, NULL);
1975 }
1976 
1977 /***********************************************************************
1978  * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
1979  */
1981  HINF InfHandle,
1982  PCWSTR InfSectionName,
1983  PWSTR InfSectionWithExt,
1984  DWORD InfSectionWithExtSize,
1986  PWSTR *Extension)
1987 {
1988  return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
1989  NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
1990  Extension, NULL);
1991 }
1992 
1993 /***********************************************************************
1994  * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
1995  */
1996 BOOL WINAPI
1998  IN HINF InfHandle,
1999  IN PCSTR InfSectionName,
2000  IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
2001  OUT PSTR InfSectionWithExt OPTIONAL,
2002  IN DWORD InfSectionWithExtSize,
2005  IN PVOID Reserved)
2006 {
2007  LPWSTR InfSectionNameW = NULL;
2008  LPWSTR InfSectionWithExtW = NULL;
2009  PWSTR ExtensionW;
2010  BOOL bResult = FALSE;
2011 
2012  TRACE("%s()\n", __FUNCTION__);
2013 
2014  if (InfSectionName)
2015  {
2016  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2017  if (InfSectionNameW == NULL)
2018  goto cleanup;
2019  }
2020  if (InfSectionWithExt)
2021  {
2022  InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
2023  if (InfSectionWithExtW == NULL)
2024  goto cleanup;
2025  }
2026 
2028  InfHandle, InfSectionNameW, AlternatePlatformInfo,
2029  InfSectionWithExt ? InfSectionWithExtW : NULL,
2030  InfSectionWithExtSize,
2031  RequiredSize,
2032  Extension ? &ExtensionW : NULL,
2033  Reserved);
2034 
2035  if (bResult && InfSectionWithExt)
2036  {
2037  bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
2038  InfSectionWithExtSize, NULL, NULL) != 0;
2039  }
2040  if (bResult && Extension)
2041  {
2042  if (ExtensionW == NULL)
2043  *Extension = NULL;
2044  else
2045  *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
2046  }
2047 
2048 cleanup:
2049  MyFree(InfSectionNameW);
2050  MyFree(InfSectionWithExtW);
2051 
2052  return bResult;
2053 }
2054 
2055 /***********************************************************************
2056  * SetupDiGetClassDescriptionA (SETUPAPI.@)
2057  */
2059  const GUID* ClassGuid,
2060  PSTR ClassDescription,
2061  DWORD ClassDescriptionSize,
2063 {
2064  return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2065  ClassDescriptionSize,
2066  RequiredSize, NULL, NULL);
2067 }
2068 
2069 /***********************************************************************
2070  * SetupDiGetClassDescriptionW (SETUPAPI.@)
2071  */
2073  const GUID* ClassGuid,
2074  PWSTR ClassDescription,
2075  DWORD ClassDescriptionSize,
2077 {
2078  return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2079  ClassDescriptionSize,
2080  RequiredSize, NULL, NULL);
2081 }
2082 
2083 /***********************************************************************
2084  * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2085  */
2087  const GUID* ClassGuid,
2088  PSTR ClassDescription,
2089  DWORD ClassDescriptionSize,
2092  PVOID Reserved)
2093 {
2094  PWCHAR ClassDescriptionW = NULL;
2095  LPWSTR MachineNameW = NULL;
2096  BOOL ret = FALSE;
2097 
2098  TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2099  ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
2100 
2101  if (ClassDescriptionSize > 0)
2102  {
2103  ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
2104  if (!ClassDescriptionW)
2105  {
2107  goto cleanup;
2108  }
2109  }
2110 
2111  if (MachineName)
2112  {
2113  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
2114  if (!MachineNameW)
2115  {
2117  goto cleanup;
2118  }
2119  }
2120 
2121  ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
2122  ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
2123  if (ret)
2124  {
2125  DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
2126  ClassDescriptionSize, NULL, NULL);
2127  if (len == 0 || len > ClassDescriptionSize)
2128  {
2130  ret = FALSE;
2131  }
2132  }
2133 
2134 cleanup:
2135  MyFree(ClassDescriptionW);
2136  MyFree(MachineNameW);
2137  return ret;
2138 }
2139 
2140 /***********************************************************************
2141  * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2142  */
2144  const GUID* ClassGuid,
2145  PWSTR ClassDescription,
2146  DWORD ClassDescriptionSize,
2149  PVOID Reserved)
2150 {
2151  HKEY hKey;
2152  DWORD dwLength;
2153  DWORD dwRegType;
2154  LONG rc;
2155  PWSTR Buffer;
2156 
2157  TRACE("%s(%s %p %lu %p %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), ClassDescription,
2158  ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
2159 
2160  /* Make sure there's a GUID */
2161  if (!ClassGuid)
2162  {
2164  return FALSE;
2165  }
2166 
2167  /* Make sure there's a real buffer when there's a size */
2168  if (!ClassDescription && ClassDescriptionSize > 0)
2169  {
2171  return FALSE;
2172  }
2173 
2174  /* Open the key for the GUID */
2178  MachineName,
2179  Reserved);
2180  if (hKey == INVALID_HANDLE_VALUE)
2181  return FALSE;
2182 
2183  /* Retrieve the class description data and close the key */
2184  rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
2185  RegCloseKey(hKey);
2186 
2187  /* Make sure we got the data */
2188  if (rc != ERROR_SUCCESS)
2189  {
2190  SetLastError(rc);
2191  return FALSE;
2192  }
2193 
2194  /* Make sure the data is a string */
2195  if (dwRegType != REG_SZ)
2196  {
2197  MyFree(Buffer);
2199  return FALSE;
2200  }
2201 
2202  /* Determine the length of the class description */
2203  dwLength /= sizeof(WCHAR);
2204 
2205  /* Count the null-terminator if none is present */
2206  if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
2207  dwLength++;
2208 
2209  /* Inform the caller about the class description */
2210  if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
2211  {
2212  memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
2213  ClassDescription[dwLength - 1] = UNICODE_NULL;
2214  }
2215 
2216  /* Inform the caller about the required size */
2217  if (RequiredSize != NULL)
2219 
2220  /* Clean up the buffer */
2221  MyFree(Buffer);
2222 
2223  /* Make sure the buffer was large enough */
2224  if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
2225  {
2227  return FALSE;
2228  }
2229 
2230  return TRUE;
2231 }
2232 
2233 /***********************************************************************
2234  * SetupDiGetClassDevsA (SETUPAPI.@)
2235  */
2237  CONST GUID *class,
2238  LPCSTR enumstr,
2239  HWND parent,
2240  DWORD flags)
2241 {
2242  return SetupDiGetClassDevsExA(class, enumstr, parent,
2243  flags, NULL, NULL, NULL);
2244 }
2245 
2246 /***********************************************************************
2247  * SetupDiGetClassDevsExA (SETUPAPI.@)
2248  */
2250  const GUID *class,
2251  PCSTR enumstr,
2252  HWND parent,
2253  DWORD flags,
2254  HDEVINFO deviceset,
2255  PCSTR machine,
2256  PVOID reserved)
2257 {
2258  HDEVINFO ret;
2259  LPWSTR enumstrW = NULL, machineW = NULL;
2260 
2261  if (enumstr)
2262  {
2263  enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
2264  if (!enumstrW)
2265  {
2267  goto end;
2268  }
2269  }
2270  if (machine)
2271  {
2273  if (!machineW)
2274  {
2275  MyFree(enumstrW);
2277  goto end;
2278  }
2279  }
2280  ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2281  machineW, reserved);
2282  MyFree(enumstrW);
2283  MyFree(machineW);
2284 
2285 end:
2286  return ret;
2287 }
2288 
2289 /***********************************************************************
2290  * SetupDiGetClassDevsW (SETUPAPI.@)
2291  */
2293  CONST GUID *class,
2294  LPCWSTR enumstr,
2295  HWND parent,
2296  DWORD flags)
2297 {
2298  return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2299  NULL);
2300 }
2301 
2302 /***********************************************************************
2303  * SetupDiGetClassDevsExW (SETUPAPI.@)
2304  */
2306  CONST GUID *class,
2307  PCWSTR enumstr,
2308  HWND parent,
2309  DWORD flags,
2310  HDEVINFO deviceset,
2311  PCWSTR machine,
2312  PVOID reserved)
2313 {
2314  HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2315  struct DeviceInfoSet *list;
2316  CONST GUID *pClassGuid;
2317  LONG rc;
2319 
2320  TRACE("%s(%s %s %p 0x%08x %p %s %p)\n", __FUNCTION__, debugstr_guid(class),
2321  debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2322  reserved);
2323 
2324  if (!(flags & DIGCF_ALLCLASSES) && !class)
2325  {
2327  return INVALID_HANDLE_VALUE;
2328  }
2329 
2330  /* Create the deviceset if not set */
2331  if (deviceset)
2332  {
2333  list = (struct DeviceInfoSet *)deviceset;
2334  if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2335  {
2337  goto cleanup;
2338  }
2339  hDeviceInfo = deviceset;
2340  }
2341  else
2342  {
2343  hDeviceInfo = SetupDiCreateDeviceInfoListExW(
2345  NULL, machine, NULL);
2346  if (hDeviceInfo == INVALID_HANDLE_VALUE)
2347  goto cleanup;
2348  list = (struct DeviceInfoSet *)hDeviceInfo;
2349  }
2350 
2351  if (flags & DIGCF_PROFILE)
2352  FIXME(": flag DIGCF_PROFILE ignored\n");
2353 
2355  {
2356  if (!class)
2357  {
2359  goto cleanup;
2360  }
2361  rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
2362  }
2363  else
2364  {
2365  /* Determine which class(es) should be included in the deviceset */
2366  if (flags & DIGCF_ALLCLASSES)
2367  {
2368  /* The caller wants all classes. Check if
2369  * the deviceset limits us to one class */
2370  if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2371  pClassGuid = NULL;
2372  else
2373  pClassGuid = &list->ClassGuid;
2374  }
2375  else if (class)
2376  {
2377  /* The caller wants one class. Check if it matches deviceset class */
2378  if (IsEqualIID(&list->ClassGuid, class)
2379  || IsEqualIID(&list->ClassGuid, &GUID_NULL))
2380  {
2381  pClassGuid = class;
2382  }
2383  else
2384  {
2386  goto cleanup;
2387  }
2388  }
2389  else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
2390  {
2391  /* No class specified. Try to use the one of the deviceset */
2392  if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2393  pClassGuid = &list->ClassGuid;
2394  else
2395  {
2397  goto cleanup;
2398  }
2399  }
2400  else
2401  {
2403  goto cleanup;
2404  }
2405  rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
2406  }
2407  if (rc != ERROR_SUCCESS)
2408  {
2409  SetLastError(rc);
2410  goto cleanup;
2411  }
2412  set = hDeviceInfo;
2413 
2414 cleanup:
2415  if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
2416  SetupDiDestroyDeviceInfoList(hDeviceInfo);
2417  return set;
2418 }
2419 
2420 /***********************************************************************
2421  * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2422  */
2425  PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2426 {
2427  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2428 
2429  TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2430 
2432  {
2434  return FALSE;
2435  }
2436  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2437  {
2439  return FALSE;
2440  }
2441  if (!DevInfoData ||
2442  DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2443  {
2445  return FALSE;
2446  }
2447  memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2448  DevInfoData->RemoteMachineHandle = set->hMachine;
2449  if (set->MachineName)
2450  {
2451  FIXME("Stub\n");
2453  return FALSE;
2454  }
2455  else
2456  DevInfoData->RemoteMachineName[0] = 0;
2457 
2458  return TRUE;
2459 }
2460 
2461 /***********************************************************************
2462  * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2463  */
2466  PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2467 {
2468  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2469 
2470  TRACE("%s(%p %p)\n", __FUNCTION__, DeviceInfoSet, DevInfoData);
2471 
2473  {
2475  return FALSE;
2476  }
2477  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2478  {
2480  return FALSE;
2481  }
2482  if (!DevInfoData ||
2483  DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2484  {
2486  return FALSE;
2487  }
2488  memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2489  DevInfoData->RemoteMachineHandle = set->hMachine;
2490  if (set->MachineName)
2491  strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
2492  else
2493  DevInfoData->RemoteMachineName[0] = 0;
2494 
2495  return TRUE;
2496 }
2497 
2498 /***********************************************************************
2499  * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2500  */
2504  const GUID *InterfaceClassGuid,
2506  DWORD CreationFlags,
2507  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2508 {
2509  BOOL ret;
2510  LPWSTR ReferenceStringW = NULL;
2511 
2512  TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2514  CreationFlags, DeviceInterfaceData);
2515 
2516  if (ReferenceString)
2517  {
2518  ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
2519  if (ReferenceStringW == NULL) return FALSE;
2520  }
2521 
2523  InterfaceClassGuid, ReferenceStringW, CreationFlags,
2524  DeviceInterfaceData);
2525 
2526  MyFree(ReferenceStringW);
2527 
2528  return ret;
2529 }
2530 
2531 /***********************************************************************
2532  * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2533  */
2537  const GUID *InterfaceClassGuid,
2539  DWORD CreationFlags,
2540  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2541 {
2542  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2543  TRACE("%s(%p %p %s %s %08x %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2545  CreationFlags, DeviceInterfaceData);
2546 
2548  {
2550  return FALSE;
2551  }
2552  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2553  {
2555  return FALSE;
2556  }
2558  || !DeviceInfoData->Reserved)
2559  {
2561  return FALSE;
2562  }
2563  if (!InterfaceClassGuid)
2564  {
2566  return FALSE;
2567  }
2568 
2569  FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2571  CreationFlags, DeviceInterfaceData);
2573  return FALSE;
2574 }
2575 
2576 /***********************************************************************
2577  * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2578  */
2581  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2582  DWORD Reserved,
2583  REGSAM samDesired,
2584  HINF InfHandle,
2585  PCSTR InfSectionName)
2586 {
2587  HKEY key;
2588  PWSTR InfSectionNameW = NULL;
2589 
2590  TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2591  samDesired, InfHandle, InfSectionName);
2592  if (InfHandle)
2593  {
2594  if (!InfSectionName)
2595  {
2597  return INVALID_HANDLE_VALUE;
2598  }
2599  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2600  if (!InfSectionNameW)
2601  return INVALID_HANDLE_VALUE;
2602  }
2604  DeviceInterfaceData, Reserved, samDesired, InfHandle,
2605  InfSectionNameW);
2606  MyFree(InfSectionNameW);
2607  return key;
2608 }
2609 
2610 /***********************************************************************
2611  * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2612  */
2615  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2616  DWORD Reserved,
2617  REGSAM samDesired,
2618  HINF InfHandle,
2619  PCWSTR InfSectionName)
2620 {
2621  HKEY hKey, hDevKey;
2623  DWORD Length, Index;
2624  LONG rc;
2625  WCHAR bracedGuidString[39];
2626  struct DeviceInterface *DevItf;
2627  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2628 
2629  TRACE("%s(%p %p %d %08x %p %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved,
2630  samDesired, InfHandle, InfSectionName);
2631 
2633  set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2634  {
2636  return INVALID_HANDLE_VALUE;
2637  }
2638  if (!DeviceInterfaceData ||
2639  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2640  !DeviceInterfaceData->Reserved)
2641  {
2643  return INVALID_HANDLE_VALUE;
2644  }
2645  if (InfHandle && !InfSectionName)
2646  {
2648  return INVALID_HANDLE_VALUE;
2649  }
2650 
2651  hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
2652  if (hKey == INVALID_HANDLE_VALUE)
2653  {
2655  if (hKey == INVALID_HANDLE_VALUE)
2656  {
2658  return INVALID_HANDLE_VALUE;
2659  }
2660  SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
2661 
2662  if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
2663  {
2665  return INVALID_HANDLE_VALUE;
2666  }
2667  RegCloseKey(hKey);
2668  hKey = hDevKey;
2669  }
2670 
2671  DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2672 
2673  Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
2675  if (!SymbolicLink)
2676  {
2677  RegCloseKey(hKey);
2679  return INVALID_HANDLE_VALUE;
2680  }
2681 
2682  wcscpy(SymbolicLink, DevItf->SymbolicLink);
2683 
2684  Index = 0;
2685  while(SymbolicLink[Index])
2686  {
2687  if (SymbolicLink[Index] == L'\\')
2688  {
2689  SymbolicLink[Index] = L'#';
2690  }
2691  Index++;
2692  }
2693 
2694  rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
2695 
2696  RegCloseKey(hKey);
2698 
2699  if (rc == ERROR_SUCCESS)
2700  {
2701  if (InfHandle && InfSectionName)
2702  {
2703  if (!SetupInstallFromInfSection(NULL /*FIXME */,
2704  InfHandle,
2705  InfSectionName,
2707  hDevKey,
2708  NULL,
2709  0,
2710  set->SelectedDevice->InstallParams.InstallMsgHandler,
2711  set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
2713  NULL))
2714  {
2715  RegCloseKey(hDevKey);
2716  return INVALID_HANDLE_VALUE;
2717  }
2718  }
2719  }
2720 
2721  SetLastError(rc);
2722  return hDevKey;
2723 }
2724 
2725 /***********************************************************************
2726  * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2727  */
2730  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2731  DWORD Reserved)
2732 {
2733  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2734  BOOL ret = FALSE;
2735 
2736  TRACE("%s(%p %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInterfaceData, Reserved);
2737 
2739  set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2740  {
2742  return FALSE;
2743  }
2744  if (!DeviceInterfaceData ||
2745  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2746  !DeviceInterfaceData->Reserved)
2747  {
2749  return FALSE;
2750  }
2751 
2752  FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2754  return ret;
2755 }
2756 
2757 /***********************************************************************
2758  * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2759  *
2760  * PARAMS
2761  * DeviceInfoSet [I] Set of devices from which to enumerate
2762  * interfaces
2763  * DeviceInfoData [I] (Optional) If specified, a specific device
2764  * instance from which to enumerate interfaces.
2765  * If it isn't specified, all interfaces for all
2766  * devices in the set are enumerated.
2767  * InterfaceClassGuid [I] The interface class to enumerate.
2768  * MemberIndex [I] An index of the interface instance to enumerate.
2769  * A caller should start with MemberIndex set to 0,
2770  * and continue until the function fails with
2771  * ERROR_NO_MORE_ITEMS.
2772  * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2773  * member must be set to
2774  * sizeof(SP_DEVICE_INTERFACE_DATA).
2775  *
2776  * RETURNS
2777  * Success: non-zero value.
2778  * Failure: FALSE. Call GetLastError() for more info.
2779  */
2784  DWORD MemberIndex,
2785  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2786 {
2787  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2788  BOOL ret = FALSE;
2789 
2790  TRACE("%s(%p, %p, %s, %d, %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
2791  debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2792 
2794  set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2795  {
2797  return FALSE;
2798  }
2799  if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2801  {
2803  return FALSE;
2804  }
2805  if (!DeviceInterfaceData ||
2806  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2807  {
2809  return FALSE;
2810  }
2811  if (DeviceInfoData)
2812  {
2813  struct DeviceInfo *devInfo =
2814  (struct DeviceInfo *)DeviceInfoData->Reserved;
2815  BOOL found = FALSE;
2816  PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2817  while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2818  {
2819  struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2821  {
2822  InterfaceListEntry = InterfaceListEntry->Flink;
2823  continue;
2824  }
2825  if (MemberIndex-- == 0)
2826  {
2827  /* return this item */
2828  memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2829  &DevItf->InterfaceClassGuid,
2830  sizeof(GUID));
2831  DeviceInterfaceData->Flags = DevItf->Flags;
2832  DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2833  found = TRUE;
2834  ret = TRUE;
2835  }
2836  InterfaceListEntry = InterfaceListEntry->Flink;
2837  }
2838  if (!found)
2840  }
2841  else
2842  {
2843  BOOL found = FALSE;
2844  PLIST_ENTRY ItemList = set->ListHead.Flink;
2845  while (ItemList != &set->ListHead && !found)
2846  {
2847  PLIST_ENTRY InterfaceListEntry;
2848  struct DeviceInfo *devInfo =
2849  CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
2850  InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2851  while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2852  {
2853  struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2855  {
2856  InterfaceListEntry = InterfaceListEntry->Flink;
2857  continue;
2858  }
2859  if (MemberIndex-- == 0)
2860  {
2861  /* return this item */
2862  memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2863  &DevItf->InterfaceClassGuid,
2864  sizeof(GUID));
2865  DeviceInterfaceData->Flags = DevItf->Flags;
2866  DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2867  found = TRUE;
2868  ret = TRUE;
2869  }
2870  InterfaceListEntry = InterfaceListEntry->Flink;
2871  }
2872  ItemList = ItemList->Flink;
2873 
2874  }
2875  if (!found)
2877  }
2878  return ret;
2879 }
2880 
2881 /***********************************************************************
2882  * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
2883  *
2884  * Destroy a DeviceInfoList and free all used memory of the list.
2885  *
2886  * PARAMS
2887  * devinfo [I] DeviceInfoList pointer to list to destroy
2888  *
2889  * RETURNS
2890  * Success: non zero value.
2891  * Failure: zero value.
2892  */
2894 {
2895  BOOL ret = FALSE;
2896 
2897  TRACE("%s(%p)\n", __FUNCTION__, devinfo);
2898  if (devinfo && devinfo != INVALID_HANDLE_VALUE)
2899  {
2900  struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
2901 
2902  if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
2903  {
2905  }
2906  }
2907 
2908  if (ret == FALSE)
2910 
2911  return ret;
2912 }
2913 
2914 /***********************************************************************
2915  * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
2916  */
2919  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2920  PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
2921  DWORD DeviceInterfaceDetailDataSize,
2924 {
2925  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2926  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
2927  DWORD sizeW = 0, bytesNeeded;
2928  BOOL ret = FALSE;
2929 
2930  TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
2931  DeviceInterfaceData, DeviceInterfaceDetailData,
2932  DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
2933 
2935  set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2936  {
2938  return FALSE;
2939  }
2940  if (!DeviceInterfaceData ||
2941  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2942  !DeviceInterfaceData->Reserved)
2943  {
2945  return FALSE;
2946  }
2947  if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
2948  {
2950  return FALSE;
2951  }
2952 
2953  if((DeviceInterfaceDetailDataSize != 0) &&
2954  (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
2955  {
2957  return FALSE;
2958  }
2959 
2960  if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
2961  {
2963  return FALSE;
2964  }
2965 
2966 
2967  if (DeviceInterfaceDetailData != NULL)
2968  {
2970  + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
2971  DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
2972  if (!DeviceInterfaceDetailDataW)
2973  {
2975  }
2976  DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
2977  }
2978  if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
2979  {
2981  DeviceInfoSet,
2982  DeviceInterfaceData,
2983  DeviceInterfaceDetailDataW,
2984  sizeW,
2985  &sizeW,
2986  DeviceInfoData);
2987  bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
2989  if (RequiredSize)
2990  *RequiredSize = bytesNeeded;
2991  if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
2992  {
2993  if (!WideCharToMultiByte(
2994  CP_ACP, 0,
2995  DeviceInterfaceDetailDataW->DevicePath, -1,
2996  DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
2997  NULL, NULL))
2998  {
2999  ret = FALSE;
3000  }
3001  }
3002  }
3003  MyFree(DeviceInterfaceDetailDataW);
3004 
3005  return ret;
3006 }
3007 
3008 /***********************************************************************
3009  * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3010  */
3013  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3014  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
3015  DWORD DeviceInterfaceDetailDataSize,
3018 {
3019  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3020  BOOL ret = FALSE;
3021 
3022  TRACE("%s(%p, %p, %p, %d, %p, %p)\n", __FUNCTION__, DeviceInfoSet,
3023  DeviceInterfaceData, DeviceInterfaceDetailData,
3024  DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3025 
3027  set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3028  {
3030  return FALSE;
3031  }
3032  if (!DeviceInterfaceData ||
3033  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3034  !DeviceInterfaceData->Reserved)
3035  {
3037  return FALSE;
3038  }
3039  if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
3040  {
3042  return FALSE;
3043  }
3044  if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3045  {
3047  return FALSE;
3048  }
3050  {
3052  return FALSE;
3053  }
3054  if ((DeviceInterfaceDetailData != NULL)
3055  && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
3056  {
3058  return FALSE;
3059  }
3060  else
3061  {
3062  struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
3063  LPCWSTR devName = deviceInterface->SymbolicLink;
3064  DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
3065  (lstrlenW(devName) + 1) * sizeof(WCHAR);
3066 
3067  if (sizeRequired > DeviceInterfaceDetailDataSize)
3068  {
3070  if (RequiredSize)
3071  *RequiredSize = sizeRequired;
3072  }
3073  else
3074  {
3075  strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
3076  TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
3077  if (DeviceInfoData)
3078  {
3080  &deviceInterface->DeviceInfo->ClassGuid,
3081  sizeof(GUID));
3082  DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
3083  DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
3084  }
3085  ret = TRUE;
3086  }
3087  }
3088  return ret;
3089 }
3090 
3092 {
3096 };
3097 
3098 static struct PropertyMapEntry PropertyMap[] = {
3099  { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
3100  { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
3101  { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
3102  { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3103  { REG_SZ, "Service", REGSTR_VAL_SERVICE },
3104  { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3105  { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3106  { REG_SZ, "Class", REGSTR_VAL_CLASS },
3107  { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
3108  { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
3109  { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
3110  { REG_SZ, "Mfg", REGSTR_VAL_MFG },
3111  { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
3112  { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
3113  { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3114  { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
3115  { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
3116  { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
3117  { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
3118  { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
3119  { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
3120  { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
3121  { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
3122  { REG_BINARY, "Security", REGSTR_SECURITY },
3123  { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
3124  { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
3125  { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
3126  { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
3127  { 0, NULL, NULL }, /* SPDRP_ADDRESS */
3128  { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
3129  { 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
3130  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
3131  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
3132  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
3133  { 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
3134 };
3135 
3136 /***********************************************************************
3137  * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3138  */
3142  DWORD Property,
3147 {
3148  BOOL ret;
3149  BOOL bIsStringProperty;
3150  DWORD RegType;
3151  DWORD RequiredSizeA, RequiredSizeW;
3152  DWORD PropertyBufferSizeW = 0;
3153  PBYTE PropertyBufferW = NULL;
3154 
3155  TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3157  RequiredSize);
3158 
3159  if (PropertyBufferSize != 0)
3160  {
3161  PropertyBufferSizeW = PropertyBufferSize * 2;
3162  PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
3163  if (!PropertyBufferW)
3164  {
3166  return FALSE;
3167  }
3168  }
3169 
3172  Property,
3173  &RegType,
3174  PropertyBufferW,
3175  PropertyBufferSizeW,
3176  &RequiredSizeW);
3177 
3179  {
3180  bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
3181 
3182  if (bIsStringProperty)
3183  RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
3184  else
3185  RequiredSizeA = RequiredSizeW;
3186  if (RequiredSize)
3187  *RequiredSize = RequiredSizeA;
3188  if (PropertyRegDataType)
3189  *PropertyRegDataType = RegType;
3190  }
3191 
3192  if (!ret)
3193  {
3194  HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3195  return ret;
3196  }
3197 
3198  if (RequiredSizeA <= PropertyBufferSize)
3199  {
3200  if (bIsStringProperty && PropertyBufferSize > 0)
3201  {
3202  if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
3203  {
3204  /* Last error is already set by WideCharToMultiByte */
3205  ret = FALSE;
3206  }
3207  }
3208  else
3209  memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
3210  }
3211  else
3212  {
3214  ret = FALSE;
3215  }
3216 
3217  HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3218  return ret;
3219 }
3220 
3221 /***********************************************************************
3222  * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3223  */
3227  DWORD Property,
3232 {
3233  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3234  struct DeviceInfo *devInfo;
3235  CONFIGRET cr;
3236  LONG lError = ERROR_SUCCESS;
3237  DWORD size;
3238 
3239  TRACE("%s(%p %p %d %p %p %d %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData,
3241  RequiredSize);
3242 
3244  {
3246  return FALSE;
3247  }
3248  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3249  {
3251  return FALSE;
3252  }
3254  || !DeviceInfoData->Reserved)
3255  {
3257  return FALSE;
3258  }
3259 
3261  {
3263  return FALSE;
3264  }
3265 
3266  devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3267 
3268  if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3270  {
3271  HKEY hKey;
3273  hKey = SETUPDI_OpenDevKey(set->HKLM, devInfo, KEY_QUERY_VALUE);
3274  if (hKey == INVALID_HANDLE_VALUE)
3275  return FALSE;
3278  RegCloseKey(hKey);
3279 
3280  if (RequiredSize)
3281  *RequiredSize = size;
3282 
3283  switch (lError)
3284  {
3285  case ERROR_SUCCESS:
3286  if (PropertyBuffer == NULL && size != 0)
3287  lError = ERROR_INSUFFICIENT_BUFFER;
3288  break;
3289  case ERROR_MORE_DATA:
3290  lError = ERROR_INSUFFICIENT_BUFFER;
3291  break;
3292  default:
3293  break;
3294  }
3295  }
3297  {
3298  size = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
3299 
3300  if (PropertyRegDataType)
3302  if (RequiredSize)
3303  *RequiredSize = size;
3304  if (PropertyBufferSize >= size)
3305  {
3306  strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
3307  }
3308  else
3309  lError = ERROR_INSUFFICIENT_BUFFER;
3310  }
3311  else
3312  {
3314 
3319  &size,
3320  0,
3321  set->hMachine);
3322  if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL))
3323  {
3324  if (RequiredSize)
3325  *RequiredSize = size;
3326  }
3327 
3328  if (cr != CR_SUCCESS)
3329  {
3330  switch (cr)
3331  {
3332  case CR_INVALID_DEVINST:
3333  lError = ERROR_NO_SUCH_DEVINST;
3334  break;
3335 
3336  case CR_INVALID_PROPERTY:
3337  lError = ERROR_INVALID_REG_PROPERTY;
3338  break;
3339 
3340  case CR_BUFFER_SMALL:
3341  lError = ERROR_INSUFFICIENT_BUFFER;
3342  break;
3343 
3344  default :
3345  lError = ERROR_INVALID_DATA;
3346  break;
3347  }
3348  }
3349  }
3350 
3351  SetLastError(lError);
3352  return (lError == ERROR_SUCCESS);
3353 }
3354 
3355 /***********************************************************************
3356  * Internal for SetupDiSetDeviceRegistryPropertyA/W
3357  */
3361  DWORD Property,
3362  const BYTE *PropertyBuffer,
3364  BOOL isAnsi)
3365 {
3366  BOOL ret = FALSE;
3367  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3368  struct DeviceInfo *deviceInfo;
3369 
3370  TRACE("%s(%p %p %d %p %d)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, Property,
3372 
3374  {
3376  return FALSE;
3377  }
3378  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3379  {
3381  return FALSE;
3382  }
3384  || !DeviceInfoData->Reserved)
3385  {
3387  return FALSE;
3388  }
3389 
3390  deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3391 
3392  if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3394  && PropertyMap[Property].nameA)
3395  {
3396  HKEY hKey;
3397  LONG l;
3398  hKey = SETUPDI_OpenDevKey(set->HKLM, deviceInfo, KEY_SET_VALUE);
3399  if (hKey == INVALID_HANDLE_VALUE)
3400  return FALSE;
3401  /* Write new data */
3402  if (isAnsi)
3403  {
3404  l = RegSetValueExA(
3405  hKey, PropertyMap[Property].nameA, 0,
3408  }
3409  else
3410  {
3411  l = RegSetValueExW(
3415  }
3416  if (!l)
3417  ret = TRUE;
3418  else
3419  SetLastError(l);
3420  RegCloseKey(hKey);
3421  }
3422  else
3423  {
3424  ERR("Property 0x%lx not implemented\n", Property);
3426  }
3427 
3428  TRACE("Returning %d\n", ret);
3429  return ret;
3430 }
3431 /***********************************************************************
3432  * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3433  */
3437  DWORD Property,
3438  const BYTE *PropertyBuffer,
3440 {
3443  Property,
3446  TRUE);
3447 }
3448 
3449 /***********************************************************************
3450  * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3451  */
3455  DWORD Property,
3456  const BYTE *PropertyBuffer,
3458 {
3461  Property,
3464  FALSE);
3465 }
3466 
3467 /***********************************************************************
3468  * SetupDiInstallClassA (SETUPAPI.@)
3469  */
3471  HWND hwndParent,
3472  PCSTR InfFileName,
3473  DWORD Flags,
3474  HSPFILEQ FileQueue)
3475 {
3476  return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3477 }
3478 
3479 /***********************************************************************
3480  * SetupDiInstallClassExA (SETUPAPI.@)
3481  */
3482 BOOL WINAPI
3485  IN PCSTR InfFileName OPTIONAL,
3486  IN DWORD Flags,
3487  IN HSPFILEQ FileQueue OPTIONAL,
3489  IN PVOID Reserved1,
3490  IN PVOID Reserved2)
3491 {
3492  PWSTR InfFileNameW = NULL;
3493  BOOL Result;
3494 
3495  if (!InfFileName)
3496  {
3498  return FALSE;
3499  }
3500  else
3501  {
3502  InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
3503  if (InfFileNameW == NULL)
3504  {
3506  return FALSE;
3507  }
3508  }
3509 
3510  Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3511  FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3512 
3513  MyFree(InfFileNameW);
3514 
3515  return Result;
3516 }
3517 
3519 {
3520  WCHAR FullBuffer[MAX_PATH];
3523  HKEY hClassKey;
3525 
3526  /* Obtain the Class GUID for this class */
3527  if (!SetupGetLineTextW(NULL,
3528  hInf,
3529  Version,
3531  Buffer,
3532  sizeof(Buffer) / sizeof(WCHAR),
3533  &RequiredSize))
3534  {
3535  return INVALID_HANDLE_VALUE;
3536  }
3537 
3538  /* Build the corresponding registry key name */
3539  lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3540  lstrcatW(FullBuffer, BackSlash);
3541  lstrcatW(FullBuffer, Buffer);
3542 
3543  /* Obtain the Class name for this class */
3544  if (!SetupGetLineTextW(NULL,
3545  hInf,
3546  Version,
3548  Buffer,
3549  sizeof(Buffer) / sizeof(WCHAR),
3550  &RequiredSize))
3551  {
3552  return INVALID_HANDLE_VALUE;
3553  }
3554 
3555  /* Try to open or create the registry key */
3556  TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
3557 #if 0 // I keep this for reference...
3559  FullBuffer,
3560  0,
3561  KEY_SET_VALUE,
3562  &hClassKey))
3563  {
3564  /* Use RegCreateKeyExW */
3565  }
3566 #endif
3568  FullBuffer,
3569  0,
3570  NULL,
3572  KEY_SET_VALUE,
3573  NULL,
3574  &hClassKey,
3575  &Disposition))
3576  {
3577  ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
3578  return INVALID_HANDLE_VALUE;
3579  }
3581  TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
3582  else
3583  TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
3584 
3585  TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
3588  0,
3589  REG_SZ,
3590  (LPBYTE)Buffer,
3591  RequiredSize * sizeof(WCHAR)))
3592  {
3595  FullBuffer);
3596  return INVALID_HANDLE_VALUE;
3597  }
3598 
3599  return hClassKey;
3600 }
3601 
3602 /***********************************************************************
3603  * SetupDiInstallClassW (SETUPAPI.@)
3604  */
3606  HWND hwndParent,
3607  PCWSTR InfFileName,
3608  DWORD Flags,
3609  HSPFILEQ FileQueue)
3610 {
3611  return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3612 }
3613 
3614 
3615 /***********************************************************************
3616  * SetupDiOpenClassRegKey (SETUPAPI.@)
3617  */
3619  const GUID* ClassGuid,
3620  REGSAM samDesired)
3621 {
3622  return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3624 }
3625 
3626 
3627 /***********************************************************************
3628  * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3629  */
3631  const GUID* ClassGuid,
3632  REGSAM samDesired,
3633  DWORD Flags,
3635  PVOID Reserved)
3636 {
3637  PWSTR MachineNameW = NULL;
3638  HKEY hKey;
3639 
3640  TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3642 
3643  if (MachineName)
3644  {
3645  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3646  if (MachineNameW == NULL)
3647  return INVALID_HANDLE_VALUE;
3648  }
3649 
3651  Flags, MachineNameW, Reserved);
3652 
3653  MyFree(MachineNameW);
3654 
3655  return hKey;
3656 }
3657 
3658 
3659 /***********************************************************************
3660  * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3661  */
3663  const GUID* ClassGuid,
3664  REGSAM samDesired,
3665  DWORD Flags,
3667  PVOID Reserved)
3668 {
3669  HKEY HKLM;
3670  HKEY hClassesKey;
3671  HKEY key;
3672  LPCWSTR lpKeyName;
3673  LONG l;
3674 
3675  TRACE("%s(%s 0x%lx 0x%lx %s %p)\n", __FUNCTION__, debugstr_guid(ClassGuid), samDesired,
3677 
3678  if (MachineName != NULL)
3679  {
3681  if (l != ERROR_SUCCESS)
3682  {
3683  SetLastError(l);
3684  return INVALID_HANDLE_VALUE;
3685  }
3686  }
3687  else
3689 
3690  if (Flags == DIOCR_INSTALLER)
3691  {
3692  lpKeyName = REGSTR_PATH_CLASS_NT;
3693  }
3694  else if (Flags == DIOCR_INTERFACE)
3695  {
3696  lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3697  }
3698  else
3699  {
3700  ERR("Invalid Flags parameter!\n");
3702  if (MachineName != NULL) RegCloseKey(HKLM);
3703  return INVALID_HANDLE_VALUE;
3704  }
3705 
3706  if (!ClassGuid)
3707  {
3708  if ((l = RegOpenKeyExW(HKLM,
3709  lpKeyName,
3710  0,
3711  samDesired,
3712  &hClassesKey)))
3713  {
3715  hClassesKey = INVALID_HANDLE_VALUE;
3716  }
3717  if (MachineName != NULL)
3718  RegCloseKey(HKLM);
3719  key = hClassesKey;
3720  }
3721  else
3722  {
3723  WCHAR bracedGuidString[39];
3724 
3725  SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3726 
3727  if (!(l = RegOpenKeyExW(HKLM,
3728  lpKeyName,
3729  0,
3730  samDesired,
3731  &hClassesKey)))
3732  {
3733  if (MachineName != NULL)
3734  RegCloseKey(HKLM);
3735 
3736  if ((l = RegOpenKeyExW(hClassesKey,
3737  bracedGuidString,
3738  0,
3739  samDesired,
3740  &key)))
3741  {
3742  SetLastError(l);
3744  }
3745  RegCloseKey(hClassesKey);
3746  }
3747  else
3748  {
3749  if (MachineName != NULL) RegCloseKey(HKLM);
3750  SetLastError(l);
3752  }
3753  }
3754 
3755  return key;
3756 }
3757 
3758 /***********************************************************************
3759  * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3760  */
3763  PCWSTR DevicePath,
3764  DWORD OpenFlags,
3765  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3766 {
3767  struct DeviceInfoSet * list;
3768  PCWSTR pEnd;
3769  DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3770  CLSID ClassId;
3771  WCHAR Buffer[MAX_PATH + 1];
3772  WCHAR SymBuffer[MAX_PATH + 1];
3773  WCHAR InstancePath[MAX_PATH + 1];
3774  HKEY hKey, hDevKey, hSymKey;
3775  struct DeviceInfo * deviceInfo;
3776  struct DeviceInterface *deviceInterface;
3777  BOOL Ret;
3778  PLIST_ENTRY ItemList;
3779  PLIST_ENTRY InterfaceListEntry;
3780 
3781  TRACE("%s(%p %s %08x %p)\n", __FUNCTION__,
3782  DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3783 
3784 
3785  if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3786  {
3788  return FALSE;
3789  }
3790 
3792  {
3794  return FALSE;
3795  }
3796 
3797  list = (struct DeviceInfoSet * )DeviceInfoSet;
3798 
3799  dwLength = wcslen(DevicePath);
3800  if (dwLength < 39)
3801  {
3802  /* path must be at least a guid length + L'\0' */
3804  return FALSE;
3805  }
3806 
3807  if (DevicePath[0] != L'\\' ||
3808  DevicePath[1] != L'\\' ||
3809  (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3810  DevicePath[3] != L'\\')
3811  {
3812  /* invalid formatted path */
3814  return FALSE;
3815  }
3816 
3817  /* check for reference strings */
3818  pEnd = wcschr(&DevicePath[4], L'\\');
3819  if (!pEnd)
3820  {
3821  /* no reference string */
3822  pEnd = DevicePath + dwLength;
3823  }
3824 
3825  /* copy guid */
3826  wcscpy(Buffer, pEnd - 37);
3827  Buffer[36] = L'\0';
3828 
3829  dwError = UuidFromStringW(Buffer, &ClassId);
3830  if (dwError != NOERROR)
3831  {
3832  /* invalid formatted path */
3834  return FALSE;
3835  }
3836 
3837  hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
3838 
3839  if (hKey == INVALID_HANDLE_VALUE)
3840  {
3841  /* invalid device class */
3842  return FALSE;
3843  }
3844 
3845  ItemList = list->ListHead.Flink;
3846  while (ItemList != &list->ListHead)
3847  {
3848  deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3849  InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3850  while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3851  {
3852  deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3853  if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3854  {
3855  InterfaceListEntry = InterfaceListEntry->Flink;
3856  continue;
3857  }
3858 
3859  if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3860  {
3861  if (DeviceInterfaceData)
3862  {
3863  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3864  DeviceInterfaceData->Flags = deviceInterface->Flags;
3865  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3866  }
3867 
3868  return TRUE;
3869  }
3870 
3871  }
3872  }
3873 
3874 
3875  dwIndex = 0;
3876  do
3877  {
3878  Buffer[0] = 0;
3879  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3880  dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3881 
3882  if (dwError != ERROR_SUCCESS)
3883  break;
3884 
3885  if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3886  break;
3887 
3888  dwSubIndex = 0;
3889  InstancePath[0] = 0;
3890  dwKeyName = sizeof(InstancePath);
3891 
3892  dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3893 
3894  while(TRUE)
3895  {
3896  Buffer[0] = 0;
3897  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3898  dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3899 
3900  if (dwError != ERROR_SUCCESS)
3901  break;
3902 
3903  dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3904  if (dwError != ERROR_SUCCESS)
3905  break;
3906 
3907  /* query for symbolic link */
3908  dwKeyName = sizeof(SymBuffer);
3909  SymBuffer[0] = L'\0';
3910  dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
3911 
3912  if (dwError != ERROR_SUCCESS)
3913  {
3914  RegCloseKey(hSymKey);
3915  break;
3916  }
3917 
3918  if (!wcsicmp(SymBuffer, DevicePath))
3919  {
3920  Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
3921  RegCloseKey(hSymKey);
3922  RegCloseKey(hDevKey);
3923  RegCloseKey(hKey);
3924 
3925  if (Ret)
3926  {
3927  deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
3928  if (deviceInterface)
3929  {
3930 
3931  CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
3932  deviceInterface->DeviceInfo = deviceInfo;
3933  deviceInterface->Flags = SPINT_ACTIVE; //FIXME
3934 
3935  wcscpy(deviceInterface->SymbolicLink, SymBuffer);
3936 
3937  InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
3938  InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
3939 
3940 
3941  if (DeviceInterfaceData)
3942  {
3943  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3944  DeviceInterfaceData->Flags = deviceInterface->Flags;
3945  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3946  }
3947  else
3948  {
3949  Ret = FALSE;
3951  }
3952  }
3953  }
3954  else
3955  {
3956  HeapFree(GetProcessHeap(), 0, deviceInfo);
3957  Ret = FALSE;
3958  }
3959  return Ret;
3960  }
3961  RegCloseKey(hSymKey);
3962  dwSubIndex++;
3963  }
3964 
3965  RegCloseKey(hDevKey);
3966  dwIndex++;
3967  } while(TRUE);
3968 
3969  RegCloseKey(hKey);
3970  return FALSE;
3971 }
3972 
3973 /***********************************************************************
3974  * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
3975  */
3978  PCSTR DevicePath,
3979  DWORD OpenFlags,
3980  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3981 {
3982  LPWSTR DevicePathW = NULL;
3983  BOOL bResult;
3984 
3985  TRACE("%s(%p %s %08lx %p)\n", __FUNCTION__, DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
3986 
3987  DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
3988  if (DevicePathW == NULL)
3989  return FALSE;
3990 
3992  DevicePathW, OpenFlags, DeviceInterfaceData);
3993 
3994  MyFree(DevicePathW);
3995 
3996  return bResult;
3997 }
3998 
3999 /***********************************************************************
4000  * SetupDiSetClassInstallParamsA (SETUPAPI.@)
4001  */
4007 {
4008  FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4009  ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4010  return FALSE;
4011 }
4012 
4013 static BOOL WINAPI
4017 {
4019 }
4020 
4021 /***********************************************************************
4022  * SetupDiCallClassInstaller (SETUPAPI.@)
4023  */
4025  DI_FUNCTION InstallFunction,
4028 {
4029  BOOL ret = FALSE;
4030 
4031  TRACE("%s(%u %p %p)\n", __FUNCTION__, InstallFunction, DeviceInfoSet, DeviceInfoData);
4032 
4033  if (!DeviceInfoSet)
4039  else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4041  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4043  else
4044  {
4046 #define CLASS_COINSTALLER 0x1
4047 #define DEVICE_COINSTALLER 0x2
4048 #define CLASS_INSTALLER 0x4
4049  UCHAR CanHandle = 0;
4051 
4052  switch (InstallFunction)
4053  {
4056  break;
4059  break;
4060  case DIF_ALLOW_INSTALL:
4061  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4062  break;
4063  case DIF_DETECT:
4064  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4065  break;
4067  CanHandle = CLASS_INSTALLER;
4068  break;
4069  case DIF_INSTALLDEVICE:
4072  break;
4074  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4076  break;
4077  case DIF_INSTALLINTERFACES:
4080  break;
4083  break;
4085  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4086  break;
4088  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4089  break;
4091  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4092  break;
4094  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4095  break;
4096  case DIF_POWERMESSAGEWAKE:
4098  break;
4099  case DIF_PROPERTYCHANGE:
4102  break;
4104  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4106  break;
4107  case DIF_REGISTERDEVICE:
4108  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4110  break;
4111  case DIF_REMOVE:
4114  break;
4116  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4118  break;
4119  case DIF_SELECTDEVICE:
4120  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4122  break;
4123  case DIF_TROUBLESHOOTER:
4125  break;
4126  case DIF_UNREMOVE:
4129  break;
4130  default:
4131  ERR("Install function %u not supported\n", InstallFunction);
4133  }
4134 
4137  /* Don't process this call, as a parameter is invalid */
4138  CanHandle = 0;
4139 
4140  if (CanHandle != 0)
4141  {
4142  LIST_ENTRY ClassCoInstallersListHead;
4143  LIST_ENTRY DeviceCoInstallersListHead;
4144  HMODULE ClassInstallerLibrary = NULL;
4145  CLASS_INSTALL_PROC ClassInstaller = NULL;
4147  PLIST_ENTRY ListEntry;
4148  HKEY hKey;
4149  DWORD dwRegType, dwLength;
4150  DWORD rc = NO_ERROR;
4151 
4152  InitializeListHead(&ClassCoInstallersListHead);
4153  InitializeListHead(&DeviceCoInstallersListHead);
4154 
4155  if (CanHandle & DEVICE_COINSTALLER)
4156  {
4158  if (hKey != INVALID_HANDLE_VALUE)
4159  {
4161  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4162  {
4163  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4164  if (KeyBuffer != NULL)
4165  {
4167  if (rc == ERROR_SUCCESS)
4168  {
4169  LPWSTR ptr;
4170  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4171  {
4172  /* Add coinstaller to DeviceCoInstallersListHead list */
4173  struct CoInstallerElement *coinstaller;
4174  TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4175  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4176  if (!coinstaller)
4177  continue;
4178  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4179  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4180  InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4181  else
4182  HeapFree(GetProcessHeap(), 0, coinstaller);
4183  }
4184  }
4185  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4186  }
4187  }
4188  RegCloseKey(hKey);
4189  }
4190  }
4191  if (CanHandle & CLASS_COINSTALLER)
4192  {
4193  rc = RegOpenKeyExW(
4196  0, /* Options */
4198  &hKey);
4199  if (rc == ERROR_SUCCESS)
4200  {
4201  WCHAR szGuidString[40];
4202  if (pSetupStringFromGuid(&DeviceInfoData->ClassGuid, szGuidString, ARRAYSIZE(szGuidString)) == ERROR_SUCCESS)
4203  {
4204  rc = RegQueryValueExW(hKey, szGuidString, NULL, &dwRegType, NULL, &dwLength);
4205  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4206  {
4207  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4208  if (KeyBuffer != NULL)
4209  {
4210  rc = RegQueryValueExW(hKey, szGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4211  if (rc == ERROR_SUCCESS)
4212  {
4213  LPWSTR ptr;
4214  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4215  {
4216  /* Add coinstaller to ClassCoInstallersListHead list */
4217  struct CoInstallerElement *coinstaller;
4218  TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4219  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4220  if (!coinstaller)
4221  continue;
4222  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4223  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4224  InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4225  else
4226  HeapFree(GetProcessHeap(), 0, coinstaller);
4227  }
4228  }
4229  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4230  }
4231  }
4232  }
4233  RegCloseKey(hKey);
4234  }
4235  }
4236  if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4237  {
4239  if (hKey != INVALID_HANDLE_VALUE)
4240  {
4242  if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4243  {
4244  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4245  if (KeyBuffer != NULL)
4246  {
4248  if (rc == ERROR_SUCCESS)
4249  {
4250  /* Get ClassInstaller function pointer */
4251  TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4252  if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4253  {
4254  InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4256  }
4257  }
4258  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4259  }
4260  }
4261  RegCloseKey(hKey);
4262  }
4263  }
4264 
4265  /* Call Class co-installers */
4266  Context.PostProcessing = FALSE;
4267  rc = NO_ERROR;
4268  ListEntry = ClassCoInstallersListHead.Flink;
4269  while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4270  {
4271  struct CoInstallerElement *coinstaller;
4272  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4273  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4274  coinstaller->PrivateData = Context.PrivateData;
4276  {
4277  coinstaller->DoPostProcessing = TRUE;
4278  rc = NO_ERROR;
4279  }
4281  }
4282 
4283  /* Call Device co-installers */
4284  ListEntry = DeviceCoInstallersListHead.Flink;
4285  while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4286  {
4287  struct CoInstallerElement *coinstaller;
4288  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4289  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4290  coinstaller->PrivateData = Context.PrivateData;
4292  {
4293  coinstaller->DoPostProcessing = TRUE;
4294  rc = NO_ERROR;
4295  }
4297  }
4298 
4299  /* Call Class installer */
4300  if (ClassInstaller)
4301  {
4302  rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4303  FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4304  }
4305  else
4306  rc = ERROR_DI_DO_DEFAULT;
4307 
4308  /* Call default handler */
4309  if (rc == ERROR_DI_DO_DEFAULT)
4310  {
4311  if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4312  {
4314  rc = NO_ERROR;
4315  else
4316  rc = GetLastError();
4317  }
4318  else
4319  rc = NO_ERROR;
4320  }
4321 
4322  /* Call Class co-installers that required postprocessing */
4323  Context.PostProcessing = TRUE;
4324  ListEntry = ClassCoInstallersListHead.Flink;
4325  while (ListEntry != &ClassCoInstallersListHead)
4326  {
4327  struct CoInstallerElement *coinstaller;
4328  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4329  if (coinstaller->DoPostProcessing)
4330  {
4331  Context.InstallResult = rc;
4332  Context.PrivateData = coinstaller->PrivateData;
4333  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4334  }
4335  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4337  }
4338 
4339  /* Call Device co-installers that required postprocessing */
4340  ListEntry = DeviceCoInstallersListHead.Flink;
4341  while (ListEntry != &DeviceCoInstallersListHead)
4342  {
4343  struct CoInstallerElement *coinstaller;
4344  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4345  if (coinstaller->DoPostProcessing)
4346  {
4347  Context.InstallResult = rc;
4348  Context.PrivateData = coinstaller->PrivateData;
4349  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4350  }
4351  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4353  }
4354 
4355  /* Free allocated memory */
4356  while (!IsListEmpty(&ClassCoInstallersListHead))
4357  {
4358  ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4360  }
4361  while (!IsListEmpty(&DeviceCoInstallersListHead))
4362  {
4363  ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4365  }
4366 
4367  ret = (rc == NO_ERROR);
4368  }
4369  }
4370 
4371  TRACE("Returning %d\n", ret);
4372  return ret;
4373 }
4374 
4375 /***********************************************************************
4376  * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4377  */
4382 {
4383  SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4384  BOOL ret = FALSE;
4385 
4387 
4388  if (DeviceInstallParams == NULL)
4390  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4392  else
4393  {
4394  deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4396 
4397  if (ret)
4398  {
4399  /* Do W->A conversion */
4400  memcpy(
4402  &deviceInstallParamsW,
4403  FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4404  if (