ReactOS  r74227
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  static const WCHAR slash[] = { '\\',0 };
3603  WCHAR FullBuffer[MAX_PATH];
3606  HKEY hClassKey;
3607 
3608  if (!SetupGetLineTextW(NULL,
3609  hInf,
3610  Version,
3612  Buffer,
3613  MAX_PATH,
3614  &RequiredSize))
3615  {
3616  return INVALID_HANDLE_VALUE;
3617  }
3618 
3619  lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
3620  lstrcatW(FullBuffer, slash);
3621  lstrcatW(FullBuffer, Buffer);
3622 
3624  FullBuffer,
3625  0,
3626  KEY_SET_VALUE,
3627  &hClassKey))
3628  {
3629  if (!SetupGetLineTextW(NULL,
3630  hInf,
3631  Version,
3633  Buffer,
3634  MAX_PATH,
3635  &RequiredSize))
3636  {
3637  return INVALID_HANDLE_VALUE;
3638  }
3639 
3641  FullBuffer,
3642  0,
3643  NULL,
3645  KEY_SET_VALUE,
3646  NULL,
3647  &hClassKey,
3648  NULL))
3649  {
3650  return INVALID_HANDLE_VALUE;
3651  }
3652  }
3653 
3654  if (RegSetValueExW(hClassKey,
3656  0,
3657  REG_SZ,
3658  (LPBYTE)Buffer,
3659  RequiredSize * sizeof(WCHAR)))
3660  {
3661  RegCloseKey(hClassKey);
3663  FullBuffer);
3664  return INVALID_HANDLE_VALUE;
3665  }
3666 
3667  return hClassKey;
3668 }
3669 
3670 /***********************************************************************
3671  * SetupDiInstallClassW (SETUPAPI.@)
3672  */
3674  HWND hwndParent,
3675  PCWSTR InfFileName,
3676  DWORD Flags,
3677  HSPFILEQ FileQueue)
3678 {
3679  return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
3680 }
3681 
3682 
3683 /***********************************************************************
3684  * SetupDiOpenClassRegKey (SETUPAPI.@)
3685  */
3687  const GUID* ClassGuid,
3688  REGSAM samDesired)
3689 {
3690  return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3692 }
3693 
3694 
3695 /***********************************************************************
3696  * SetupDiOpenClassRegKeyExA (SETUPAPI.@)
3697  */
3699  const GUID* ClassGuid,
3700  REGSAM samDesired,
3701  DWORD Flags,
3703  PVOID Reserved)
3704 {
3705  PWSTR MachineNameW = NULL;
3706  HKEY hKey;
3707 
3708  TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3709  Flags, debugstr_a(MachineName), Reserved);
3710 
3711  if (MachineName)
3712  {
3713  MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
3714  if (MachineNameW == NULL)
3715  return INVALID_HANDLE_VALUE;
3716  }
3717 
3718  hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
3719  Flags, MachineNameW, Reserved);
3720 
3721  MyFree(MachineNameW);
3722 
3723  return hKey;
3724 }
3725 
3726 
3727 /***********************************************************************
3728  * SetupDiOpenClassRegKeyExW (SETUPAPI.@)
3729  */
3731  const GUID* ClassGuid,
3732  REGSAM samDesired,
3733  DWORD Flags,
3735  PVOID Reserved)
3736 {
3737  HKEY HKLM;
3738  HKEY hClassesKey;
3739  HKEY key;
3740  LPCWSTR lpKeyName;
3741  LONG l;
3742 
3743  TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
3744  Flags, debugstr_w(MachineName), Reserved);
3745 
3746  if (MachineName != NULL)
3747  {
3748  l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
3749  if (l != ERROR_SUCCESS)
3750  {
3751  SetLastError(l);
3752  return INVALID_HANDLE_VALUE;
3753  }
3754  }
3755  else
3756  HKLM = HKEY_LOCAL_MACHINE;
3757 
3758  if (Flags == DIOCR_INSTALLER)
3759  {
3760  lpKeyName = REGSTR_PATH_CLASS_NT;
3761  }
3762  else if (Flags == DIOCR_INTERFACE)
3763  {
3764  lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
3765  }
3766  else
3767  {
3768  ERR("Invalid Flags parameter!\n");
3770  if (MachineName != NULL) RegCloseKey(HKLM);
3771  return INVALID_HANDLE_VALUE;
3772  }
3773 
3774  if (!ClassGuid)
3775  {
3776  if ((l = RegOpenKeyExW(HKLM,
3777  lpKeyName,
3778  0,
3779  samDesired,
3780  &hClassesKey)))
3781  {
3783  hClassesKey = INVALID_HANDLE_VALUE;
3784  }
3785  if (MachineName != NULL)
3786  RegCloseKey(HKLM);
3787  key = hClassesKey;
3788  }
3789  else
3790  {
3791  WCHAR bracedGuidString[39];
3792 
3793  SETUPDI_GuidToString(ClassGuid, bracedGuidString);
3794 
3795  if (!(l = RegOpenKeyExW(HKLM,
3796  lpKeyName,
3797  0,
3798  samDesired,
3799  &hClassesKey)))
3800  {
3801  if (MachineName != NULL)
3802  RegCloseKey(HKLM);
3803 
3804  if ((l = RegOpenKeyExW(hClassesKey,
3805  bracedGuidString,
3806  0,
3807  samDesired,
3808  &key)))
3809  {
3810  SetLastError(l);
3811  key = INVALID_HANDLE_VALUE;
3812  }
3813  RegCloseKey(hClassesKey);
3814  }
3815  else
3816  {
3817  if (MachineName != NULL) RegCloseKey(HKLM);
3818  SetLastError(l);
3819  key = INVALID_HANDLE_VALUE;
3820  }
3821  }
3822 
3823  return key;
3824 }
3825 
3826 /***********************************************************************
3827  * SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
3828  */
3832  DWORD OpenFlags,
3833  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
3834 {
3835  struct DeviceInfoSet * list;
3836  PCWSTR pEnd;
3837  DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
3838  CLSID ClassId;
3839  WCHAR Buffer[MAX_PATH + 1];
3840  WCHAR SymBuffer[MAX_PATH + 1];
3841  WCHAR InstancePath[MAX_PATH + 1];
3842  HKEY hKey, hDevKey, hSymKey;
3843  struct DeviceInfo * deviceInfo;
3844  struct DeviceInterface *deviceInterface;
3845  BOOL Ret;
3846  PLIST_ENTRY ItemList;
3847  PLIST_ENTRY InterfaceListEntry;
3848 
3849  TRACE("%p %s %08x %p\n",
3850  DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
3851 
3852 
3853  if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
3854  {
3856  return FALSE;
3857  }
3858 
3859  if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
3860  {
3862  return FALSE;
3863  }
3864 
3865  list = (struct DeviceInfoSet * )DeviceInfoSet;
3866 
3867  dwLength = wcslen(DevicePath);
3868  if (dwLength < 39)
3869  {
3870  /* path must be at least a guid length + L'\0' */
3872  return FALSE;
3873  }
3874 
3875  if (DevicePath[0] != L'\\' ||
3876  DevicePath[1] != L'\\' ||
3877  (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
3878  DevicePath[3] != L'\\')
3879  {
3880  /* invalid formatted path */
3882  return FALSE;
3883  }
3884 
3885  /* check for reference strings */
3886  pEnd = wcschr(&DevicePath[4], L'\\');
3887  if (!pEnd)
3888  {
3889  /* no reference string */
3890  pEnd = DevicePath + dwLength;
3891  }
3892 
3893  /* copy guid */
3894  wcscpy(Buffer, pEnd - 37);
3895  Buffer[36] = L'\0';
3896 
3897  dwError = UuidFromStringW(Buffer, &ClassId);
3898  if (dwError != NOERROR)
3899  {
3900  /* invalid formatted path */
3902  return FALSE;
3903  }
3904 
3906 
3907  if (hKey == INVALID_HANDLE_VALUE)
3908  {
3909  /* invalid device class */
3910  return FALSE;
3911  }
3912 
3913  ItemList = list->ListHead.Flink;
3914  while (ItemList != &list->ListHead)
3915  {
3916  deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
3917  InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
3918  while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
3919  {
3920  deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
3921  if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
3922  {
3923  InterfaceListEntry = InterfaceListEntry->Flink;
3924  continue;
3925  }
3926 
3927  if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
3928  {
3929  if (DeviceInterfaceData)
3930  {
3931  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
3932  DeviceInterfaceData->Flags = deviceInterface->Flags;
3933  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
3934  }
3935 
3936  return TRUE;
3937  }
3938 
3939  }
3940  }
3941 
3942 
3943  dwIndex = 0;
3944  do
3945  {
3946  Buffer[0] = 0;
3947  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3948  dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3949 
3950  if (dwError != ERROR_SUCCESS)
3951  break;
3952 
3953  if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
3954  break;
3955 
3956  dwSubIndex = 0;
3957  InstancePath[0] = 0;
3958  dwKeyName = sizeof(InstancePath);
3959 
3960  dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
3961 
3962  while(TRUE)
3963  {
3964  Buffer[0] = 0;
3965  dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
3966  dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
3967 
3968  if (dwError != ERROR_SUCCESS)
3969  break;
3970 
3971  dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
3972  if (dwError != ERROR_SUCCESS)
3973  break;
3974 
3975  /* query for symbolic link */
3976  dwKeyName = sizeof(SymBuffer);
3977  SymBuffer[0] = L'\0';
3978  dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
3979 
3980  if (dwError != ERROR_SUCCESS)
3981  {
3982  RegCloseKey(hSymKey);
3983  break;
3984  }
3985 
3986  if (!wcsicmp(SymBuffer, DevicePath))
3987  {
3988  Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
3989  RegCloseKey(hSymKey);
3990  RegCloseKey(hDevKey);
3991  RegCloseKey(hKey);
3992 
3993  if (Ret)
3994  {
3995  deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
3996  if (deviceInterface)
3997  {
3998 
3999  CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
4000  deviceInterface->DeviceInfo = deviceInfo;
4001  deviceInterface->Flags = SPINT_ACTIVE; //FIXME
4002 
4003  wcscpy(deviceInterface->SymbolicLink, SymBuffer);
4004 
4005  InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
4006  InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
4007 
4008 
4009  if (DeviceInterfaceData)
4010  {
4011  DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
4012  DeviceInterfaceData->Flags = deviceInterface->Flags;
4013  CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
4014  }
4015  else
4016  {
4017  Ret = FALSE;
4019  }
4020  }
4021  }
4022  else
4023  {
4024  HeapFree(GetProcessHeap(), 0, deviceInfo);
4025  Ret = FALSE;
4026  }
4027  return Ret;
4028  }
4029  RegCloseKey(hSymKey);
4030  dwSubIndex++;
4031  }
4032 
4033  RegCloseKey(hDevKey);
4034  dwIndex++;
4035  } while(TRUE);
4036 
4037  RegCloseKey(hKey);
4038  return FALSE;
4039 }
4040 
4041 /***********************************************************************
4042  * SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
4043  */
4046  PCSTR DevicePath,
4047  DWORD OpenFlags,
4048  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
4049 {
4050  LPWSTR DevicePathW = NULL;
4051  BOOL bResult;
4052 
4053  TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
4054 
4055  DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
4056  if (DevicePathW == NULL)
4057  return FALSE;
4058 
4059  bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
4060  DevicePathW, OpenFlags, DeviceInterfaceData);
4061 
4062  MyFree(DevicePathW);
4063 
4064  return bResult;
4065 }
4066 
4067 /***********************************************************************
4068  * SetupDiSetClassInstallParamsA (SETUPAPI.@)
4069  */
4075 {
4076  FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
4077  ClassInstallParams->InstallFunction, ClassInstallParamsSize);
4078  return FALSE;
4079 }
4080 
4081 static BOOL WINAPI
4085 {
4086  return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
4087 }
4088 
4089 /***********************************************************************
4090  * SetupDiCallClassInstaller (SETUPAPI.@)
4091  */
4093  DI_FUNCTION InstallFunction,
4096 {
4097  BOOL ret = FALSE;
4098 
4099  TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
4100 
4101  if (!DeviceInfoSet)
4103  else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
4105  else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4107  else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
4109  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4111  else
4112  {
4114 #define CLASS_COINSTALLER 0x1
4115 #define DEVICE_COINSTALLER 0x2
4116 #define CLASS_INSTALLER 0x4
4117  UCHAR CanHandle = 0;
4118  DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
4119 
4120  switch (InstallFunction)
4121  {
4124  break;
4127  break;
4128  case DIF_ALLOW_INSTALL:
4129  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4130  break;
4131  case DIF_DETECT:
4132  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4133  break;
4135  CanHandle = CLASS_INSTALLER;
4136  break;
4137  case DIF_INSTALLDEVICE:
4139  DefaultHandler = SetupDiInstallDevice;
4140  break;
4142  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4143  DefaultHandler = SetupDiInstallDriverFiles;
4144  break;
4145  case DIF_INSTALLINTERFACES:
4147  DefaultHandler = SetupDiInstallDeviceInterfaces;
4148  break;
4151  break;
4153  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4154  break;
4156  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4157  break;
4159  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4160  break;
4162  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4163  break;
4164  case DIF_POWERMESSAGEWAKE:
4166  break;
4167  case DIF_PROPERTYCHANGE:
4169  DefaultHandler = SetupDiChangeState;
4170  break;
4172  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4173  DefaultHandler = SetupDiRegisterCoDeviceInstallers;
4174  break;
4175  case DIF_REGISTERDEVICE:
4176  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4177  DefaultHandler = IntSetupDiRegisterDeviceInfo;
4178  break;
4179  case DIF_REMOVE:
4181  DefaultHandler = SetupDiRemoveDevice;
4182  break;
4184  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4185  DefaultHandler = SetupDiSelectBestCompatDrv;
4186  break;
4187  case DIF_SELECTDEVICE:
4188  CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
4189  DefaultHandler = SetupDiSelectDevice;
4190  break;
4191  case DIF_TROUBLESHOOTER:
4193  break;
4194  case DIF_UNREMOVE:
4196  DefaultHandler = SetupDiUnremoveDevice;
4197  break;
4198  default:
4199  ERR("Install function %u not supported\n", InstallFunction);
4201  }
4202 
4203  InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4204  if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
4205  /* Don't process this call, as a parameter is invalid */
4206  CanHandle = 0;
4207 
4208  if (CanHandle != 0)
4209  {
4210  LIST_ENTRY ClassCoInstallersListHead;
4211  LIST_ENTRY DeviceCoInstallersListHead;
4212  HMODULE ClassInstallerLibrary = NULL;
4213  CLASS_INSTALL_PROC ClassInstaller = NULL;
4215  PLIST_ENTRY ListEntry;
4216  HKEY hKey;
4217  DWORD dwRegType, dwLength;
4218  DWORD rc = NO_ERROR;
4219 
4220  InitializeListHead(&ClassCoInstallersListHead);
4221  InitializeListHead(&DeviceCoInstallersListHead);
4222 
4223  if (CanHandle & DEVICE_COINSTALLER)
4224  {
4225  hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
4226  if (hKey != INVALID_HANDLE_VALUE)
4227  {
4228  rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
4229  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4230  {
4231  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4232  if (KeyBuffer != NULL)
4233  {
4234  rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4235  if (rc == ERROR_SUCCESS)
4236  {
4237  LPWSTR ptr;
4238  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4239  {
4240  /* Add coinstaller to DeviceCoInstallersListHead list */
4241  struct CoInstallerElement *coinstaller;
4242  TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
4243  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4244  if (!coinstaller)
4245  continue;
4246  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4247  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4248  InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
4249  else
4250  HeapFree(GetProcessHeap(), 0, coinstaller);
4251  }
4252  }
4253  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4254  }
4255  }
4256  RegCloseKey(hKey);
4257  }
4258  }
4259  if (CanHandle & CLASS_COINSTALLER)
4260  {
4261  rc = RegOpenKeyExW(
4264  0, /* Options */
4266  &hKey);
4267  if (rc == ERROR_SUCCESS)
4268  {
4269  LPWSTR lpGuidString;
4270  if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
4271  {
4272  rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
4273  if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
4274  {
4275  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4276  if (KeyBuffer != NULL)
4277  {
4278  rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4279  if (rc == ERROR_SUCCESS)
4280  {
4281  LPWSTR ptr;
4282  for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
4283  {
4284  /* Add coinstaller to ClassCoInstallersListHead list */
4285  struct CoInstallerElement *coinstaller;
4286  TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
4287  coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
4288  if (!coinstaller)
4289  continue;
4290  ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
4291  if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
4292  InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
4293  else
4294  HeapFree(GetProcessHeap(), 0, coinstaller);
4295  }
4296  }
4297  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4298  }
4299  }
4300  RpcStringFreeW(&lpGuidString);
4301  }
4302  RegCloseKey(hKey);
4303  }
4304  }
4305  if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
4306  {
4307  hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
4308  if (hKey != INVALID_HANDLE_VALUE)
4309  {
4310  rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
4311  if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
4312  {
4313  LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
4314  if (KeyBuffer != NULL)
4315  {
4316  rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
4317  if (rc == ERROR_SUCCESS)
4318  {
4319  /* Get ClassInstaller function pointer */
4320  TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
4321  if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
4322  {
4323  InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
4324  SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
4325  }
4326  }
4327  HeapFree(GetProcessHeap(), 0, KeyBuffer);
4328  }
4329  }
4330  RegCloseKey(hKey);
4331  }
4332  }
4333 
4334  /* Call Class co-installers */
4335  Context.PostProcessing = FALSE;
4336  rc = NO_ERROR;
4337  ListEntry = ClassCoInstallersListHead.Flink;
4338  while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
4339  {
4340  struct CoInstallerElement *coinstaller;
4341  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4342  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4343  coinstaller->PrivateData = Context.PrivateData;
4345  {
4346  coinstaller->DoPostProcessing = TRUE;
4347  rc = NO_ERROR;
4348  }
4349  ListEntry = ListEntry->Flink;
4350  }
4351 
4352  /* Call Device co-installers */
4353  ListEntry = DeviceCoInstallersListHead.Flink;
4354  while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
4355  {
4356  struct CoInstallerElement *coinstaller;
4357  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4358  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4359  coinstaller->PrivateData = Context.PrivateData;
4361  {
4362  coinstaller->DoPostProcessing = TRUE;
4363  rc = NO_ERROR;
4364  }
4365  ListEntry = ListEntry->Flink;
4366  }
4367 
4368  /* Call Class installer */
4369  if (ClassInstaller)
4370  {
4371  rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
4372  FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
4373  }
4374  else
4375  rc = ERROR_DI_DO_DEFAULT;
4376 
4377  /* Call default handler */
4378  if (rc == ERROR_DI_DO_DEFAULT)
4379  {
4380  if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
4381  {
4382  if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
4383  rc = NO_ERROR;
4384  else
4385  rc = GetLastError();
4386  }
4387  else
4388  rc = NO_ERROR;
4389  }
4390 
4391  /* Call Class co-installers that required postprocessing */
4392  Context.PostProcessing = TRUE;
4393  ListEntry = ClassCoInstallersListHead.Flink;
4394  while (ListEntry != &ClassCoInstallersListHead)
4395  {
4396  struct CoInstallerElement *coinstaller;
4397  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4398  if (coinstaller->DoPostProcessing)
4399  {
4400  Context.InstallResult = rc;
4401  Context.PrivateData = coinstaller->PrivateData;
4402  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4403  }
4404  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4405  ListEntry = ListEntry->Flink;
4406  }
4407 
4408  /* Call Device co-installers that required postprocessing */
4409  ListEntry = DeviceCoInstallersListHead.Flink;
4410  while (ListEntry != &DeviceCoInstallersListHead)
4411  {
4412  struct CoInstallerElement *coinstaller;
4413  coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
4414  if (coinstaller->DoPostProcessing)
4415  {
4416  Context.InstallResult = rc;
4417  Context.PrivateData = coinstaller->PrivateData;
4418  rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
4419  }
4420  FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
4421  ListEntry = ListEntry->Flink;
4422  }
4423 
4424  /* Free allocated memory */
4425  while (!IsListEmpty(&ClassCoInstallersListHead))
4426  {
4427  ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
4428  HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4429  }
4430  while (!IsListEmpty(&DeviceCoInstallersListHead))
4431  {
4432  ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
4433  HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
4434  }
4435 
4436  ret = (rc == NO_ERROR);
4437  }
4438  }
4439 
4440  TRACE("Returning %d\n", ret);
4441  return ret;
4442 }
4443 
4444 /***********************************************************************
4445  * SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
4446  */
4451 {
4452  SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4453  BOOL ret = FALSE;
4454 
4455  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4456 
4457  if (DeviceInstallParams == NULL)
4459  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
4461  else
4462  {
4463  deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4464  ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4465 
4466  if (ret)
4467  {
4468  /* Do W->A conversion */
4469  memcpy(
4470  DeviceInstallParams,
4471  &deviceInstallParamsW,
4472  FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
4473  if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
4474  DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
4475  {
4476  DeviceInstallParams->DriverPath[0] = '\0';
4477  ret = FALSE;
4478  }
4479  }
4480  }
4481 
4482  TRACE("Returning %d\n", ret);
4483  return ret;
4484 }
4485 
4486 /***********************************************************************
4487  * SetupDiGetDeviceInfoListClass (SETUPAPI.@)
4488  */
4489 BOOL WINAPI
4492  OUT LPGUID ClassGuid)
4493 {
4494  struct DeviceInfoSet *list;
4495  BOOL ret = FALSE;
4496 
4497  TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
4498 
4499  if (!DeviceInfoSet)
4501  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4503  else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
4505  else
4506  {
4507  memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
4508 
4509  ret = TRUE;
4510  }
4511 
4512  TRACE("Returning %d\n", ret);
4513  return ret;
4514 }
4515 
4516 /***********************************************************************
4517  * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
4518  */
4519 BOOL WINAPI
4524 {
4525  struct DeviceInfoSet *list;
4526  BOOL ret = FALSE;
4527 
4528  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4529 
4530  if (!DeviceInfoSet)
4532  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4534  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4536  else if (!DeviceInstallParams)
4538  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4540  else
4541  {
4543 
4544  if (DeviceInfoData)
4545  Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4546  else
4547  Source = &list->InstallParams;
4548 
4549  ret = TRUE;
4550 
4551  _SEH2_TRY
4552  {
4553  memcpy(DeviceInstallParams, Source, Source->cbSize);
4554  }
4556  {
4558  ret = FALSE;
4559  }
4560  _SEH2_END;
4561  }
4562 
4563  TRACE("Returning %d\n", ret);
4564  return ret;
4565 }
4566 
4567 static BOOL
4570 {
4571  DWORD SupportedFlags =
4572  DI_NOVCP | /* 0x00000008 */
4573  DI_DIDCOMPAT | /* 0x00000010 */
4574  DI_DIDCLASS | /* 0x00000020 */
4575  DI_NEEDRESTART | /* 0x00000080 */
4576  DI_NEEDREBOOT | /* 0x00000100 */
4577  DI_RESOURCEPAGE_ADDED | /* 0x00002000 */
4578  DI_PROPERTIES_CHANGE | /* 0x00004000 */
4579  DI_ENUMSINGLEINF | /* 0x00010000 */
4580  DI_DONOTCALLCONFIGMG | /* 0x00020000 */
4581  DI_CLASSINSTALLPARAMS | /* 0x00100000 */
4582  DI_NODI_DEFAULTACTION | /* 0x00200000 */
4583  DI_QUIETINSTALL | /* 0x00800000 */
4584  DI_NOFILECOPY | /* 0x01000000 */
4585  DI_DRIVERPAGE_ADDED; /* 0x04000000 */
4586  DWORD SupportedFlagsEx =
4587  DI_FLAGSEX_CI_FAILED | /* 0x00000004 */
4588  DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
4589  DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
4590  DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
4591  DI_FLAGSEX_NO_DRVREG_MODIFY | /* 0x00008000 */
4592  DI_FLAGSEX_INSTALLEDDRIVER; /* 0x04000000 */
4593  BOOL ret = FALSE;
4594 
4595  /* FIXME: add support for more flags */
4596 
4597  /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
4598  * It should be checked before accessing to other values
4599  * of the SP_DEVINSTALL_PARAMS structure */
4600 
4601  if (DeviceInstallParams->Flags & ~SupportedFlags)
4602  {
4603  FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
4605  }
4606  else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
4607  {
4608  FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
4610  }
4611  else if ((DeviceInstallParams->Flags & DI_NOVCP)
4612  && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
4614  else
4615  {
4616  /* FIXME: check Reserved field */
4617  ret = TRUE;
4618  }
4619 
4620  return ret;
4621 }
4622 
4623 /***********************************************************************
4624  * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4625  */
4626 BOOL WINAPI
4631 {
4632  struct DeviceInfoSet *list;
4633  BOOL ret = FALSE;
4634 
4635  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4636 
4637  if (!DeviceInfoSet)
4639  else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4641  else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
4643  else if (!DeviceInstallParams)
4645  else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
4647  else if (CheckDeviceInstallParameters(DeviceInstallParams))
4648  {
4650 
4651  if (DeviceInfoData)
4652  Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
4653  else
4654  Destination = &list->InstallParams;
4655  memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
4656  ret = TRUE;
4657  }
4658 
4659  TRACE("Returning %d\n", ret);
4660  return ret;
4661 }
4662 
4663 /***********************************************************************
4664  * SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
4665  */
4666 BOOL WINAPI
4671 {
4672  SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
4673  int len = 0;
4674  BOOL ret = FALSE;
4675 
4676  TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
4677 
4678  if (DeviceInstallParams == NULL)
4680  else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
4682  else
4683  {
4684  memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
4685  deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
4686  len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
4687  if (!len)
4688  {
4689  ERR("DrivePath is NULL\n");
4690  ret = FALSE;
4691  }
4692  else
4693  {
4694  MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
4695  ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
4696  }
4697  }
4698 
4699  TRACE("Returning %d\n", ret);
4700  return ret;
4701 }
4702 
4703 static HKEY
4705  IN HKEY HKLM,
4706  IN DWORD HwProfile,
4707  IN DWORD samDesired)
4708 {
4709  HKEY hHWProfilesKey = NULL;
4710  HKEY hHWProfileKey = NULL;
4712  LONG rc;
4713 
4714  rc = RegOpenKeyExW(HKLM,
4716  0,
4717  READ_CONTROL,
4718  &hHWProfilesKey);
4719  if (rc != ERROR_SUCCESS)
4720  {
4721  SetLastError(rc);
4722  goto cleanup;
4723  }
4724  if (HwProfile == 0)
4725  {
4726  rc = RegOpenKeyExW(hHWProfilesKey,
4728  0,
4730  &hHWProfileKey);
4731  }
4732  else
4733  {
4734  WCHAR subKey[5];
4735  snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
4736  subKey[4] = '\0';
4737  rc = RegOpenKeyExW(hHWProfilesKey,
4738  subKey,
4739  0,
4741  &hHWProfileKey);
4742  }
4743  if (rc != ERROR_SUCCESS)
4744  {
4745  SetLastError(rc);
4746  goto cleanup;
4747  }
4748  ret = hHWProfileKey;
4749 
4750 cleanup:
4751  if (hHWProfilesKey != NULL)
4752  RegCloseKey(hHWProfilesKey);
4753  if (hHWProfileKey != NULL && hHWProfileKey != ret)
4754  RegCloseKey(hHWProfileKey);
4755  return ret;
4756 }
4757 
4758 static BOOL
4760  struct DeviceInfoSet *deviceInfoSet,
4761  struct DeviceInfo *deviceInfo)
4762 {
4764 
4765  ListEntry = deviceInfoSet->ListHead.Flink;
4766  while (ListEntry != &deviceInfoSet->ListHead)
4767  {
4768  if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
4769  return TRUE;
4770 
4771  ListEntry = ListEntry->Flink;
4772  }
4773 
4774  return FALSE;
4775 }
4776 
4777 /***********************************************************************
4778  * SetupDiDeleteDeviceInfo (SETUPAPI.@)
4779  */
4780 BOOL WINAPI
4784 {
4785  struct DeviceInfoSet *deviceInfoSet;
4786  struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
4787  BOOL ret = FALSE;
4788 
4789  TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
4790 
4791  if (!DeviceInfoSet)
4793  else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
4795  else