ReactOS  r75907
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 /* Unicode constants */
25 static const WCHAR BackSlash[] = {'\\',0};
26 static const WCHAR DateFormat[] = {'%','u','-','%','u','-','%','u',0};
27 static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
28 static const WCHAR DotHW[] = {'.','H','W',0};
29 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
30 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
31 static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
32 static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
33 static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
34 
35 static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
36 static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
37 static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
38 static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
39 static const WCHAR REGSTR_UI_NUMBER_DESC_FORMAT[] = {'U','I','N','u','m','b','e','r','D','e','s','c','F','o','r','m','a','t',0};
40 
41 typedef DWORD
42 (CALLBACK* CLASS_INSTALL_PROC) (
43  IN DI_FUNCTION InstallFunction,
46 typedef BOOL
47 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
50 typedef DWORD
51 (CALLBACK* COINSTALLER_PROC) (
52  IN DI_FUNCTION InstallFunction,
56 
58 {
60 
62  COINSTALLER_PROC Function;
65 };
66 
68 {
75 };
76 
77 
78 
80 {
81  static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
82  '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
83  'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
84  '0','2','X','}',0};
85 
86  sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
87  guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
88  guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
89 }
90 
91 static DWORD
93 {
94  switch (cr)
95  {
99  case CR_FAILURE: return ERROR_GEN_FAILURE;
113  case CR_SUCCESS: return ERROR_SUCCESS;
114  default: return ERROR_GEN_FAILURE;
115  }
116 
117  /* Does not happen */
118 }
119 
120 /* Lower scores are best ones */
121 static BOOL
123  IN LPCWSTR SectionName,
124  IN PSP_ALTPLATFORM_INFO PlatformInfo,
125  IN BYTE ProductType,
126  IN WORD SuiteMask,
127  OUT PDWORD ScorePlatform,
128  OUT PDWORD ScoreMajorVersion,
129  OUT PDWORD ScoreMinorVersion,
130  OUT PDWORD ScoreProductType,
131  OUT PDWORD ScoreSuiteMask)
132 {
133  LPWSTR Section = NULL;
134  //LPCWSTR pExtensionPlatform;
135  LPCWSTR pExtensionArchitecture;
136  LPWSTR Fields[6];
137  DWORD i;
138  BOOL ret = FALSE;
139 
140  //static const WCHAR ExtensionPlatformNone[] = {'.',0};
141  static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
142  static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
143 
144  static const WCHAR ExtensionArchitectureNone[] = {0};
145  static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
146  static const WCHAR ExtensionArchitectureamd64[] = {'A','M','D','6','4',0};
147  static const WCHAR ExtensionArchitectureia64[] = {'I','A','6','4',0};
148  static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
149  static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
150  static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
151 
152  TRACE("%s %p 0x%x 0x%x\n",
153  debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
154 
155  *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
156 
157  Section = pSetupDuplicateString(SectionName);
158  if (!Section)
159  {
160  TRACE("pSetupDuplicateString() failed\n");
161  goto cleanup;
162  }
163 
164  /* Set various extensions values */
165  switch (PlatformInfo->Platform)
166  {
168  //pExtensionPlatform = ExtensionPlatformWindows;
169  break;
171  //pExtensionPlatform = ExtensionPlatformNT;
172  break;
173  default:
174  ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
175  //pExtensionPlatform = ExtensionPlatformNone;
176  break;
177  }
178  switch (PlatformInfo->ProcessorArchitecture)
179  {
181  pExtensionArchitecture = ExtensionArchitecturealpha;
182  break;
184  pExtensionArchitecture = ExtensionArchitectureamd64;
185  break;
187  pExtensionArchitecture = ExtensionArchitectureia64;
188  break;
190  pExtensionArchitecture = ExtensionArchitecturex86;
191  break;
193  pExtensionArchitecture = ExtensionArchitecturemips;
194  break;
196  pExtensionArchitecture = ExtensionArchitectureppc;
197  break;
198  default:
199  ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
201  pExtensionArchitecture = ExtensionArchitectureNone;
202  break;
203  }
204 
205  /*
206  * Field[0] Platform
207  * Field[1] Architecture
208  * Field[2] Major version
209  * Field[3] Minor version
210  * Field[4] Product type
211  * Field[5] Suite mask
212  * Remark: these fields may be NULL if the information is not provided
213  */
214  Fields[0] = Section;
215  if (Fields[0] == NULL)
216  {
217  TRACE("No extension found\n");
218  *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
219  ret = TRUE;
220  goto cleanup;
221  }
222  Fields[1] = Fields[0] + 1;
223  Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
224  for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
225  {
226  Fields[i] = wcschr(Fields[i - 1], '.');
227  if (Fields[i])
228  {
229  Fields[i]++;
230  *(Fields[i] - 1) = UNICODE_NULL;
231  }
232  }
233  /* Take care of first 2 fields */
234  if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
235  {
236  if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
237  {
238  TRACE("Mismatch on platform field\n");
239  goto cleanup;
240  }
241  Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
242  }
243  else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
244  {
245  if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
246  {
247  TRACE("Mismatch on platform field\n");
248  goto cleanup;
249  }
250  Fields[1] += wcslen(ExtensionPlatformNT) - 1;
251  }
252  else
253  {
254  /* No platform specified */
255  *ScorePlatform |= 0x02;
256  }
257  if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
258  {
259  /* No architecture specified */
260  *ScorePlatform |= 0x01;
261  }
262  else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
263  {
264  TRACE("Mismatch on architecture field ('%s' and '%s')\n",
265  debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
266  goto cleanup;
267  }
268 
269  /* Check if informations are matching */
270  if (Fields[2] && *Fields[2])
271  {
273  MajorVersion = strtoulW(Fields[2], NULL, 0);
274  if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
275  (errno == ERANGE || errno == EINVAL))
276  {
277  TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
278  goto cleanup;
279  }
280  if (Fields[3] && *Fields[3])
281  {
282  MinorVersion = strtoulW(Fields[3], NULL, 0);
283  if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
284  (errno == ERANGE || errno == EINVAL))
285  {
286  TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
287  goto cleanup;
288  }
289  }
290  if (PlatformInfo->MajorVersion < MajorVersion ||
291  (PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
292  {
293  TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
294  MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
295  goto cleanup;
296  }
297  *ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
298  if (MajorVersion == PlatformInfo->MajorVersion)
299  *ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
300  else
301  *ScoreMinorVersion = MinorVersion;
302  }
303  else if (Fields[3] && *Fields[3])
304  {
305  TRACE("Minor version found without major version\n");
306  goto cleanup;
307  }
308  else
309  {
310  *ScoreMajorVersion = PlatformInfo->MajorVersion;
311  *ScoreMinorVersion = PlatformInfo->MinorVersion;
312  }
313 
314  if (Fields[4] && *Fields[4])
315  {
316  DWORD CurrentProductType;
317  CurrentProductType = strtoulW(Fields[4], NULL, 0);
318  if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
319  (errno == ERANGE || errno == EINVAL))
320  {
321  TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
322  goto cleanup;
323  }
324  if (CurrentProductType != ProductType)
325  {
326  TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
327  CurrentProductType, ProductType);
328  goto cleanup;
329  }
330  }
331  else
332  *ScoreProductType = 1;
333 
334  if (Fields[5] && *Fields[5])
335  {
336  DWORD CurrentSuiteMask;
337  CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
338  if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
339  (errno == ERANGE || errno == EINVAL))
340  {
341  TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
342  goto cleanup;
343  }
344  if ((CurrentSuiteMask & ~SuiteMask) != 0)
345  {
346  TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
347  CurrentSuiteMask, SuiteMask);
348  goto cleanup;
349  }
350  *ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
351  }
352  else
353  *ScoreSuiteMask = SuiteMask;
354 
355  ret = TRUE;
356 
357 cleanup:
358  MyFree(Section);
359  return ret;
360 }
361 
362 static BOOL
364  IN LPCWSTR SectionName,
365  IN PVOID Context)
366 {
368  DWORD Score1, Score2, Score3, Score4, Score5;
369  BOOL ret;
370 
371  if (SectionName[info->PrefixLength] != '.')
372  return TRUE;
373 
374  ret = CheckSectionValid(
375  &SectionName[info->PrefixLength],
376  info->PlatformInfo,
377  info->ProductType,
378  info->SuiteMask,
379  &Score1, &Score2, &Score3, &Score4, &Score5);
380  if (!ret)
381  {
382  TRACE("Section %s not compatible\n", debugstr_w(SectionName));
383  return TRUE;
384  }
385  if (Score1 > info->BestScore1) goto done;
386  if (Score1 < info->BestScore1) goto bettersection;
387  if (Score2 > info->BestScore2) goto done;
388  if (Score2 < info->BestScore2) goto bettersection;
389  if (Score3 > info->BestScore3) goto done;
390  if (Score3 < info->BestScore3) goto bettersection;
391  if (Score4 > info->BestScore4) goto done;
392  if (Score4 < info->BestScore4) goto bettersection;
393  if (Score5 > info->BestScore5) goto done;
394  if (Score5 < info->BestScore5) goto bettersection;
395  goto done;
396 
397 bettersection:
398  strcpyW(info->BestSection, SectionName);
399  info->BestScore1 = Score1;
400  info->BestScore2 = Score2;
401  info->BestScore3 = Score3;
402  info->BestScore4 = Score4;
403  info->BestScore5 = Score5;
404 
405 done:
406  return TRUE;
407 }
408 
409 /***********************************************************************
410  * SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
411  */
412 BOOL WINAPI
414  IN HINF InfHandle,
415  IN PCWSTR InfSectionName,
416  IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
417  OUT PWSTR InfSectionWithExt OPTIONAL,
418  IN DWORD InfSectionWithExtSize,
419  OUT PDWORD RequiredSize OPTIONAL,
420  OUT PWSTR* Extension OPTIONAL,
421  IN PVOID Reserved)
422 {
423  BOOL ret = FALSE;
424 
425  TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
426  AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
427  RequiredSize, Extension, Reserved);
428 
429  if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
431  else if (!InfSectionName)
433  else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
435  else if (Reserved != NULL)
437  else
438  {
439  static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
440  static BYTE CurrentProductType = 0;
441  static WORD CurrentSuiteMask = 0;
442  PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
443  struct GetSectionCallbackInfo CallbackInfo;
444  DWORD dwFullLength;
446  WORD SuiteMask;
447 
448  /* Fill platform info if needed */
449  if (AlternatePlatformInfo)
450  {
451  pPlatformInfo = AlternatePlatformInfo;
452  ProductType = 0;
453  SuiteMask = 0;
454  }
455  else
456  {
457  if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
458  {
459  /* That's the first time we go here. We need to fill in the structure */
460  SYSTEM_INFO SystemInfo;
461  GetSystemInfo(&SystemInfo);
462  CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
463  CurrentPlatform.Platform = OsVersionInfo.dwPlatformId;
464  CurrentPlatform.MajorVersion = OsVersionInfo.dwMajorVersion;
465  CurrentPlatform.MinorVersion = OsVersionInfo.dwMinorVersion;
466  CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
467  CurrentPlatform.Reserved = 0;
468  CurrentProductType = OsVersionInfo.wProductType;
469  CurrentSuiteMask = OsVersionInfo.wSuiteMask;
470  }
471  ProductType = CurrentProductType;
472  SuiteMask = CurrentSuiteMask;
473  }
474 
475  CallbackInfo.PlatformInfo = pPlatformInfo;
476  CallbackInfo.ProductType = ProductType;
477  CallbackInfo.SuiteMask = SuiteMask;
478  CallbackInfo.PrefixLength = strlenW(InfSectionName);
479  CallbackInfo.BestScore1 = ULONG_MAX;
480  CallbackInfo.BestScore2 = ULONG_MAX;
481  CallbackInfo.BestScore3 = ULONG_MAX;
482  CallbackInfo.BestScore4 = ULONG_MAX;
483  CallbackInfo.BestScore5 = ULONG_MAX;
484  strcpyW(CallbackInfo.BestSection, InfSectionName);
485  TRACE("EnumerateSectionsStartingWith(InfSectionName = %S)\n", InfSectionName);
487  InfHandle,
488  InfSectionName,
490  &CallbackInfo))
491  {
493  goto done;
494  }
495  TRACE("CallbackInfo.BestSection = %S\n", CallbackInfo.BestSection);
496 
497  dwFullLength = lstrlenW(CallbackInfo.BestSection);
498  if (RequiredSize != NULL)
499  *RequiredSize = dwFullLength + 1;
500 
501  if (InfSectionWithExtSize > 0)
502  {
503  if (InfSectionWithExtSize < dwFullLength + 1)
504  {
506  goto done;
507  }
508  strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
509  if (Extension)
510  {
511  DWORD dwLength = lstrlenW(InfSectionName);
512  *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
513  }
514  }
515 
516  ret = TRUE;
517  }
518 
519 done:
520  TRACE("Returning %d\n", ret);
521  return ret;
522 }
523 
524 
525 BOOL
527  IN struct DeviceInfoSet *list,
528  IN LPCWSTR InstancePath,
529  IN LPCGUID pClassGuid,
530  OUT struct DeviceInfo **pDeviceInfo)
531 {
532  DWORD size;
533  CONFIGRET cr;
534  struct DeviceInfo *deviceInfo;
535 
536  *pDeviceInfo = NULL;
537 
538  size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
539  deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
540  if (!deviceInfo)
541  {
543  return FALSE;
544  }
545  ZeroMemory(deviceInfo, size);
546 
547  cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
548  if (cr != CR_SUCCESS)
549  {
551  return FALSE;
552  }
553 
554  deviceInfo->set = list;
555  deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
556  strcpyW(deviceInfo->Data, InstancePath);
557  deviceInfo->instanceId = deviceInfo->Data;
558  deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
559  deviceInfo->DeviceDescription = NULL;
560  memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
561  deviceInfo->CreationFlags = 0;
562  InitializeListHead(&deviceInfo->DriverListHead);
564 
565  *pDeviceInfo = deviceInfo;
566  return TRUE;
567 }
568 
569 
570 static BOOL
572 {
573  HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
574  HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
575  return TRUE;
576 }
577 
578 static BOOL
579 DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
580 {
582  struct DriverInfoElement *driverInfo;
583  struct DeviceInterface *deviceInterface;
584 
585  while (!IsListEmpty(&deviceInfo->DriverListHead))
586  {
587  ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
588  driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
589  if (!DestroyDriverInfoElement(driverInfo))
590  return FALSE;
591  }
592  while (!IsListEmpty(&deviceInfo->InterfaceListHead))
593  {
594  ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
595  deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
596  if (!DestroyDeviceInterface(deviceInterface))
597  return FALSE;
598  }
600  if (deviceInfo->hmodDevicePropPageProvider)
602  return HeapFree(GetProcessHeap(), 0, deviceInfo);
603 }
604 
605 static BOOL
607 {
609  struct DeviceInfo *deviceInfo;
610 
611  while (!IsListEmpty(&list->ListHead))
612  {
613  ListEntry = RemoveHeadList(&list->ListHead);
614  deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
615  if (!DestroyDeviceInfo(deviceInfo))
616  return FALSE;
617  }
618  if (list->HKLM != HKEY_LOCAL_MACHINE)
619  RegCloseKey(list->HKLM);
622  if (list->hmodClassPropPageProvider)
624  return HeapFree(GetProcessHeap(), 0, list);
625 }
626 
627 /***********************************************************************
628  * SetupDiBuildClassInfoList (SETUPAPI.@)
629  *
630  * Returns a list of setup class GUIDs that identify the classes
631  * that are installed on a local machine.
632  *
633  * PARAMS
634  * Flags [I] control exclusion of classes from the list.
635  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
636  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
637  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
638  *
639  * RETURNS
640  * Success: TRUE.
641  * Failure: FALSE.
642  */
644  DWORD Flags,
645  LPGUID ClassGuidList,
648 {
649  TRACE("\n");
650  return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
651  ClassGuidListSize, RequiredSize,
652  NULL, NULL);
653 }
654 
655 /***********************************************************************
656  * SetupDiBuildClassInfoListExA (SETUPAPI.@)
657  *
658  * Returns a list of setup class GUIDs that identify the classes
659  * that are installed on a local or remote machine.
660  *
661  * PARAMS
662  * Flags [I] control exclusion of classes from the list.
663  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
664  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
665  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
666  * MachineName [I] name of a remote machine.
667  * Reserved [I] must be NULL.
668  *
669  * RETURNS
670  * Success: TRUE.
671  * Failure: FALSE.
672  */
674  DWORD Flags,
675  LPGUID ClassGuidList,
679  PVOID Reserved)
680 {
681  LPWSTR MachineNameW = NULL;
682  BOOL bResult;
683 
684  TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
685  ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
686 
687  if (MachineName)
688  {
689  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
690  if (MachineNameW == NULL) return FALSE;
691  }
692 
693  bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
694  ClassGuidListSize, RequiredSize,
695  MachineNameW, Reserved);
696 
697  MyFree(MachineNameW);
698 
699  return bResult;
700 }
701 
702 /***********************************************************************
703  * SetupDiBuildClassInfoListExW (SETUPAPI.@)
704  *
705  * Returns a list of setup class GUIDs that identify the classes
706  * that are installed on a local or remote machine.
707  *
708  * PARAMS
709  * Flags [I] control exclusion of classes from the list.
710  * ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
711  * ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
712  * RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
713  * MachineName [I] name of a remote machine.
714  * Reserved [I] must be NULL.
715  *
716  * RETURNS
717  * Success: TRUE.
718  * Failure: FALSE.
719  */
721  DWORD Flags,
722  LPGUID ClassGuidList,
726  PVOID Reserved)
727 {
728  WCHAR szKeyName[40];
729  HKEY hClassesKey = INVALID_HANDLE_VALUE;
730  HKEY hClassKey;
731  DWORD dwLength;
732  DWORD dwIndex;
733  LONG lError;
734  DWORD dwGuidListIndex = 0;
735 
736  TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
737  ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
738 
739  if (!RequiredSize)
740  {
742  return FALSE;
743  }
744  else if (!ClassGuidList && ClassGuidListSize > 0)
745  {
747  return FALSE;
748  }
749 
750  hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
753  MachineName,
754  Reserved);
755  if (hClassesKey == INVALID_HANDLE_VALUE)
756  {
757  return FALSE;
758  }
759 
760  for (dwIndex = 0; ; dwIndex++)
761  {
762  dwLength = 40;
763  lError = RegEnumKeyExW(hClassesKey,
764  dwIndex,
765  szKeyName,
766  &dwLength,
767  NULL,
768  NULL,
769  NULL,
770  NULL);
771  TRACE("RegEnumKeyExW() returns %d\n", lError);
772  if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
773  {
774  TRACE("Key name: %s\n", debugstr_w(szKeyName));
775 
776  if (RegOpenKeyExW(hClassesKey,
777  szKeyName,
778  0,
780  &hClassKey))
781  {
782  RegCloseKey(hClassesKey);
783  return FALSE;
784  }
785 
786  if (!RegQueryValueExW(hClassKey,
788  NULL,
789  NULL,
790  NULL,
791  NULL))
792  {
793  TRACE("'NoUseClass' value found!\n");
794  RegCloseKey(hClassKey);
795  continue;
796  }
797 
798  if ((Flags & DIBCI_NOINSTALLCLASS) &&
799  (!RegQueryValueExW(hClassKey,
801  NULL,
802  NULL,
803  NULL,
804  NULL)))
805  {
806  TRACE("'NoInstallClass' value found!\n");
807  RegCloseKey(hClassKey);
808  continue;
809  }
810 
811  if ((Flags & DIBCI_NODISPLAYCLASS) &&
812  (!RegQueryValueExW(hClassKey,
814  NULL,
815  NULL,
816  NULL,
817  NULL)))
818  {
819  TRACE("'NoDisplayClass' value found!\n");
820  RegCloseKey(hClassKey);
821  continue;
822  }
823 
824  RegCloseKey(hClassKey);
825 
826  TRACE("Guid: %s\n", debugstr_w(szKeyName));
827  if (dwGuidListIndex < ClassGuidListSize)
828  {
829  if (szKeyName[0] == '{' && szKeyName[37] == '}')
830  {
831  szKeyName[37] = 0;
832  }
833  TRACE("Guid: %p\n", &szKeyName[1]);
834 
835  UuidFromStringW(&szKeyName[1],
836  &ClassGuidList[dwGuidListIndex]);
837  }
838 
839  dwGuidListIndex++;
840  }
841 
842  if (lError != ERROR_SUCCESS)
843  break;
844  }
845 
846  RegCloseKey(hClassesKey);
847 
848  if (RequiredSize != NULL)
849  *RequiredSize = dwGuidListIndex;
850 
851  if (ClassGuidListSize < dwGuidListIndex)
852  {
854  return FALSE;
855  }
856 
857  return TRUE;
858 }
859 
860 /***********************************************************************
861  * SetupDiClassGuidsFromNameA (SETUPAPI.@)
862  */
864  LPCSTR ClassName,
865  LPGUID ClassGuidList,
868 {
869  return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
870  ClassGuidListSize, RequiredSize,
871  NULL, NULL);
872 }
873 
874 /***********************************************************************
875  * SetupDiClassGuidsFromNameW (SETUPAPI.@)
876  */
878  LPCWSTR ClassName,
879  LPGUID ClassGuidList,
882 {
883  return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
884  ClassGuidListSize, RequiredSize,
885  NULL, NULL);
886 }
887 
888 /***********************************************************************
889  * SetupDiClassGuidsFromNameExA (SETUPAPI.@)
890  */
892  LPCSTR ClassName,
893  LPGUID ClassGuidList,
897  PVOID Reserved)
898 {
899  LPWSTR ClassNameW = NULL;
900  LPWSTR MachineNameW = NULL;
901  BOOL bResult;
902 
903  TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName), ClassGuidList,
904  ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
905 
906  if (!ClassName)
907  {
909  return FALSE;
910  }
911 
912  ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
913  if (ClassNameW == NULL)
914  return FALSE;
915 
916  if (MachineName)
917  {
918  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
919  if (MachineNameW == NULL)
920  {
921  MyFree(ClassNameW);
922  return FALSE;
923  }
924  }
925 
926  bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
927  ClassGuidListSize, RequiredSize,
928  MachineNameW, Reserved);
929 
930  MyFree(MachineNameW);
931  MyFree(ClassNameW);
932 
933  return bResult;
934 }
935 
936 /***********************************************************************
937  * SetupDiClassGuidsFromNameExW (SETUPAPI.@)
938  */
940  LPCWSTR ClassName,
941  LPGUID ClassGuidList,
945  PVOID Reserved)
946 {
947  WCHAR szKeyName[40];
949  HKEY hClassesKey;
950  HKEY hClassKey;
951  DWORD dwLength;
952  DWORD dwIndex;
953  LONG lError;
954  DWORD dwGuidListIndex = 0;
955 
956  TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
957  ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
958 
959  if (!ClassName || !RequiredSize)
960  {
962  return FALSE;
963  }
964  if (!ClassGuidList && ClassGuidListSize > 0)
965  {
967  return FALSE;
968  }
969  *RequiredSize = 0;
970 
971  hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
974  MachineName,
975  Reserved);
976  if (hClassesKey == INVALID_HANDLE_VALUE)
977  {
978  return FALSE;
979  }
980 
981  for (dwIndex = 0; ; dwIndex++)
982  {
983  dwLength = 40;
984  lError = RegEnumKeyExW(hClassesKey,
985  dwIndex,
986  szKeyName,
987  &dwLength,
988  NULL,
989  NULL,
990  NULL,
991  NULL);
992  TRACE("RegEnumKeyExW() returns %d\n", lError);
993  if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
994  {
995  TRACE("Key name: %p\n", szKeyName);
996 
997  if (RegOpenKeyExW(hClassesKey,
998  szKeyName,
999  0,
1001  &hClassKey))
1002  {
1003  RegCloseKey(hClassesKey);
1004  return FALSE;
1005  }
1006 
1007  dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
1008  if (!RegQueryValueExW(hClassKey,
1010  NULL,
1011  NULL,
1012  (LPBYTE)szClassName,
1013  &dwLength))
1014  {
1015  TRACE("Class name: %p\n", szClassName);
1016 
1017  if (strcmpiW(szClassName, ClassName) == 0)
1018  {
1019  TRACE("Found matching class name\n");
1020 
1021  TRACE("Guid: %p\n", szKeyName);
1022  if (dwGuidListIndex < ClassGuidListSize)
1023  {
1024  if (szKeyName[0] == '{' && szKeyName[37] == '}')
1025  {
1026  szKeyName[37] = 0;
1027  }
1028  TRACE("Guid: %p\n", &szKeyName[1]);
1029 
1030  UuidFromStringW(&szKeyName[1],
1031  &ClassGuidList[dwGuidListIndex]);
1032  }
1033 
1034  dwGuidListIndex++;
1035  }
1036  }
1037 
1038  RegCloseKey(hClassKey);
1039  }
1040 
1041  if (lError != ERROR_SUCCESS)
1042  break;
1043  }
1044 
1045  RegCloseKey(hClassesKey);
1046 
1047  if (RequiredSize != NULL)
1048  *RequiredSize = dwGuidListIndex;
1049 
1050  if (ClassGuidListSize < dwGuidListIndex)
1051  {
1053  return FALSE;
1054  }
1055 
1056  return TRUE;
1057 }
1058 
1059 /***********************************************************************
1060  * SetupDiClassNameFromGuidA (SETUPAPI.@)
1061  */
1063  const GUID* ClassGuid,
1064  PSTR ClassName,
1065  DWORD ClassNameSize,
1067 {
1068  return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
1069  ClassNameSize, RequiredSize,
1070  NULL, NULL);
1071 }
1072 
1073 /***********************************************************************
1074  * SetupDiClassNameFromGuidW (SETUPAPI.@)
1075  */
1077  const GUID* ClassGuid,
1078  PWSTR ClassName,
1079  DWORD ClassNameSize,
1081 {
1082  return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
1083  ClassNameSize, RequiredSize,
1084  NULL, NULL);
1085 }
1086 
1087 /***********************************************************************
1088  * SetupDiClassNameFromGuidExA (SETUPAPI.@)
1089  */
1091  const GUID* ClassGuid,
1092  PSTR ClassName,
1093  DWORD ClassNameSize,
1096  PVOID Reserved)
1097 {
1098  WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
1099  LPWSTR MachineNameW = NULL;
1100  BOOL ret;
1101 
1102  if (MachineName)
1103  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1104  ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
1105  RequiredSize, MachineNameW, Reserved);
1106  if (ret)
1107  {
1108  int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
1109  ClassNameSize, NULL, NULL);
1110  if (len == 0 || len > ClassNameSize)
1111  {
1113  ret = FALSE;
1114  }
1115  }
1116  MyFree(MachineNameW);
1117  return ret;
1118 }
1119 
1120 /***********************************************************************
1121  * SetupDiClassNameFromGuidExW (SETUPAPI.@)
1122  */
1124  const GUID* ClassGuid,
1125  PWSTR ClassName,
1126  DWORD ClassNameSize,
1129  PVOID Reserved)
1130 {
1131  HKEY hKey;
1132  DWORD dwLength;
1133  DWORD dwRegType;
1134  LONG rc;
1135  PWSTR Buffer;
1136 
1137  TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
1138  ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
1139 
1140  /* Make sure there's a GUID */
1141  if (ClassGuid == NULL)
1142  {
1143  SetLastError(ERROR_INVALID_CLASS); /* On Vista: ERROR_INVALID_USER_BUFFER */
1144  return FALSE;
1145  }
1146 
1147  /* Make sure there's a real buffer when there's a size */
1148  if ((ClassNameSize > 0) && (ClassName == NULL))
1149  {
1150  SetLastError(ERROR_INVALID_PARAMETER); /* On Vista: ERROR_INVALID_USER_BUFFER */
1151  return FALSE;
1152  }
1153 
1154  /* Open the key for the GUID */
1155  hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved);
1156 
1157  if (hKey == INVALID_HANDLE_VALUE)
1158  return FALSE;
1159 
1160  /* Retrieve the class name data and close the key */
1161  rc = QueryRegistryValue(hKey, REGSTR_VAL_CLASS, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
1162  RegCloseKey(hKey);
1163 
1164  /* Make sure we got the data */
1165  if (rc != ERROR_SUCCESS)
1166  {
1167  SetLastError(rc);
1168  return FALSE;
1169  }
1170 
1171  /* Make sure the data is a string */
1172  if (dwRegType != REG_SZ)
1173  {
1174  MyFree(Buffer);
1176  return FALSE;
1177  }
1178 
1179  /* Determine the length of the class name */
1180  dwLength /= sizeof(WCHAR);
1181 
1182  if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
1183  /* Count the null-terminator */
1184  dwLength++;
1185 
1186  /* Inform the caller about the class name */
1187  if ((ClassName != NULL) && (dwLength <= ClassNameSize))
1188  {
1189  memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
1190  ClassName[dwLength - 1] = UNICODE_NULL;
1191  }
1192 
1193  /* Inform the caller about the required size */
1194  if (RequiredSize != NULL)
1195  *RequiredSize = dwLength;
1196 
1197  /* Clean up the buffer */
1198  MyFree(Buffer);
1199 
1200  /* Make sure the buffer was large enough */
1201  if ((ClassName == NULL) || (dwLength > ClassNameSize))
1202  {
1204  return FALSE;
1205  }
1206 
1207  return TRUE;
1208 }
1209 
1210 /***********************************************************************
1211  * SetupDiCreateDeviceInfoList (SETUPAPI.@)
1212  */
1215  HWND hwndParent)
1216 {
1217  return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
1218 }
1219 
1220 /***********************************************************************
1221  * SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
1222  */
1225  HWND hwndParent,
1227  PVOID Reserved)
1228 {
1229  LPWSTR MachineNameW = NULL;
1230  HDEVINFO hDevInfo;
1231 
1232  TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1233  debugstr_a(MachineName), Reserved);
1234 
1235  if (MachineName)
1236  {
1237  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
1238  if (MachineNameW == NULL)
1239  return INVALID_HANDLE_VALUE;
1240  }
1241 
1242  hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
1243  MachineNameW, Reserved);
1244 
1245  MyFree(MachineNameW);
1246 
1247  return hDevInfo;
1248 }
1249 
1250 /***********************************************************************
1251  * SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
1252  *
1253  * Create an empty DeviceInfoSet list.
1254  *
1255  * PARAMS
1256  * ClassGuid [I] if not NULL only devices with GUID ClassGuid are associated
1257  * with this list.
1258  * hwndParent [I] hwnd needed for interface related actions.
1259  * MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
1260  * local registry will be used.
1261  * Reserved [I] must be NULL
1262  *
1263  * RETURNS
1264  * Success: empty list.
1265  * Failure: INVALID_HANDLE_VALUE.
1266  */
1269  HWND hwndParent,
1271  PVOID Reserved)
1272 {
1273  struct DeviceInfoSet *list = NULL;
1275  DWORD rc;
1276  CONFIGRET cr;
1278 
1279  TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
1280  debugstr_w(MachineName), Reserved);
1281 
1282  if (MachineName != NULL)
1283  {
1284  SIZE_T len = strlenW(MachineName);
1285  if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
1286  {
1288  goto cleanup;
1289  }
1290  if(len > 0)
1291  size += (len + 3) * sizeof(WCHAR);
1292  else
1293  MachineName = NULL;
1294  }
1295 
1296  if (Reserved != NULL)
1297  {
1299  return INVALID_HANDLE_VALUE;
1300  }
1301 
1302  list = MyMalloc(size);
1303  if (!list)
1304  {
1306  return INVALID_HANDLE_VALUE;
1307  }
1308  ZeroMemory(list, FIELD_OFFSET(struct DeviceInfoSet, szData));
1309 
1311  memcpy(&list->ClassGuid,
1312  ClassGuid ? ClassGuid : &GUID_NULL,
1313  sizeof(list->ClassGuid));
1317  if (MachineName)
1318  {
1319  rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
1320  if (rc != ERROR_SUCCESS)
1321  {
1323  goto cleanup;
1324  }
1325 
1326  list->szData[0] = list->szData[1] = '\\';
1327  strcpyW(list->szData + 2, MachineName);
1328  list->MachineName = list->szData;
1329  }
1330  else
1331  {
1332  list->HKLM = HKEY_LOCAL_MACHINE;
1333  list->MachineName = NULL;
1334  }
1335  cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
1336  if (cr != CR_SUCCESS)
1337  {
1339  goto cleanup;
1340  }
1342  InitializeListHead(&list->ListHead);
1343 
1344  return (HDEVINFO)list;
1345 
1346 cleanup:
1347  if (ret == INVALID_HANDLE_VALUE)
1348  {
1349  if (list)
1350  {
1351  if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
1352  RegCloseKey(list->HKLM);
1353  MyFree(list);
1354  }
1355  }
1356  return ret;
1357 }
1358 
1359 /***********************************************************************
1360  * SetupDiCreateDevRegKeyA (SETUPAPI.@)
1361  */
1365  DWORD Scope,
1366  DWORD HwProfile,
1367  DWORD KeyType,
1368  HINF InfHandle,
1369  PCSTR InfSectionName)
1370 {
1371  PWSTR InfSectionNameW = NULL;
1372  HKEY key;
1373 
1374  TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1375  HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
1376 
1377  if (InfHandle)
1378  {
1379  if (!InfSectionName)
1380  {
1382  return INVALID_HANDLE_VALUE;
1383  }
1384  else
1385  {
1386  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
1387  if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
1388  }
1389  }
1390  key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
1391  HwProfile, KeyType, InfHandle, InfSectionNameW);
1392  MyFree(InfSectionNameW);
1393  return key;
1394 }
1395 
1396 static HKEY
1398  IN HKEY HKLM,
1399  IN DWORD HwProfile,
1400  IN DWORD samDesired);
1401 
1402 /***********************************************************************
1403  * SetupDiCreateDevRegKeyW (SETUPAPI.@)
1404  */
1408  DWORD Scope,
1409  DWORD HwProfile,
1410  DWORD KeyType,
1411  HINF InfHandle,
1412  PCWSTR InfSectionName)
1413 {
1414  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1416  LPWSTR lpGuidString = NULL;
1417  LPWSTR DriverKey = NULL; /* {GUID}\Index */
1418  LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
1419  DWORD Index; /* Index used in the DriverKey name */
1420  DWORD dwSize;
1422  DWORD rc;
1423  HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
1424  HKEY hEnumKey = NULL;
1425  HKEY hClassKey = NULL;
1426  HKEY hDeviceKey = INVALID_HANDLE_VALUE;
1427  HKEY hKey = NULL;
1428  HKEY RootKey;
1429 
1430  TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
1431  HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
1432 
1433  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1434  {
1436  return INVALID_HANDLE_VALUE;
1437  }
1438  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1439  {
1441  return INVALID_HANDLE_VALUE;
1442  }
1443  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1444  || !DeviceInfoData->Reserved)
1445  {
1447  return INVALID_HANDLE_VALUE;
1448  }
1449  if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
1450  {
1452  return INVALID_HANDLE_VALUE;
1453  }
1454  if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
1455  {
1457  return INVALID_HANDLE_VALUE;
1458  }
1459  if (InfHandle && !InfSectionName)
1460  {
1462  return INVALID_HANDLE_VALUE;
1463  }
1464  if (!InfHandle && InfSectionName)
1465  {
1467  return INVALID_HANDLE_VALUE;
1468  }
1469 
1470  if (Scope == DICS_FLAG_GLOBAL)
1471  RootKey = set->HKLM;
1472  else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
1473  {
1474  hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
1475  if (hHWProfileKey == INVALID_HANDLE_VALUE)
1476  goto cleanup;
1477  RootKey = hHWProfileKey;
1478  }
1479 
1480  if (KeyType == DIREG_DEV)
1481  {
1482  struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
1483 
1484  rc = RegCreateKeyExW(
1485  RootKey,
1487  0,
1488  NULL,
1491  NULL,
1492  &hEnumKey,
1493  NULL);
1494  if (rc != ERROR_SUCCESS)
1495  {
1496  SetLastError(rc);
1497  goto cleanup;
1498  }
1499  rc = RegCreateKeyExW(
1500  hEnumKey,
1501  deviceInfo->instanceId,
1502  0,
1503  NULL,
1505 #if _WIN32_WINNT >= 0x502
1506  KEY_READ | KEY_WRITE,
1507 #else
1509 #endif
1510  NULL,
1511  &hKey,
1512  NULL);
1513  if (rc != ERROR_SUCCESS)
1514  {
1515  SetLastError(rc);
1516  goto cleanup;
1517  }
1518  }
1519  else /* KeyType == DIREG_DRV */
1520  {
1521  /* Open device key, to read Driver value */
1522  hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
1523  if (hDeviceKey == INVALID_HANDLE_VALUE)
1524  goto cleanup;
1525 
1526  rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
1527  if (rc != ERROR_SUCCESS)
1528  {
1529  SetLastError(rc);
1530  goto cleanup;
1531  }
1532 
1533  rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
1534  if (rc != ERROR_SUCCESS)
1535  {
1536  /* Create a new driver key */
1537 
1538  if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
1539  goto cleanup;
1540 
1541  /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
1542  DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1543  if (!DriverKey)
1544  {
1546  goto cleanup;
1547  }
1548 
1549  DriverKey[0] = '{';
1550  strcpyW(&DriverKey[1], lpGuidString);
1551  pDeviceInstance = &DriverKey[strlenW(DriverKey)];
1552  *pDeviceInstance++ = '}';
1553  *pDeviceInstance++ = '\\';
1554 
1555  /* Try all values for Index between 0 and 9999 */
1556  Index = 0;
1557  while (Index <= 9999)
1558  {
1559  sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
1560  rc = RegCreateKeyExW(hClassKey,
1561  DriverKey,
1562  0,
1563  NULL,
1565 #if _WIN32_WINNT >= 0x502
1566  KEY_READ | KEY_WRITE,
1567 #else
1569 #endif
1570  NULL,
1571  &hKey,
1572  &Disposition);
1573  if (rc != ERROR_SUCCESS)
1574  {
1575  SetLastError(rc);
1576  goto cleanup;
1577  }
1578  if (Disposition == REG_CREATED_NEW_KEY)
1579  break;
1580  RegCloseKey(hKey);
1581  hKey = NULL;
1582  Index++;
1583  }
1584 
1585  if (Index > 9999)
1586  {
1587  /* Unable to create more than 9999 devices within the same class */
1589  goto cleanup;
1590  }
1591 
1592  /* Write the new Driver value */
1593  rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
1594  if (rc != ERROR_SUCCESS)
1595  {
1596  SetLastError(rc);
1597  goto cleanup;
1598  }
1599 
1600  }
1601  else
1602  {
1603  /* Open the existing driver key */
1604 
1605  DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
1606  if (!DriverKey)
1607  {
1609  goto cleanup;
1610  }
1611 
1612  rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
1613  if (rc != ERROR_SUCCESS)
1614  {
1615  SetLastError(rc);
1616  goto cleanup;
1617  }
1618 
1619  rc = RegCreateKeyExW(hClassKey,
1620  DriverKey,
1621  0,
1622  NULL,
1624 #if _WIN32_WINNT >= 0x502
1625  KEY_READ | KEY_WRITE,
1626 #else
1628 #endif
1629  NULL,
1630  &hKey,
1631  &Disposition);
1632  if (rc != ERROR_SUCCESS)
1633  {
1634  SetLastError(rc);
1635  goto cleanup;
1636  }
1637  }
1638  }
1639 
1640  /* Do installation of the specified section */
1641  if (InfHandle)
1642  {
1643  FIXME("Need to install section %s in file %p\n",
1644  debugstr_w(InfSectionName), InfHandle);
1645  }
1646  key = hKey;
1647 
1648 cleanup:
1649  if (lpGuidString)
1650  RpcStringFreeW(&lpGuidString);
1651  HeapFree(GetProcessHeap(), 0, DriverKey);
1652  if (hHWProfileKey != INVALID_HANDLE_VALUE)
1653  RegCloseKey(hHWProfileKey);
1654  if (hEnumKey != NULL)
1655  RegCloseKey(hEnumKey);
1656  if (hClassKey != NULL)
1657  RegCloseKey(hClassKey);
1658  if (hDeviceKey != INVALID_HANDLE_VALUE)
1659  RegCloseKey(hDeviceKey);
1660  if (hKey != NULL && hKey != key)
1661  RegCloseKey(hKey);
1662 
1663  TRACE("Returning 0x%p\n", key);
1664  return key;
1665 }
1666 
1667 /***********************************************************************
1668  * SetupDiCreateDeviceInfoA (SETUPAPI.@)
1669  */
1672  PCSTR DeviceName,
1673  CONST GUID *ClassGuid,
1675  HWND hwndParent,
1678 {
1679  BOOL ret;
1680  LPWSTR DeviceNameW = NULL;
1681  LPWSTR DeviceDescriptionW = NULL;
1682 
1683  TRACE("\n");
1684 
1685  if (DeviceName)
1686  {
1687  DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
1688  if (DeviceNameW == NULL) return FALSE;
1689  }
1690  if (DeviceDescription)
1691  {
1692  DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
1693  if (DeviceDescriptionW == NULL)
1694  {
1695  MyFree(DeviceNameW);
1696  return FALSE;
1697  }
1698  }
1699 
1700  ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
1701  hwndParent, CreationFlags, DeviceInfoData);
1702 
1703  MyFree(DeviceNameW);
1704  MyFree(DeviceDescriptionW);
1705 
1706  return ret;
1707 }
1708 
1709 /***********************************************************************
1710  * SetupDiCreateDeviceInfoW (SETUPAPI.@)
1711  */
1715  CONST GUID *ClassGuid,
1717  HWND hwndParent,
1720 {
1721  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1722  struct DeviceInfo *deviceInfo = NULL;
1723  BOOL ret = FALSE;
1724  CONFIGRET cr;
1725  DEVINST RootDevInst;
1726  DEVINST DevInst;
1727  WCHAR GenInstanceId[MAX_DEVICE_ID_LEN];
1728 
1729  TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
1730  debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
1731  hwndParent, CreationFlags, DeviceInfoData);
1732 
1733  if (!DeviceName)
1734  {
1736  return FALSE;
1737  }
1738  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1739  {
1741  return FALSE;
1742  }
1743  if (!ClassGuid)
1744  {
1746  return FALSE;
1747  }
1748  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1749  {
1751  return FALSE;
1752  }
1753  if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
1754  !IsEqualGUID(ClassGuid, &set->ClassGuid))
1755  {
1757  return FALSE;
1758  }
1759  if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
1760  {
1761  TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
1763  return FALSE;
1764  }
1765 
1766  /* Get the root device instance */
1767  cr = CM_Locate_DevInst_ExW(&RootDevInst,
1768  NULL,
1770  set->hMachine);
1771  if (cr != CR_SUCCESS)
1772  {
1774  return FALSE;
1775  }
1776 
1777  /* Create the new device instance */
1778  cr = CM_Create_DevInst_ExW(&DevInst,
1779  (DEVINSTID)DeviceName,
1780  RootDevInst,
1781  (CreationFlags & DICD_GENERATE_ID) ?
1783  set->hMachine);
1784  if (cr != CR_SUCCESS)
1785  {
1787  return FALSE;
1788  }
1789 
1790  if (CreationFlags & DICD_GENERATE_ID)
1791  {
1792  /* Grab the actual instance ID that was created */
1793  cr = CM_Get_Device_ID_Ex(DevInst,
1794  GenInstanceId,
1796  0,
1797  set->hMachine);
1798  if (cr != CR_SUCCESS)
1799  {
1801  return FALSE;
1802  }
1803 
1804  DeviceName = GenInstanceId;
1805  TRACE("Using generated instance ID: %s\n", debugstr_w(DeviceName));
1806  }
1807 
1808  if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
1809  {
1810  InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
1811 
1812  if (!DeviceInfoData)
1813  ret = TRUE;
1814  else
1815  {
1816  if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1817  {
1819  }
1820  else
1821  {
1822  memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
1823  DeviceInfoData->DevInst = deviceInfo->dnDevInst;
1824  DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
1825  ret = TRUE;
1826  }
1827  }
1828  }
1829 
1830  if (ret == FALSE)
1831  {
1832  if (deviceInfo != NULL)
1833  {
1834  /* Remove deviceInfo from List */
1835  RemoveEntryList(&deviceInfo->ListEntry);
1836 
1837  /* Destroy deviceInfo */
1838  DestroyDeviceInfo(deviceInfo);
1839  }
1840  }
1841 
1842  TRACE("Returning %d\n", ret);
1843  return ret;
1844 }
1845 
1846 /***********************************************************************
1847  * SetupDiRegisterDeviceInfo (SETUPAPI.@)
1848  */
1852  DWORD Flags,
1853  PSP_DETSIG_CMPPROC CompareProc,
1854  PVOID CompareContext,
1855  PSP_DEVINFO_DATA DupDeviceInfoData)
1856 {
1857  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
1858  WCHAR DevInstId[MAX_DEVICE_ID_LEN];
1859  DEVINST ParentDevInst;
1860  CONFIGRET cr;
1861  DWORD dwError = ERROR_SUCCESS;
1862 
1863  TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
1864  CompareProc, CompareContext, DupDeviceInfoData);
1865 
1866  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
1867  {
1869  return FALSE;
1870  }
1871  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
1872  {
1874  return FALSE;
1875  }
1876  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
1877  || !DeviceInfoData->Reserved)
1878  {
1880  return FALSE;
1881  }
1882 
1883  if (Flags & ~SPRDI_FIND_DUPS)
1884  {
1885  TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
1887  return FALSE;
1888  }
1889 
1890  if (Flags & SPRDI_FIND_DUPS)
1891  {
1892  FIXME("Unimplemented codepath!\n");
1893  }
1894 
1895  CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
1896  DevInstId,
1898  0,
1899  set->hMachine);
1900 
1901  CM_Get_Parent_Ex(&ParentDevInst,
1902  DeviceInfoData->DevInst,
1903  0,
1904  set->hMachine);
1905 
1906  cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
1907  DevInstId,
1908  ParentDevInst,
1910  set->hMachine);
1911  if (cr != CR_SUCCESS &&
1913  {
1914  dwError = ERROR_NO_SUCH_DEVINST;
1915  }
1916 
1917  SetLastError(dwError);
1918 
1919  return (dwError == ERROR_SUCCESS);
1920 }
1921 
1922 /***********************************************************************
1923  * SetupDiEnumDeviceInfo (SETUPAPI.@)
1924  */
1926  HDEVINFO devinfo,
1927  DWORD index,
1929 {
1930  BOOL ret = FALSE;
1931 
1932  TRACE("%p %d %p\n", devinfo, index, info);
1933 
1934  if(info==NULL)
1935  {
1937  return FALSE;
1938  }
1939  if (devinfo && devinfo != INVALID_HANDLE_VALUE)
1940  {
1941  struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
1942  if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
1943  {
1944  if (info->cbSize != sizeof(SP_DEVINFO_DATA))
1946  else
1947  {
1948  PLIST_ENTRY ItemList = list->ListHead.Flink;
1949  while (ItemList != &list->ListHead && index-- > 0)
1950  ItemList = ItemList->Flink;
1951  if (ItemList == &list->ListHead)
1953  else
1954  {
1955  struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
1956  memcpy(&info->ClassGuid,
1957  &DevInfo->ClassGuid,
1958  sizeof(GUID));
1959  info->DevInst = DevInfo->dnDevInst;
1960  info->Reserved = (ULONG_PTR)DevInfo;
1961  ret = TRUE;
1962  }
1963  }
1964  }
1965  else
1967  }
1968  else
1970  return ret;
1971 }
1972 
1973 /***********************************************************************
1974  * SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
1975  */
1979  PSTR DeviceInstanceId,
1980  DWORD DeviceInstanceIdSize,
1982 {
1983  BOOL ret = FALSE;
1984  DWORD size;
1985  PWSTR instanceId;
1986 
1987  TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
1988  DeviceInstanceIdSize, RequiredSize);
1989 
1990  if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
1991  {
1993  return FALSE;
1994  }
1995 
1996  ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
1997  DeviceInfoData,
1998  NULL,
1999  0,
2000  &size);
2001  if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2002  return FALSE;
2003  instanceId = MyMalloc(size * sizeof(WCHAR));
2004  if (instanceId)
2005  {
2006  ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
2007  DeviceInfoData,
2008  instanceId,
2009  size,
2010  &size);
2011  if (ret)
2012  {
2013  int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
2014  DeviceInstanceId,
2015  DeviceInstanceIdSize, NULL, NULL);
2016 
2017  if (!len)
2018  ret = FALSE;
2019  else
2020  {
2021  if (len > DeviceInstanceIdSize)
2022  {
2024  ret = FALSE;
2025  }
2026  if (RequiredSize)
2027  *RequiredSize = len;
2028  }
2029  }
2030  MyFree(instanceId);
2031  }
2032  else
2033  {
2034  if (RequiredSize)
2035  *RequiredSize = size;
2037  ret = FALSE;
2038  }
2039  return ret;
2040 }
2041 
2042 /***********************************************************************
2043  * SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
2044  */
2048  PWSTR DeviceInstanceId,
2049  DWORD DeviceInstanceIdSize,
2051 {
2052  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2053  struct DeviceInfo *devInfo;
2054 
2055  TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
2056  DeviceInstanceIdSize, RequiredSize);
2057 
2058  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2059  {
2061  return FALSE;
2062  }
2063  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2064  {
2066  return FALSE;
2067  }
2068  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2069  || !DeviceInfoData->Reserved)
2070  {
2072  return FALSE;
2073  }
2074  devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
2075  if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
2076  {
2078  return FALSE;
2079  }
2080  if (DeviceInstanceId && DeviceInstanceIdSize == 0)
2081  {
2083  return FALSE;
2084  }
2085  TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
2086  if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
2087  {
2089  if (RequiredSize)
2090  *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
2091  return FALSE;
2092  }
2093  lstrcpyW(DeviceInstanceId, devInfo->instanceId);
2094  if (RequiredSize)
2095  *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
2096  return TRUE;
2097 }
2098 
2099 /***********************************************************************
2100  * SetupDiGetActualSectionToInstallA (SETUPAPI.@)
2101  */
2103  HINF InfHandle,
2104  PCSTR InfSectionName,
2105  PSTR InfSectionWithExt,
2106  DWORD InfSectionWithExtSize,
2108  PSTR *Extension)
2109 {
2110  return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
2111  NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
2112  Extension, NULL);
2113 }
2114 
2115 /***********************************************************************
2116  * SetupDiGetActualSectionToInstallW (SETUPAPI.@)
2117  */
2119  HINF InfHandle,
2120  PCWSTR InfSectionName,
2121  PWSTR InfSectionWithExt,
2122  DWORD InfSectionWithExtSize,
2124  PWSTR *Extension)
2125 {
2126  return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
2127  NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
2128  Extension, NULL);
2129 }
2130 
2131 /***********************************************************************
2132  * SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
2133  */
2134 BOOL WINAPI
2136  IN HINF InfHandle,
2137  IN PCSTR InfSectionName,
2138  IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
2139  OUT PSTR InfSectionWithExt OPTIONAL,
2140  IN DWORD InfSectionWithExtSize,
2141  OUT PDWORD RequiredSize OPTIONAL,
2142  OUT PSTR* Extension OPTIONAL,
2143  IN PVOID Reserved)
2144 {
2145  LPWSTR InfSectionNameW = NULL;
2146  LPWSTR InfSectionWithExtW = NULL;
2147  PWSTR ExtensionW;
2148  BOOL bResult = FALSE;
2149 
2150  TRACE("\n");
2151 
2152  if (InfSectionName)
2153  {
2154  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2155  if (InfSectionNameW == NULL)
2156  goto cleanup;
2157  }
2158  if (InfSectionWithExt)
2159  {
2160  InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
2161  if (InfSectionWithExtW == NULL)
2162  goto cleanup;
2163  }
2164 
2166  InfHandle, InfSectionNameW, AlternatePlatformInfo,
2167  InfSectionWithExt ? InfSectionWithExtW : NULL,
2168  InfSectionWithExtSize,
2169  RequiredSize,
2170  Extension ? &ExtensionW : NULL,
2171  Reserved);
2172 
2173  if (bResult && InfSectionWithExt)
2174  {
2175  bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
2176  InfSectionWithExtSize, NULL, NULL) != 0;
2177  }
2178  if (bResult && Extension)
2179  {
2180  if (ExtensionW == NULL)
2181  *Extension = NULL;
2182  else
2183  *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
2184  }
2185 
2186 cleanup:
2187  MyFree(InfSectionNameW);
2188  MyFree(InfSectionWithExtW);
2189 
2190  return bResult;
2191 }
2192 
2193 /***********************************************************************
2194  * SetupDiGetClassDescriptionA (SETUPAPI.@)
2195  */
2197  const GUID* ClassGuid,
2198  PSTR ClassDescription,
2199  DWORD ClassDescriptionSize,
2201 {
2202  return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
2203  ClassDescriptionSize,
2204  RequiredSize, NULL, NULL);
2205 }
2206 
2207 /***********************************************************************
2208  * SetupDiGetClassDescriptionW (SETUPAPI.@)
2209  */
2211  const GUID* ClassGuid,
2212  PWSTR ClassDescription,
2213  DWORD ClassDescriptionSize,
2215 {
2216  return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
2217  ClassDescriptionSize,
2218  RequiredSize, NULL, NULL);
2219 }
2220 
2221 /***********************************************************************
2222  * SetupDiGetClassDescriptionExA (SETUPAPI.@)
2223  */
2225  const GUID* ClassGuid,
2226  PSTR ClassDescription,
2227  DWORD ClassDescriptionSize,
2230  PVOID Reserved)
2231 {
2232  PWCHAR ClassDescriptionW = NULL;
2233  LPWSTR MachineNameW = NULL;
2234  BOOL ret = FALSE;
2235 
2236  TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
2237  ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
2238 
2239  if (ClassDescriptionSize > 0)
2240  {
2241  ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
2242  if (!ClassDescriptionW)
2243  {
2245  goto cleanup;
2246  }
2247  }
2248 
2249  if (MachineName)
2250  {
2251  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
2252  if (!MachineNameW)
2253  {
2255  goto cleanup;
2256  }
2257  }
2258 
2259  ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
2260  ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
2261  if (ret)
2262  {
2263  DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
2264  ClassDescriptionSize, NULL, NULL);
2265  if (len == 0 || len > ClassDescriptionSize)
2266  {
2268  ret = FALSE;
2269  }
2270  }
2271 
2272 cleanup:
2273  MyFree(ClassDescriptionW);
2274  MyFree(MachineNameW);
2275  return ret;
2276 }
2277 
2278 /***********************************************************************
2279  * SetupDiGetClassDescriptionExW (SETUPAPI.@)
2280  */
2282  const GUID* ClassGuid,
2283  PWSTR ClassDescription,
2284  DWORD ClassDescriptionSize,
2287  PVOID Reserved)
2288 {
2289  HKEY hKey;
2290  DWORD dwLength;
2291  DWORD dwRegType;
2292  LONG rc;
2293  PWSTR Buffer;
2294 
2295  TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
2296  ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
2297 
2298  /* Make sure there's a GUID */
2299  if (!ClassGuid)
2300  {
2302  return FALSE;
2303  }
2304 
2305  /* Make sure there's a real buffer when there's a size */
2306  if (!ClassDescription && ClassDescriptionSize > 0)
2307  {
2309  return FALSE;
2310  }
2311 
2312  /* Open the key for the GUID */
2313  hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
2316  MachineName,
2317  Reserved);
2318  if (hKey == INVALID_HANDLE_VALUE)
2319  return FALSE;
2320 
2321  /* Retrieve the class description data and close the key */
2322  rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
2323  RegCloseKey(hKey);
2324 
2325  /* Make sure we got the data */
2326  if (rc != ERROR_SUCCESS)
2327  {
2328  SetLastError(rc);
2329  return FALSE;
2330  }
2331 
2332  /* Make sure the data is a string */
2333  if (dwRegType != REG_SZ)
2334  {
2335  MyFree(Buffer);
2337  return FALSE;
2338  }
2339 
2340  /* Determine the length of the class description */
2341  dwLength /= sizeof(WCHAR);
2342 
2343  /* Count the null-terminator if none is present */
2344  if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
2345  dwLength++;
2346 
2347  /* Inform the caller about the class description */
2348  if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
2349  {
2350  memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
2351  ClassDescription[dwLength - 1] = UNICODE_NULL;
2352  }
2353 
2354  /* Inform the caller about the required size */
2355  if (RequiredSize != NULL)
2356  *RequiredSize = dwLength;
2357 
2358  /* Clean up the buffer */
2359  MyFree(Buffer);
2360 
2361  /* Make sure the buffer was large enough */
2362  if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
2363  {
2365  return FALSE;
2366  }
2367 
2368  return TRUE;
2369 }
2370 
2371 /***********************************************************************
2372  * SetupDiGetClassDevsA (SETUPAPI.@)
2373  */
2375  CONST GUID *class,
2376  LPCSTR enumstr,
2377  HWND parent,
2378  DWORD flags)
2379 {
2380  return SetupDiGetClassDevsExA(class, enumstr, parent,
2381  flags, NULL, NULL, NULL);
2382 }
2383 
2384 /***********************************************************************
2385  * SetupDiGetClassDevsExA (SETUPAPI.@)
2386  */
2388  const GUID *class,
2389  PCSTR enumstr,
2390  HWND parent,
2391  DWORD flags,
2392  HDEVINFO deviceset,
2393  PCSTR machine,
2394  PVOID reserved)
2395 {
2396  HDEVINFO ret;
2397  LPWSTR enumstrW = NULL, machineW = NULL;
2398 
2399  if (enumstr)
2400  {
2401  enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
2402  if (!enumstrW)
2403  {
2404  ret = INVALID_HANDLE_VALUE;
2405  goto end;
2406  }
2407  }
2408  if (machine)
2409  {
2410  machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
2411  if (!machineW)
2412  {
2413  MyFree(enumstrW);
2414  ret = INVALID_HANDLE_VALUE;
2415  goto end;
2416  }
2417  }
2418  ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
2419  machineW, reserved);
2420  MyFree(enumstrW);
2421  MyFree(machineW);
2422 
2423 end:
2424  return ret;
2425 }
2426 
2427 /***********************************************************************
2428  * SetupDiGetClassDevsW (SETUPAPI.@)
2429  */
2431  CONST GUID *class,
2432  LPCWSTR enumstr,
2433  HWND parent,
2434  DWORD flags)
2435 {
2436  return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
2437  NULL);
2438 }
2439 
2440 /***********************************************************************
2441  * SetupDiGetClassDevsExW (SETUPAPI.@)
2442  */
2444  CONST GUID *class,
2445  PCWSTR enumstr,
2446  HWND parent,
2447  DWORD flags,
2448  HDEVINFO deviceset,
2449  PCWSTR machine,
2450  PVOID reserved)
2451 {
2452  HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2453  struct DeviceInfoSet *list;
2454  CONST GUID *pClassGuid;
2455  LONG rc;
2457 
2458  TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
2459  debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
2460  reserved);
2461 
2462  if (!(flags & DIGCF_ALLCLASSES) && !class)
2463  {
2465  return INVALID_HANDLE_VALUE;
2466  }
2467 
2468  /* Create the deviceset if not set */
2469  if (deviceset)
2470  {
2471  list = (struct DeviceInfoSet *)deviceset;
2472  if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2473  {
2475  goto cleanup;
2476  }
2477  hDeviceInfo = deviceset;
2478  }
2479  else
2480  {
2481  hDeviceInfo = SetupDiCreateDeviceInfoListExW(
2482  flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
2483  NULL, machine, NULL);
2484  if (hDeviceInfo == INVALID_HANDLE_VALUE)
2485  goto cleanup;
2486  list = (struct DeviceInfoSet *)hDeviceInfo;
2487  }
2488 
2489  if (flags & DIGCF_PROFILE)
2490  FIXME(": flag DIGCF_PROFILE ignored\n");
2491 
2492  if (flags & DIGCF_DEVICEINTERFACE)
2493  {
2494  if (!class)
2495  {
2497  goto cleanup;
2498  }
2499  rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
2500  }
2501  else
2502  {
2503  /* Determine which class(es) should be included in the deviceset */
2504  if (flags & DIGCF_ALLCLASSES)
2505  {
2506  /* The caller wants all classes. Check if
2507  * the deviceset limits us to one class */
2508  if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2509  pClassGuid = NULL;
2510  else
2511  pClassGuid = &list->ClassGuid;
2512  }
2513  else if (class)
2514  {
2515  /* The caller wants one class. Check if it matches deviceset class */
2516  if (IsEqualIID(&list->ClassGuid, class)
2517  || IsEqualIID(&list->ClassGuid, &GUID_NULL))
2518  {
2519  pClassGuid = class;
2520  }
2521  else
2522  {
2524  goto cleanup;
2525  }
2526  }
2527  else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
2528  {
2529  /* No class specified. Try to use the one of the deviceset */
2530  if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
2531  pClassGuid = &list->ClassGuid;
2532  else
2533  {
2535  goto cleanup;
2536  }
2537  }
2538  else
2539  {
2541  goto cleanup;
2542  }
2543  rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
2544  }
2545  if (rc != ERROR_SUCCESS)
2546  {
2547  SetLastError(rc);
2548  goto cleanup;
2549  }
2550  set = hDeviceInfo;
2551 
2552 cleanup:
2553  if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
2554  SetupDiDestroyDeviceInfoList(hDeviceInfo);
2555  return set;
2556 }
2557 
2558 /***********************************************************************
2559  * SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
2560  */
2563  PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
2564 {
2565  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2566 
2567  TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2568 
2569  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2570  {
2572  return FALSE;
2573  }
2574  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2575  {
2577  return FALSE;
2578  }
2579  if (!DevInfoData ||
2580  DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
2581  {
2583  return FALSE;
2584  }
2585  memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2586  DevInfoData->RemoteMachineHandle = set->hMachine;
2587  if (set->MachineName)
2588  {
2589  FIXME("Stub\n");
2591  return FALSE;
2592  }
2593  else
2594  DevInfoData->RemoteMachineName[0] = 0;
2595 
2596  return TRUE;
2597 }
2598 
2599 /***********************************************************************
2600  * SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
2601  */
2604  PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
2605 {
2606  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2607 
2608  TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
2609 
2610  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2611  {
2613  return FALSE;
2614  }
2615  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2616  {
2618  return FALSE;
2619  }
2620  if (!DevInfoData ||
2621  DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
2622  {
2624  return FALSE;
2625  }
2626  memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
2627  DevInfoData->RemoteMachineHandle = set->hMachine;
2628  if (set->MachineName)
2629  strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
2630  else
2631  DevInfoData->RemoteMachineName[0] = 0;
2632 
2633  return TRUE;
2634 }
2635 
2636 /***********************************************************************
2637  * SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
2638  */
2642  const GUID *InterfaceClassGuid,
2644  DWORD CreationFlags,
2645  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2646 {
2647  BOOL ret;
2648  LPWSTR ReferenceStringW = NULL;
2649 
2650  TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2651  debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
2652  CreationFlags, DeviceInterfaceData);
2653 
2654  if (ReferenceString)
2655  {
2656  ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
2657  if (ReferenceStringW == NULL) return FALSE;
2658  }
2659 
2660  ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
2661  InterfaceClassGuid, ReferenceStringW, CreationFlags,
2662  DeviceInterfaceData);
2663 
2664  MyFree(ReferenceStringW);
2665 
2666  return ret;
2667 }
2668 
2669 /***********************************************************************
2670  * SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
2671  */
2675  const GUID *InterfaceClassGuid,
2677  DWORD CreationFlags,
2678  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2679 {
2680  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2681  TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2682  debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2683  CreationFlags, DeviceInterfaceData);
2684 
2685  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
2686  {
2688  return FALSE;
2689  }
2690  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2691  {
2693  return FALSE;
2694  }
2695  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
2696  || !DeviceInfoData->Reserved)
2697  {
2699  return FALSE;
2700  }
2701  if (!InterfaceClassGuid)
2702  {
2704  return FALSE;
2705  }
2706 
2707  FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
2708  debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
2709  CreationFlags, DeviceInterfaceData);
2711  return FALSE;
2712 }
2713 
2714 /***********************************************************************
2715  * SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
2716  */
2719  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2720  DWORD Reserved,
2721  REGSAM samDesired,
2722  HINF InfHandle,
2723  PCSTR InfSectionName)
2724 {
2725  HKEY key;
2726  PWSTR InfSectionNameW = NULL;
2727 
2728  TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2729  samDesired, InfHandle, InfSectionName);
2730  if (InfHandle)
2731  {
2732  if (!InfSectionName)
2733  {
2735  return INVALID_HANDLE_VALUE;
2736  }
2737  InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
2738  if (!InfSectionNameW)
2739  return INVALID_HANDLE_VALUE;
2740  }
2741  key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
2742  DeviceInterfaceData, Reserved, samDesired, InfHandle,
2743  InfSectionNameW);
2744  MyFree(InfSectionNameW);
2745  return key;
2746 }
2747 
2748 /***********************************************************************
2749  * SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
2750  */
2753  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2754  DWORD Reserved,
2755  REGSAM samDesired,
2756  HINF InfHandle,
2757  PCWSTR InfSectionName)
2758 {
2759  HKEY hKey, hDevKey;
2761  DWORD Length, Index;
2762  LONG rc;
2763  WCHAR bracedGuidString[39];
2764  struct DeviceInterface *DevItf;
2765  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2766 
2767  TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
2768  samDesired, InfHandle, InfSectionName);
2769 
2770  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2772  {
2774  return INVALID_HANDLE_VALUE;
2775  }
2776  if (!DeviceInterfaceData ||
2777  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2778  !DeviceInterfaceData->Reserved)
2779  {
2781  return INVALID_HANDLE_VALUE;
2782  }
2783  if (InfHandle && !InfSectionName)
2784  {
2786  return INVALID_HANDLE_VALUE;
2787  }
2788 
2789  hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
2790  if (hKey == INVALID_HANDLE_VALUE)
2791  {
2792  hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
2793  if (hKey == INVALID_HANDLE_VALUE)
2794  {
2796  return INVALID_HANDLE_VALUE;
2797  }
2798  SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
2799 
2800  if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
2801  {
2803  return INVALID_HANDLE_VALUE;
2804  }
2805  RegCloseKey(hKey);
2806  hKey = hDevKey;
2807  }
2808 
2809  DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
2810 
2811  Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
2812  SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
2813  if (!SymbolicLink)
2814  {
2815  RegCloseKey(hKey);
2817  return INVALID_HANDLE_VALUE;
2818  }
2819 
2820  wcscpy(SymbolicLink, DevItf->SymbolicLink);
2821 
2822  Index = 0;
2823  while(SymbolicLink[Index])
2824  {
2825  if (SymbolicLink[Index] == L'\\')
2826  {
2827  SymbolicLink[Index] = L'#';
2828  }
2829  Index++;
2830  }
2831 
2832  rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
2833 
2834  RegCloseKey(hKey);
2835  HeapFree(GetProcessHeap(), 0, SymbolicLink);
2836 
2837  if (rc == ERROR_SUCCESS)
2838  {
2839  if (InfHandle && InfSectionName)
2840  {
2841  if (!SetupInstallFromInfSection(NULL /*FIXME */,
2842  InfHandle,
2843  InfSectionName,
2845  hDevKey,
2846  NULL,
2847  0,
2848  set->SelectedDevice->InstallParams.InstallMsgHandler,
2849  set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
2851  NULL))
2852  {
2853  RegCloseKey(hDevKey);
2854  return INVALID_HANDLE_VALUE;
2855  }
2856  }
2857  }
2858 
2859  SetLastError(rc);
2860  return hDevKey;
2861 }
2862 
2863 /***********************************************************************
2864  * SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
2865  */
2868  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
2869  DWORD Reserved)
2870 {
2871  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2872  BOOL ret = FALSE;
2873 
2874  TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2875 
2876  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2878  {
2880  return FALSE;
2881  }
2882  if (!DeviceInterfaceData ||
2883  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
2884  !DeviceInterfaceData->Reserved)
2885  {
2887  return FALSE;
2888  }
2889 
2890  FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
2892  return ret;
2893 }
2894 
2895 /***********************************************************************
2896  * SetupDiEnumDeviceInterfaces (SETUPAPI.@)
2897  *
2898  * PARAMS
2899  * DeviceInfoSet [I] Set of devices from which to enumerate
2900  * interfaces
2901  * DeviceInfoData [I] (Optional) If specified, a specific device
2902  * instance from which to enumerate interfaces.
2903  * If it isn't specified, all interfaces for all
2904  * devices in the set are enumerated.
2905  * InterfaceClassGuid [I] The interface class to enumerate.
2906  * MemberIndex [I] An index of the interface instance to enumerate.
2907  * A caller should start with MemberIndex set to 0,
2908  * and continue until the function fails with
2909  * ERROR_NO_MORE_ITEMS.
2910  * DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
2911  * member must be set to
2912  * sizeof(SP_DEVICE_INTERFACE_DATA).
2913  *
2914  * RETURNS
2915  * Success: non-zero value.
2916  * Failure: FALSE. Call GetLastError() for more info.
2917  */
2922  DWORD MemberIndex,
2923  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
2924 {
2925  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
2926  BOOL ret = FALSE;
2927 
2928  TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
2929  debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
2930 
2931  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
2933  {
2935  return FALSE;
2936  }
2937  if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
2938  !DeviceInfoData->Reserved))
2939  {
2941  return FALSE;
2942  }
2943  if (!DeviceInterfaceData ||
2944  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
2945  {
2947  return FALSE;
2948  }
2949  if (DeviceInfoData)
2950  {
2951  struct DeviceInfo *devInfo =
2952  (struct DeviceInfo *)DeviceInfoData->Reserved;
2953  BOOL found = FALSE;
2954  PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2955  while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2956  {
2957  struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2958  if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2959  {
2960  InterfaceListEntry = InterfaceListEntry->Flink;
2961  continue;
2962  }
2963  if (MemberIndex-- == 0)
2964  {
2965  /* return this item */
2966  memcpy(&DeviceInterfaceData->InterfaceClassGuid,
2967  &DevItf->InterfaceClassGuid,
2968  sizeof(GUID));
2969  DeviceInterfaceData->Flags = DevItf->Flags;
2970  DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
2971  found = TRUE;
2972  ret = TRUE;
2973  }
2974  InterfaceListEntry = InterfaceListEntry->Flink;
2975  }
2976  if (!found)
2978  }
2979  else
2980  {
2981  BOOL found = FALSE;
2982  PLIST_ENTRY ItemList = set->ListHead.Flink;
2983  while (ItemList != &set->ListHead && !found)
2984  {
2985  PLIST_ENTRY InterfaceListEntry;
2986  struct DeviceInfo *devInfo =
2987  CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
2988  InterfaceListEntry = devInfo->InterfaceListHead.Flink;
2989  while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
2990  {
2991  struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
2992  if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
2993  {
2994  InterfaceListEntry = InterfaceListEntry->Flink;
2995  continue;
2996  }
2997  if (MemberIndex-- == 0)
2998  {
2999  /* return this item */
3000  memcpy(&DeviceInterfaceData->InterfaceClassGuid,
3001  &DevItf->InterfaceClassGuid,
3002  sizeof(GUID));
3003  DeviceInterfaceData->Flags = DevItf->Flags;
3004  DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
3005  found = TRUE;
3006  ret = TRUE;
3007  }
3008  InterfaceListEntry = InterfaceListEntry->Flink;
3009  }
3010  ItemList = ItemList->Flink;
3011 
3012  }
3013  if (!found)
3015  }
3016  return ret;
3017 }
3018 
3019 /***********************************************************************
3020  * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
3021  *
3022  * Destroy a DeviceInfoList and free all used memory of the list.
3023  *
3024  * PARAMS
3025  * devinfo [I] DeviceInfoList pointer to list to destroy
3026  *
3027  * RETURNS
3028  * Success: non zero value.
3029  * Failure: zero value.
3030  */
3032 {
3033  BOOL ret = FALSE;
3034 
3035  TRACE("%p\n", devinfo);
3036  if (devinfo && devinfo != INVALID_HANDLE_VALUE)
3037  {
3038  struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
3039 
3040  if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
3041  {
3042  ret = DestroyDeviceInfoSet(list);
3043  }
3044  }
3045 
3046  if (ret == FALSE)
3048 
3049  return ret;
3050 }
3051 
3052 /***********************************************************************
3053  * SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
3054  */
3057  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3058  PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
3059  DWORD DeviceInterfaceDetailDataSize,
3062 {
3063  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3064  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
3065  DWORD sizeW = 0, bytesNeeded;
3066  BOOL ret = FALSE;
3067 
3068  TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
3069  DeviceInterfaceData, DeviceInterfaceDetailData,
3070  DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3071 
3072  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3074  {
3076  return FALSE;
3077  }
3078  if (!DeviceInterfaceData ||
3079  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3080  !DeviceInterfaceData->Reserved)
3081  {
3083  return FALSE;
3084  }
3085  if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
3086  {
3088  return FALSE;
3089  }
3090 
3091  if((DeviceInterfaceDetailDataSize != 0) &&
3092  (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
3093  {
3095  return FALSE;
3096  }
3097 
3098  if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3099  {
3101  return FALSE;
3102  }
3103 
3104 
3105  if (DeviceInterfaceDetailData != NULL)
3106  {
3108  + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
3109  DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
3110  if (!DeviceInterfaceDetailDataW)
3111  {
3113  }
3114  DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
3115  }
3116  if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
3117  {
3119  DeviceInfoSet,
3120  DeviceInterfaceData,
3121  DeviceInterfaceDetailDataW,
3122  sizeW,
3123  &sizeW,
3124  DeviceInfoData);
3125  bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
3127  if (RequiredSize)
3128  *RequiredSize = bytesNeeded;
3129  if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
3130  {
3131  if (!WideCharToMultiByte(
3132  CP_ACP, 0,
3133  DeviceInterfaceDetailDataW->DevicePath, -1,
3134  DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
3135  NULL, NULL))
3136  {
3137  ret = FALSE;
3138  }
3139  }
3140  }
3141  MyFree(DeviceInterfaceDetailDataW);
3142 
3143  return ret;
3144 }
3145 
3146 /***********************************************************************
3147  * SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
3148  */
3151  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
3152  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
3153  DWORD DeviceInterfaceDetailDataSize,
3156 {
3157  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3158  BOOL ret = FALSE;
3159 
3160  TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
3161  DeviceInterfaceData, DeviceInterfaceDetailData,
3162  DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
3163 
3164  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
3166  {
3168  return FALSE;
3169  }
3170  if (!DeviceInterfaceData ||
3171  DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
3172  !DeviceInterfaceData->Reserved)
3173  {
3175  return FALSE;
3176  }
3177  if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
3178  {
3180  return FALSE;
3181  }
3182  if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
3183  {
3185  return FALSE;
3186  }
3187  if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
3188  {
3190  return FALSE;
3191  }
3192  if ((DeviceInterfaceDetailData != NULL)
3193  && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
3194  {
3196  return FALSE;
3197  }
3198  else
3199  {
3200  struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
3201  LPCWSTR devName = deviceInterface->SymbolicLink;
3202  DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
3203  (lstrlenW(devName) + 1) * sizeof(WCHAR);
3204 
3205  if (sizeRequired > DeviceInterfaceDetailDataSize)
3206  {
3208  if (RequiredSize)
3209  *RequiredSize = sizeRequired;
3210  }
3211  else
3212  {
3213  strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
3214  TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
3215  if (DeviceInfoData)
3216  {
3217  memcpy(&DeviceInfoData->ClassGuid,
3218  &deviceInterface->DeviceInfo->ClassGuid,
3219  sizeof(GUID));
3220  DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
3221  DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
3222  }
3223  ret = TRUE;
3224  }
3225  }
3226  return ret;
3227 }
3228 
3230 {
3234 };
3235 
3236 static struct PropertyMapEntry PropertyMap[] = {
3237  { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
3238  { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
3239  { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
3240  { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
3241  { REG_SZ, "Service", REGSTR_VAL_SERVICE },
3242  { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
3243  { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
3244  { REG_SZ, "Class", REGSTR_VAL_CLASS },
3245  { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
3246  { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
3247  { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
3248  { REG_SZ, "Mfg", REGSTR_VAL_MFG },
3249  { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
3250  { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
3251  { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
3252  { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
3253  { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
3254  { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
3255  { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
3256  { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
3257  { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
3258  { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
3259  { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
3260  { REG_BINARY, "Security", REGSTR_SECURITY },
3261  { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
3262  { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
3263  { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
3264  { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
3265  { 0, NULL, NULL }, /* SPDRP_ADDRESS */
3266  { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
3267  { 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
3268  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
3269  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
3270  { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
3271  { 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
3272 };
3273 
3274 /***********************************************************************
3275  * SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
3276  */
3280  DWORD Property,
3282  PBYTE PropertyBuffer,
3285 {
3286  BOOL ret;
3287  BOOL bIsStringProperty;
3288  DWORD RegType;
3289  DWORD RequiredSizeA, RequiredSizeW;
3290  DWORD PropertyBufferSizeW = 0;
3291  PBYTE PropertyBufferW = NULL;
3292 
3293  TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
3294  Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3295  RequiredSize);
3296 
3297  if (PropertyBufferSize != 0)
3298  {
3299  PropertyBufferSizeW = PropertyBufferSize * 2;
3300  PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
3301  if (!PropertyBufferW)
3302  {
3304  return FALSE;
3305  }
3306  }
3307 
3308  ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
3309  DeviceInfoData,
3310  Property,
3311  &RegType,
3312  PropertyBufferW,
3313  PropertyBufferSizeW,
3314  &RequiredSizeW);
3315 
3316  if (ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3317  {
3318  bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
3319 
3320  if (bIsStringProperty)
3321  RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
3322  else
3323  RequiredSizeA = RequiredSizeW;
3324  if (RequiredSize)
3325  *RequiredSize = RequiredSizeA;
3326  if (PropertyRegDataType)
3327  *PropertyRegDataType = RegType;
3328  }
3329 
3330  if (!ret)
3331  {
3332  HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3333  return ret;
3334  }
3335 
3336  if (RequiredSizeA <= PropertyBufferSize)
3337  {
3338  if (bIsStringProperty && PropertyBufferSize > 0)
3339  {
3340  if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
3341  {
3342  /* Last error is already set by WideCharToMultiByte */
3343  ret = FALSE;
3344  }
3345  }
3346  else
3347  memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
3348  }
3349  else
3350  {
3352  ret = FALSE;
3353  }
3354 
3355  HeapFree(GetProcessHeap(), 0, PropertyBufferW);
3356  return ret;
3357 }
3358 
3359 /***********************************************************************
3360  * SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
3361  */
3365  DWORD Property,
3367  PBYTE PropertyBuffer,
3370 {
3371  BOOL ret = FALSE;
3372  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3373  struct DeviceInfo *devInfo;
3374 
3375  TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
3376  Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
3377  RequiredSize);
3378 
3379  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3380  {
3382  return FALSE;
3383  }
3384  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3385  {
3387  return FALSE;
3388  }
3389  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3390  || !DeviceInfoData->Reserved)
3391  {
3393  return FALSE;
3394  }
3395  devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
3396  if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3397  && PropertyMap[Property].nameW)
3398  {
3400  HKEY hKey;
3401  LONG l;
3402  hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
3403  if (hKey == INVALID_HANDLE_VALUE)
3404  return FALSE;
3405  l = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
3406  NULL, PropertyRegDataType, PropertyBuffer, &size);
3407  RegCloseKey(hKey);
3408 
3409  if (RequiredSize)
3410  *RequiredSize = size;
3411  switch(l) {
3412  case ERROR_SUCCESS:
3413  if (PropertyBuffer != NULL || size == 0)
3414  ret = TRUE;
3415  else
3417  break;
3418  case ERROR_MORE_DATA:
3420  break;
3421  default:
3422  SetLastError(l);
3423  }
3424  }
3425  else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
3426  {
3427  DWORD required = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
3428 
3429  if (PropertyRegDataType)
3430  *PropertyRegDataType = REG_SZ;
3431  if (RequiredSize)
3432  *RequiredSize = required;
3433  if (PropertyBufferSize >= required)
3434  {
3435  strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
3436  ret = TRUE;
3437  }
3438  else
3440  }
3441  else
3442  {
3443  ERR("Property 0x%lx not implemented\n", Property);
3445  }
3446  return ret;
3447 }
3448 
3449 /***********************************************************************
3450  * SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
3451  */
3455  DWORD Property,
3456  const BYTE *PropertyBuffer,
3458 {
3459  BOOL ret = FALSE;
3460  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3461 
3462  TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
3463  PropertyBuffer, PropertyBufferSize);
3464 
3465  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3466  {
3468  return FALSE;
3469  }
3470  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3471  {
3473  return FALSE;
3474  }
3475  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3476  || !DeviceInfoData->Reserved)
3477  {
3479  return FALSE;
3480  }
3481 
3482  FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
3483  Property, PropertyBuffer, PropertyBufferSize);
3485  return ret;
3486 }
3487 
3488 /***********************************************************************
3489  * SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
3490  */
3494  DWORD Property,
3495  const BYTE *PropertyBuffer,
3497 {
3498  BOOL ret = FALSE;
3499  struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
3500 
3501  TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
3502  PropertyBuffer, PropertyBufferSize);
3503 
3504  if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
3505  {
3507  return FALSE;
3508  }
3509  if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3510  {
3512  return FALSE;
3513  }
3514  if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
3515  || !DeviceInfoData->Reserved)
3516  {
3518  return FALSE;
3519  }
3520  if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
3521  && PropertyMap[Property].nameW)
3522  {
3523  HKEY hKey;
3524  LONG l;
3525  hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
3526  if (hKey == INVALID_HANDLE_VALUE)
3527  return FALSE;
3528  /* Write new data */
3529  l = RegSetValueExW(
3530  hKey, PropertyMap[Property].nameW, 0,
3531  PropertyMap[Property].regType, PropertyBuffer,
3532  PropertyBufferSize);
3533  if (!l)
3534  ret = TRUE;
3535  else
3536  SetLastError(l);
3537  RegCloseKey(hKey);
3538  }
3539  else
3540  {
3541  ERR("Property 0x%lx not implemented\n", Property);
3543  }
3544 
3545  TRACE("Returning %d\n", ret);
3546  return ret;
3547 }
3548 
3549 /***********************************************************************
3550  * SetupDiInstallClassA (SETUPAPI.@)
3551  */
3553  HWND hwndParent,
3554  PCSTR InfFileName,
3555  DWORD Flags,
3556  HSPFILEQ FileQueue)
3557 {
3558  return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3559 }
3560 
3561 /***********************************************************************
3562  * SetupDiInstallClassExA (SETUPAPI.@)
3563  */
3564 BOOL WINAPI
3567  IN PCSTR InfFileName OPTIONAL,
3568  IN DWORD Flags,
3569  IN HSPFILEQ FileQueue OPTIONAL,
3570  IN CONST GUID *InterfaceClassGuid OPTIONAL,
3571  IN PVOID Reserved1,
3572  IN PVOID Reserved2)
3573 {
3574  PWSTR InfFileNameW = NULL;
3575  BOOL Result;
3576 
3577  if (!InfFileName)
3578  {
3580  return FALSE;
3581  }
3582  else
3583  {
3584  InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
3585  if (InfFileNameW == NULL)
3586  {
3588  return FALSE;
3589  }
3590  }
3591 
3592  Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
3593  FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
3594 
3595  MyFree(InfFileNameW);
3596 
3597  return Result;
3598 }
3599 
3601 {
3602  WCHAR FullBuffer[MAX_PATH];
3605  HKEY hClassKey;
3607 
3608  /* Obtain the Class GUID for this class */
3609  if (!SetupGetLineTextW(NULL,
3610  hInf,
3611  Version,
3613  Buffer,
3614  sizeof(Buffer) / sizeof(WCHAR),
3615  &RequiredSize))
3616  {
3617  return INVALID_HANDLE_VALUE;
3618  }
3619 
3620  /* Build the corresponding registry key name */
3621  lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3622  lstrcatW(FullBuffer, BackSlash);
3623  lstrcatW(FullBuffer, Buffer);
3624 
3625  /* Obtain the Class name for this class */
3626  if (!SetupGetLineTextW(NULL,
3627  hInf,
3628  Version,
3630  Buffer,
3631  sizeof(Buffer) / sizeof(WCHAR),
3632  &RequiredSize))
3633  {
3634  return INVALID_HANDLE_VALUE;
3635  }
3636 
3637  /* Try to open or create the registry key */
3638  TRACE("Opening class key %s\n", debugstr_w(FullBuffer));
3639 #if 0 // I keep this for reference...
3641  FullBuffer,
3642  0,
3643  KEY_SET_VALUE,
3644  &hClassKey))
3645  {
3646  /* Use RegCreateKeyExW */
3647  }
3648 #endif
3650  FullBuffer,
3651  0,
3652  NULL,
3654  KEY_SET_VALUE,
3655  NULL,
3656  &hClassKey,
3657  &Disposition))
3658  {
3659  ERR("RegCreateKeyExW(%s) failed\n", debugstr_w(FullBuffer));
3660  return INVALID_HANDLE_VALUE;
3661  }
3662  if (Disposition == REG_CREATED_NEW_KEY)
3663  TRACE("The class key %s was successfully created\n", debugstr_w(FullBuffer));
3664  else
3665  TRACE("The class key %s was successfully opened\n", debugstr_w(FullBuffer));
3666 
3667  TRACE( "setting value %s to %s\n", debugstr_w(REGSTR_VAL_CLASS), debugstr_w(Buffer) );
3668  if (RegSetValueExW(hClassKey,
3670  0,
3671  REG_SZ,
3672  (LPBYTE)Buffer,
3673  RequiredSize * sizeof(WCHAR)))
3674  {
3675  RegCloseKey(hClassKey);
3677  FullBuffer);
3678  return INVALID_HANDLE_VALUE;
3679  }
3680 
3681  return hClassKey;
3682 }
3683 
3684 /***********************************************************************
3685  * SetupDiInstallClassW (SETUPAPI.@)
3686  */
3688  HWND hwndParent,
3689  PCWSTR InfFileName,
3690  DWORD Flags,
3691  HSPFILEQ FileQueue)
3692 {
3693  return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3694 }
3695 
3696 
3697 /***********************************************************************
3698  * SetupDiOpenClassRegKey (SETUPAPI.@)
3699  */
3701  const GUID* ClassGuid,
3702  REGSAM samDesired)
3703 {
3704  return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3706 }
3707 
3708 
3709 /***********************************************************************
3710  * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3711  */
3713  const GUID* ClassGuid,
3714  REGSAM samDesired,
3715  DWORD Flags,
3717  PVOID Reserved)
3718 {
3719  PWSTR MachineNameW = NULL;
3720  HKEY hKey;
3721 
3722  TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3723  Flags, debugstr_a(MachineName), Reserved);
3724 
3725  if (MachineName)
3726  {
3727  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3728  if (MachineNameW == NULL)
3729  return INVALID_HANDLE_VALUE;
3730  }
3731 
3732  hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3733  Flags, MachineNameW, Reserved);
3734 
3735  MyFree(MachineNameW);
3736 
3737  return hKey;
3738 }
3739 
3740 
3741 /***********************************************************************
3742  * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3743  */
3745  const GUID* ClassGuid,
3746  REGSAM samDesired,
3747  DWORD Flags,
3749  PVOID Reserved)
3750 {
3751  HKEY HKLM;
3752  HKEY hClassesKey;
3753  HKEY key;
3754  LPCWSTR lpKeyName;
3755  LONG l;
3756 
3757  TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3758  Flags, debugstr_w(MachineName), Reserved);
3759 
3760  if (MachineName != NULL)
3761  {
3762  l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3763  if (l != ERROR_SUCCESS)
3764  {
3765  SetLastError(l);
3766  return INVALID_HANDLE_VALUE;
3767  }
3768  }
3769  else
3770  HKLM = HKEY_LOCAL_MACHINE;
3771 
3772  if (Flags == DIOCR_INSTALLER)
3773  {
3774  lpKeyName = REGSTR_PATH_CLASS_NT;
3775  }
3776  else if (Flags == DIOCR_INTERFACE)
3777  {
3778  lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3779  }
3780  else
3781  {
3782  ERR("Invalid Flags parameter!\n");
3784  if (MachineName != NULL) RegCloseKey(HKLM);
3785  return INVALID_HANDLE_VALUE;
3786  }
3787 
3788  if (!ClassGuid)
3789  {
3790  if ((l = RegOpenKeyExW(HKLM,
3791  lpKeyName,
3792  0,
3793  samDesired,
3794  &hClassesKey)))
3795  {
3797  hClassesKey = INVALID_HANDLE_VALUE;
3798  }
3799  if (MachineName != NULL)
3800  RegCloseKey(HKLM);
3801  key = hClassesKey;
3802  }
3803  else
3804  {
3805  WCHAR bracedGuidString[39];
3806 
3807  SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3808 
3809  if (!(l = RegOpenKeyExW(HKLM,
3810  lpKeyName,
3811  0,
3812  samDesired,
3813  &hClassesKey)))
3814  {
3815  if (MachineName != NULL)
3816  RegCloseKey(HKLM);
3817 
3818  if ((l = RegOpenKeyExW(hClassesKey,
3819  bracedGuidString,
3820  0,
3821  samDesired,
3822  &key)))
3823  {
3824  SetLastError(l);
3825  key = INVALID_HANDLE_VALUE;
3826  }
3827  RegCloseKey(hClassesKey);
3828  }
3829  else
3830  {
3831  if (MachineName != NULL) RegCloseKey(HKLM);
3832  SetLastError(l);
3833  key = INVALID_HANDLE_VALUE;
3834  }
3835  }
3836 
3837  return key;
3838 }
3839 
3840 /***********************************************************************
3841  * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3842  */
3846  DWORD OpenFlags,
3847  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3848 {
3849  struct DeviceInfoSet * list;
3850  PCWSTR pEnd;
3851  DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3852  CLSID ClassId;
3853  WCHAR Buffer[MAX_PATH + 1];
3854  WCHAR SymBuffer[MAX_PATH + 1];
3855  WCHAR InstancePath[MAX_PATH + 1];
3856  HKEY hKey, hDevKey, hSymKey;
3857  struct DeviceInfo * deviceInfo;
3858  struct DeviceInterface *deviceInterface;
3859  BOOL Ret;
3860  PLIST_ENTRY ItemList;
3861  PLIST_ENTRY InterfaceListEntry;
3862 
3863  TRACE("%p %s %08x %p\n",
3864  DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3865 
3866 
3867  if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3868  {
3870  return FALSE;
3871  }
3872 
3873  if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3874  {
3876  return FALSE;
3877  }
3878 
3879  list = (struct DeviceInfoSet * )DeviceInfoSet;
3880 
3881  dwLength = wcslen(DevicePath);
3882  if (dwLength < 39)
3883  {
3884  /* path must be at least a guid length + L'\0' */
3886  return FALSE;
3887  }
3888 
3889  if (DevicePath[0] != L'\\' ||
3890  DevicePath[1] != L'\\' ||
3891  (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3892  DevicePath[3] != L'\\')
3893  {
3894  /* invalid formatted path */
3896  return FALSE;
3897  }
3898 
3899  /* check for reference strings */
3900  pEnd = wcschr(&DevicePath[4], L'\\');
3901  if (!pEnd)
3902  {
3903  /* no reference string */
3904  pEnd = DevicePath + dwLength;
3905  }
3906 
3907  /* copy guid */
3908  wcscpy(Buffer, pEnd - 37);
3909  Buffer[36] = L'\0';
3910 
3911  dwError = UuidFromStringW(Buffer, &ClassId);
3912  if (dwError != NOERROR)
3913  {
3914  /* invalid formatted path */
3916  return FALSE;
3917  }
3918 
3920 
3921  if (hKey == INVALID_HANDLE_VALUE)
3922  {
3923  /* invalid device class */
3924  return FALSE;
3925  }
3926 
3927  ItemList = list->ListHead.Flink;
3928  while (ItemList != &list->ListHead)
3929  {
3930  deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3931  InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3932  while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3933  {
3934  deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3935  if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3936  {
3937  InterfaceListEntry = InterfaceListEntry->Flink;
3938  continue;
3939  }
3940 
3941  if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3942  {
3943  if (DeviceInterfaceData)
3944  {
3945  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3946  DeviceInterfaceData->Flags = deviceInterface->Flags;
3947  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3948  }
3949 
3950  return TRUE;
3951  }
3952 
3953  }
3954  }
3955 
3956 
3957  dwIndex = 0;
3958  do
3959  {
3960  Buffer[0] = 0;
3961  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3962  dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3963 
3964  if (dwError != ERROR_SUCCESS)
3965  break;
3966 
3967  if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3968  break;
3969 
3970  dwSubIndex = 0;
3971  InstancePath[0] = 0;
3972  dwKeyName = sizeof(InstancePath);
3973 
3974  dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3975 
3976  while(TRUE)
3977  {
3978  Buffer[0] = 0;
3979  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3980  dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3981 
3982  if (dwError != ERROR_SUCCESS)
3983  break;
3984 
3985  dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3986  if (dwError != ERROR_SUCCESS)
3987  break;
3988 
3989  /* query for symbolic link */
3990  dwKeyName = sizeof(SymBuffer);
3991  SymBuffer[0] = L'\0';
3992  dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
3993 
3994  if (dwError != ERROR_SUCCESS)
3995  {
3996  RegCloseKey(hSymKey);
3997  break;
3998  }
3999 
4000  if (!wcsicmp(SymBuffer, DevicePath))
4001  {
4002  Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
4003  RegCloseKey(hSymKey);
4004  RegCloseKey(hDevKey);
4005  RegCloseKey(hKey);
4006 
4007  if (Ret)
4008  {
4009  deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
4010  if (deviceInterface)
4011  {
4012 
4013  CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
4014  deviceInterface->DeviceInfo = deviceInfo;
4015  deviceInterface->Flags = SPINT_ACTIVE; //FIXME
4016 
4017  wcscpy(deviceInterface->SymbolicLink, SymBuffer);
4018 
4019  InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
4020  InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4021 
4022 
4023  if (DeviceInterfaceData)
4024  {
4025  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
4026  DeviceInterfaceData->Flags = deviceInterface->Flags;
4027  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
4028  }
4029  else
4030  {
4031  Ret = FALSE;
4033  }
4034  }
4035  }
4036  else
4037  {
4038  HeapFree(GetProcessHeap(), 0, deviceInfo);
4039  Ret = FALSE;
4040  }
4041  return Ret;
4042  }
4043  RegCloseKey(hSymKey);
4044  dwSubIndex++;
4045  }
4046 
4047  RegCloseKey(hDevKey);
4048  dwIndex++;
4049  } while(TRUE);
4050 
4051  RegCloseKey(hKey);
4052  return FALSE;
4053 }
4054 
4055 /***********************************************************************
4056  * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
4057  */
4060  PCSTR DevicePath,
4061  DWORD OpenFlags,
4062  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
4063 {
4064  LPWSTR DevicePathW = NULL;
4065  BOOL bResult;
4066 
4067  TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
4068 
4069  DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
4070  if (DevicePathW == NULL)
4071  return FALSE;
4072 
4073  bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
4074  DevicePathW, OpenFlags, DeviceInterfaceData);
4075 
4076  MyFree(DevicePathW);
4077 
4078  return bResult;
4079 }
4080 
4081 /***********************************************************************
4082  * SetupDiSetClassInstallParamsA (SETUPAPI.@)
4083  */
4089 {
4090  FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4091  ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4092  return FALSE;
4093 }
4094 
4095 static BOOL WINAPI
4099 {
4100  return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
4101 }
4102 
4103 /***********************************************************************
4104  * SetupDiCallClassInstaller (SETUPAPI.@)
4105  */
4107  DI_FUNCTION InstallFunction,
4110 {
4111  BOOL ret = FALSE;
4112 
4113  TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
4114 
4115  if (!DeviceInfoSet)
4117  else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4119  else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4121  else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4123  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4125  else
4126  {
4128 #define CLASS_COINSTALLER 0x1
4129 #define DEVICE_COINSTALLER 0x2
4130 #define CLASS_INSTALLER 0x4
4131  UCHAR CanHandle = 0;
4132  DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
4133 
4134  switch (InstallFunction)
4135  {
4138  break;
4141  break;
4142  case DIF_ALLOW_INSTALL:
4143  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4144  break;
4145  case DIF_DETECT:
4146  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4147  break;
4149  CanHandle = CLASS_INSTALLER;
4150  break;
4151  case DIF_INSTALLDEVICE:
4153  DefaultHandler = SetupDiInstallDevice;
4154  break;
4156  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4157  DefaultHandler = SetupDiInstallDriverFiles;
4158  break;
4159  case DIF_INSTALLINTERFACES:
4161  DefaultHandler = SetupDiInstallDeviceInterfaces;
4162  break;
4165  break;
4167  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4168  break;
4170  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4171  break;
4173  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4174  break;
4176  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4177  break;
4178  case DIF_POWERMESSAGEWAKE:
4180  break;
4181  case DIF_PROPERTYCHANGE:
4183  DefaultHandler = SetupDiChangeState;
4184  break;
4186  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4187  DefaultHandler = SetupDiRegisterCoDeviceInstallers;
4188  break;
4189  case DIF_REGISTERDEVICE:
4190  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4191  DefaultHandler = IntSetupDiRegisterDeviceInfo;
4192  break;
4193  case DIF_REMOVE:
4195  DefaultHandler = SetupDiRemoveDevice;
4196  break;
4198  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4199  DefaultHandler = SetupDiSelectBestCompatDrv;
4200  break;
4201  case DIF_SELECTDEVICE:
4202  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4203  DefaultHandler = SetupDiSelectDevice;
4204  break;
4205  case DIF_TROUBLESHOOTER:
4207  break;
4208  case DIF_UNREMOVE:
4210  DefaultHandler = SetupDiUnremoveDevice;
4211  break;
4212  default:
4213  ERR("Install function %u not supported\n", InstallFunction);
4215  }
4216 
4217  InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4218  if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
4219  /* Don't process this call, as a parameter is invalid */
4220  CanHandle = 0;
4221 
4222  if (CanHandle != 0)
4223  {
4224  LIST_ENTRY ClassCoInstallersListHead;
4225  LIST_ENTRY DeviceCoInstallersListHead;
4226  HMODULE ClassInstallerLibrary = NULL;
4227  CLASS_INSTALL_PROC ClassInstaller = NULL;
4229  PLIST_ENTRY ListEntry;
4230  HKEY hKey;
4231  DWORD dwRegType, dwLength;
4232  DWORD rc = NO_ERROR;
4233 
4234  InitializeListHead(&ClassCoInstallersListHead);
4235  InitializeListHead(&DeviceCoInstallersListHead);
4236 
4237  if (CanHandle & DEVICE_COINSTALLER)
4238  {
4239  hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
4240  if (hKey != INVALID_HANDLE_VALUE)
4241  {
4242  rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
4243  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4244  {
4245  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4246  if (KeyBuffer != NULL)
4247  {
4248  rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4249  if (rc == ERROR_SUCCESS)
4250  {
4251  LPWSTR ptr;
4252  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4253  {
4254  /* Add coinstaller to DeviceCoInstallersListHead list */
4255  struct CoInstallerElement *coinstaller;
4256  TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4257  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4258  if (!coinstaller)
4259  continue;
4260  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4261  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4262  InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4263  else
4264  HeapFree(GetProcessHeap(), 0, coinstaller);
4265  }
4266  }
4267  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4268  }
4269  }
4270  RegCloseKey(hKey);
4271  }
4272  }
4273  if (CanHandle & CLASS_COINSTALLER)
4274  {
4275  rc = RegOpenKeyExW(
4278  0, /* Options */
4280  &hKey);
4281  if (rc == ERROR_SUCCESS)
4282  {
4283  LPWSTR lpGuidString;
4284  if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
4285  {
4286  rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
4287  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4288  {
4289  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4290  if (KeyBuffer != NULL)
4291  {
4292  rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4293  if (rc == ERROR_SUCCESS)
4294  {
4295  LPWSTR ptr;
4296  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4297  {
4298  /* Add coinstaller to ClassCoInstallersListHead list */
4299  struct CoInstallerElement *coinstaller;
4300  TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4301  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4302  if (!coinstaller)
4303  continue;
4304  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4305  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4306  InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4307  else
4308  HeapFree(GetProcessHeap(), 0, coinstaller);
4309  }
4310  }
4311  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4312  }
4313  }
4314  RpcStringFreeW(&lpGuidString);
4315  }
4316  RegCloseKey(hKey);
4317  }
4318  }
4319  if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4320  {
4321  hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4322  if (hKey != INVALID_HANDLE_VALUE)
4323  {
4324  rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4325  if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4326  {
4327  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4328  if (KeyBuffer != NULL)
4329  {
4330  rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4331  if (rc == ERROR_SUCCESS)
4332  {
4333  /* Get ClassInstaller function pointer */
4334  TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4335  if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4336  {
4337  InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4338  SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4339  }
4340  }
4341  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4342  }
4343  }
4344  RegCloseKey(hKey);
4345  }
4346  }
4347 
4348  /* Call Class co-installers */
4349  Context.PostProcessing = FALSE;
4350  rc = NO_ERROR;
4351  ListEntry = ClassCoInstallersListHead.Flink;
4352  while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4353  {
4354  struct CoInstallerElement *coinstaller;
4355  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4356  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4357  coinstaller->PrivateData = Context.PrivateData;
4359  {
4360  coinstaller->DoPostProcessing = TRUE;
4361  rc = NO_ERROR;
4362  }
4363  ListEntry = ListEntry->Flink;
4364  }
4365 
4366  /* Call Device co-installers */
4367  ListEntry = DeviceCoInstallersListHead.Flink;
4368  while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4369  {
4370  struct CoInstallerElement *coinstaller;
4371  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4372  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4373  coinstaller->PrivateData = Context.PrivateData;
4375  {
4376  coinstaller->DoPostProcessing = TRUE;
4377  rc = NO_ERROR;
4378  }
4379  ListEntry = ListEntry->Flink;
4380  }
4381 
4382  /* Call Class installer */
4383  if (ClassInstaller)
4384  {
4385  rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4386  FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4387  }
4388  else
4389  rc = ERROR_DI_DO_DEFAULT;
4390 
4391  /* Call default handler */
4392  if (rc == ERROR_DI_DO_DEFAULT)
4393  {
4394  if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4395  {
4396  if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4397  rc = NO_ERROR;
4398  else
4399  rc = GetLastError();
4400  }
4401  else
4402  rc = NO_ERROR;
4403  }
4404 
4405  /* Call Class co-installers that required postprocessing */
4406  Context.PostProcessing = TRUE;
4407  ListEntry = ClassCoInstallersListHead.Flink;
4408  while (ListEntry != &ClassCoInstallersListHead)
4409  {
4410  struct CoInstallerElement *coinstaller;
4411  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4412  if (coinstaller->DoPostProcessing)
4413  {
4414  Context.InstallResult = rc;
4415  Context.PrivateData = coinstaller->PrivateData;
4416  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4417  }
4418  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4419  ListEntry = ListEntry->Flink;
4420  }
4421 
4422  /* Call Device co-installers that required postprocessing */
4423  ListEntry = DeviceCoInstallersListHead.Flink;
4424  while (ListEntry != &DeviceCoInstallersListHead)
4425  {
4426  struct CoInstallerElement *coinstaller;
4427  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4428  if (coinstaller->DoPostProcessing)
4429  {
4430  Context.InstallResult = rc;
4431  Context.PrivateData = coinstaller->PrivateData;
4432  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4433  }
4434  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4435  ListEntry = ListEntry->Flink;
4436  }
4437 
4438  /* Free allocated memory */
4439  while (!IsListEmpty(&ClassCoInstallersListHead))
4440  {
4441  ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4442  HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4443  }
4444  while (!IsListEmpty(&DeviceCoInstallersListHead))
4445  {
4446  ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4447  HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4448  }
4449 
4450  ret = (rc == NO_ERROR);
4451  }
4452  }
4453 
4454  TRACE("Returning %d\n", ret);
4455  return ret;
4456 }
4457 
4458 /***********************************************************************
4459  * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4460  */
4465 {
4466  SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4467  BOOL ret = FALSE;
4468 
4469  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4470 
4471  if (DeviceInstallParams == NULL)
4473  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4475  else
4476  {
4477  deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4478  ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4479 
4480  if (ret)
4481  {
4482  /* Do W->A conversion */
4483  memcpy(
4484  DeviceInstallParams,
4485  &deviceInstallParamsW,
4486  FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4487  if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4488  DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4489  {
4490  DeviceInstallParams->DriverPath[0] = '\0';
4491  ret = FALSE;
4492  }
4493  }
4494  }
4495 
4496  TRACE("Returning %d\n", ret);
4497  return ret;
4498 }
4499 
4500 /***********************************************************************
4501  * SetupDiGetDeviceInfoListClass (SETUPAPI.@)
4502  */
4503 BOOL WINAPI
4506  OUT LPGUID ClassGuid)
4507 {
4508  struct DeviceInfoSet *list;
4509  BOOL ret = FALSE;
4510 
4511  TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
4512 
4513  if (!DeviceInfoSet)
4515  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4517  else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4519  else
4520  {
4521  memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
4522 
4523  ret = TRUE;
4524  }
4525 
4526  TRACE("Returning %d\n", ret);
4527  return ret;
4528 }
4529 
4530 /***********************************************************************
4531  * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4532  */
4533 BOOL WINAPI
4538 {
4539  struct DeviceInfoSet *list;
4540  BOOL ret = FALSE;
4541 
4542  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4543 
4544  if (!DeviceInfoSet)
4546  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4548  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4550  else if (!DeviceInstallParams)
4552  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4554  else
4555  {
4557 
4558  if (DeviceInfoData)
4559  Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4560  else
4561  Source = &list->InstallParams;
4562 
4563  ret = TRUE;
4564 
4565  _SEH2_TRY
4566  {
4567  memcpy(DeviceInstallParams, Source, Source->cbSize);
4568  }
4570  {
4572  ret = FALSE;
4573  }
4574  _SEH2_END;
4575  }
4576 
4577  TRACE("Returning %d\n", ret);
4578  return ret;
4579 }
4580 
4581 static BOOL
4584 {
4585  DWORD SupportedFlags =
4586  DI_NOVCP | /* 0x00000008 */
4587  DI_DIDCOMPAT | /* 0x00000010 */
4588  DI_DIDCLASS | /* 0x00000020 */
4589  DI_NEEDRESTART | /* 0x00000080 */
4590  DI_NEEDREBOOT | /* 0x00000100 */
4591  DI_RESOURCEPAGE_ADDED | /* 0x00002000 */
4592  DI_PROPERTIES_CHANGE | /* 0x00004000 */
4593  DI_ENUMSINGLEINF | /* 0x00010000 */
4594  DI_DONOTCALLCONFIGMG | /* 0x00020000 */
4595  DI_CLASSINSTALLPARAMS | /* 0x00100000 */
4596  DI_NODI_DEFAULTACTION | /* 0x00200000 */
4597  DI_QUIETINSTALL | /* 0x00800000 */
4598  DI_NOFILECOPY | /* 0x01000000 */
4599  DI_DRIVERPAGE_ADDED; /* 0x04000000 */
4600  DWORD SupportedFlagsEx =
4601  DI_FLAGSEX_CI_FAILED | /* 0x00000004 */
4602  DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
4603  DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
4604  DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
4605  DI_FLAGSEX_NO_DRVREG_MODIFY | /* 0x00008000 */
4606  DI_FLAGSEX_INSTALLEDDRIVER; /* 0x04000000 */
4607  BOOL ret = FALSE;
4608 
4609  /* FIXME: add support for more flags */
4610 
4611  /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4612  * It should be checked before accessing to other values
4613  * of the SP_DEVINSTALL_PARAMS structure */
4614 
4615  if (DeviceInstallParams->Flags & ~SupportedFlags)
4616  {
4617  FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4619  }
4620  else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4621  {
4622  FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4624  }
4625  else if ((DeviceInstallParams->Flags & DI_NOVCP)
4626  && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4628  else
4629  {
4630  /* FIXME: check Reserved field */
4631  ret = TRUE;
4632  }
4633 
4634  return ret;
4635 }
4636 
4637 /***********************************************************************
4638  * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4639  */
4640 BOOL WINAPI
4645 {
4646  struct DeviceInfoSet *list;
4647  BOOL ret = FALSE;
4648 
4649  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4650 
4651  if (!DeviceInfoSet)
4653  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4655  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4657  else if (!DeviceInstallParams)
4659  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4661  else if (CheckDeviceInstallParameters(DeviceInstallParams))
4662  {
4664 
4665  if (DeviceInfoData)
4666  Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4667  else
4668  Destination = &list->InstallParams;
4669  memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4670  ret = TRUE;
4671  }
4672 
4673  TRACE("Returning %d\n", ret);
4674  return ret;
4675 }
4676 
4677 /***********************************************************************
4678  * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4679  */
4680 BOOL WINAPI
4685 {
4686  SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4687  int len = 0;
4688  BOOL ret = FALSE;
4689 
4690  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4691 
4692  if (DeviceInstallParams == NULL)
4694  else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4696  else
4697  {
4698  memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4699  deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4700  len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4701  if (!len)
4702  {
4703  ERR("DrivePath is NULL\n");
4704  ret = FALSE;
4705  }
4706  else
4707  {
4708  MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4709  ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4710  }
4711  }
4712 
4713  TRACE("Returning %d\n", ret);
4714  return ret;
4715 }
4716 
4717 static HKEY
4719  IN HKEY HKLM,
4720  IN DWORD HwProfile,
4721  IN DWORD samDesired)
4722 {
4723  HKEY hHWProfilesKey = NULL;
4724  HKEY hHWProfileKey = NULL;
4726  LONG rc;
4727 
4728  rc = RegOpenKeyExW(HKLM,
4730  0,
4731  READ_CONTROL,
4732  &hHWProfilesKey);
4733  if (rc != ERROR_SUCCESS)
4734  {
4735  SetLastError(rc);
4736  goto cleanup;
4737  }
4738  if (HwProfile == 0)
4739  {
4740  rc = RegOpenKeyExW(hHWProfilesKey,
4742  0,
4744  &hHWProfileKey);
4745  }
4746  else
4747  {
4748  WCHAR subKey[5];
4749  snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4750  subKey[4] = '\0';
4751  rc = RegOpenKeyExW(hHWProfilesKey,
4752  subKey,
4753  0,
4755  &hHWProfileKey);
4756  }
4757  if (rc != ERROR_SUCCESS)
4758  {
4759  SetLastError(rc);
4760  goto cleanup;
4761  }
4762  ret = hHWProfileKey;
4763 
4764 cleanup:
4765  if (hHWProfilesKey != NULL)
4766  RegCloseKey(hHWProfilesKey);
4767  if (hHWProfileKey != NULL && hHWProfileKey != ret)
4768  RegCloseKey(hHWProfileKey);
4769  return ret;
4770 }
4771 
4772 static BOOL
4774  struct DeviceInfoSet *deviceInfoSet,
4775  struct DeviceInfo *deviceInfo)
4776 {
4778 
4779  ListEntry = deviceInfoSet->ListHead.Flink;
4780  while (ListEntry != &deviceInfoSet->