ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

devinst.c
Go to the documentation of this file.
00001 /*
00002  * SetupAPI device installer
00003  *
00004  * Copyright 2000 Andreas Mohr for CodeWeavers
00005  *           2005-2006 Hervé Poussineau (hpoussin@reactos.org)
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "setupapi_private.h"
00023 
00024 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
00025 
00026 /* Unicode constants */
00027 static const WCHAR BackSlash[] = {'\\',0};
00028 static const WCHAR ClassGUID[]  = {'C','l','a','s','s','G','U','I','D',0};
00029 static const WCHAR Class[]  = {'C','l','a','s','s',0};
00030 static const WCHAR DateFormat[]  = {'%','u','-','%','u','-','%','u',0};
00031 static const WCHAR DotCoInstallers[]  = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
00032 static const WCHAR DotHW[]  = {'.','H','W',0};
00033 static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
00034 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
00035 static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
00036 static const WCHAR Version[]  = {'V','e','r','s','i','o','n',0};
00037 static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
00038 
00039 static const WCHAR REGSTR_DRIVER_DATE[]  = {'D','r','i','v','e','r','D','a','t','e',0};
00040 static const WCHAR REGSTR_DRIVER_DATE_DATA[]  = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
00041 static const WCHAR REGSTR_DRIVER_VERSION[]  = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
00042 static const WCHAR REGSTR_SECURITY[]  = {'S','e','c','u','r','i','t','y',0};
00043 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};
00044 
00045 typedef DWORD
00046 (CALLBACK* CLASS_INSTALL_PROC) (
00047     IN DI_FUNCTION InstallFunction,
00048     IN HDEVINFO DeviceInfoSet,
00049     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
00050 typedef BOOL
00051 (WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
00052     IN HDEVINFO DeviceInfoSet,
00053     IN OUT PSP_DEVINFO_DATA DeviceInfoData);
00054 typedef DWORD
00055 (CALLBACK* COINSTALLER_PROC) (
00056     IN DI_FUNCTION InstallFunction,
00057     IN HDEVINFO DeviceInfoSet,
00058     IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
00059     IN OUT PCOINSTALLER_CONTEXT_DATA Context);
00060 
00061 struct CoInstallerElement
00062 {
00063     LIST_ENTRY ListEntry;
00064 
00065     HMODULE Module;
00066     COINSTALLER_PROC Function;
00067     BOOL DoPostProcessing;
00068     PVOID PrivateData;
00069 };
00070 
00071 struct GetSectionCallbackInfo
00072 {
00073     PSP_ALTPLATFORM_INFO PlatformInfo;
00074     BYTE ProductType;
00075     WORD SuiteMask;
00076     DWORD PrefixLength;
00077     WCHAR BestSection[LINE_LEN + 1];
00078     DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
00079 };
00080 
00081 
00082 
00083 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
00084 {
00085     static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
00086         '%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
00087         'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
00088         '0','2','X','}',0};
00089 
00090     sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
00091         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
00092         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
00093 }
00094 
00095 static DWORD
00096 GetErrorCodeFromCrCode(const IN CONFIGRET cr)
00097 {
00098   switch (cr)
00099   {
00100     case CR_ACCESS_DENIED:        return ERROR_ACCESS_DENIED;
00101     case CR_BUFFER_SMALL:         return ERROR_INSUFFICIENT_BUFFER;
00102     case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
00103     case CR_FAILURE:              return ERROR_GEN_FAILURE;
00104     case CR_INVALID_DATA:         return ERROR_INVALID_USER_BUFFER;
00105     case CR_INVALID_DEVICE_ID:    return ERROR_INVALID_PARAMETER;
00106     case CR_INVALID_MACHINENAME:  return ERROR_INVALID_COMPUTERNAME;
00107     case CR_INVALID_DEVNODE:      return ERROR_INVALID_PARAMETER;
00108     case CR_INVALID_FLAG:         return ERROR_INVALID_FLAGS;
00109     case CR_INVALID_POINTER:      return ERROR_INVALID_PARAMETER;
00110     case CR_INVALID_PROPERTY:     return ERROR_INVALID_PARAMETER;
00111     case CR_NO_SUCH_DEVNODE:      return ERROR_FILE_NOT_FOUND;
00112     case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
00113     case CR_NO_SUCH_VALUE:        return ERROR_FILE_NOT_FOUND;
00114     case CR_OUT_OF_MEMORY:        return ERROR_NOT_ENOUGH_MEMORY;
00115     case CR_REGISTRY_ERROR:       return ERROR_GEN_FAILURE;
00116     case CR_ALREADY_SUCH_DEVINST: return ERROR_DEVINST_ALREADY_EXISTS;
00117     case CR_SUCCESS:              return ERROR_SUCCESS;
00118     default:                      return ERROR_GEN_FAILURE;
00119   }
00120 
00121   /* Does not happen */
00122 }
00123 
00124 /* Lower scores are best ones */
00125 static BOOL
00126 CheckSectionValid(
00127     IN LPCWSTR SectionName,
00128     IN PSP_ALTPLATFORM_INFO PlatformInfo,
00129     IN BYTE ProductType,
00130     IN WORD SuiteMask,
00131     OUT PDWORD ScorePlatform,
00132     OUT PDWORD ScoreMajorVersion,
00133     OUT PDWORD ScoreMinorVersion,
00134     OUT PDWORD ScoreProductType,
00135     OUT PDWORD ScoreSuiteMask)
00136 {
00137     LPWSTR Section = NULL;
00138     //LPCWSTR pExtensionPlatform;
00139     LPCWSTR pExtensionArchitecture;
00140     LPWSTR Fields[6];
00141     DWORD i;
00142     BOOL ret = FALSE;
00143 
00144     //static const WCHAR ExtensionPlatformNone[]  = {'.',0};
00145     static const WCHAR ExtensionPlatformNT[]  = {'.','N','T',0};
00146     static const WCHAR ExtensionPlatformWindows[]  = {'.','W','i','n',0};
00147 
00148     static const WCHAR ExtensionArchitectureNone[]  = {0};
00149     static const WCHAR ExtensionArchitecturealpha[]  = {'a','l','p','h','a',0};
00150     static const WCHAR ExtensionArchitectureamd64[]  = {'A','M','D','6','4',0};
00151     static const WCHAR ExtensionArchitectureia64[]  = {'I','A','6','4',0};
00152     static const WCHAR ExtensionArchitecturemips[]  = {'m','i','p','s',0};
00153     static const WCHAR ExtensionArchitectureppc[]  = {'p','p','c',0};
00154     static const WCHAR ExtensionArchitecturex86[]  = {'x','8','6',0};
00155 
00156     TRACE("%s %p 0x%x 0x%x\n",
00157         debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
00158 
00159     *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
00160 
00161     Section = pSetupDuplicateString(SectionName);
00162     if (!Section)
00163     {
00164         TRACE("pSetupDuplicateString() failed\n");
00165         goto cleanup;
00166     }
00167 
00168     /* Set various extensions values */
00169     switch (PlatformInfo->Platform)
00170     {
00171         case VER_PLATFORM_WIN32_WINDOWS:
00172             //pExtensionPlatform = ExtensionPlatformWindows;
00173             break;
00174         case VER_PLATFORM_WIN32_NT:
00175             //pExtensionPlatform = ExtensionPlatformNT;
00176             break;
00177         default:
00178             ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
00179             //pExtensionPlatform = ExtensionPlatformNone;
00180             break;
00181     }
00182     switch (PlatformInfo->ProcessorArchitecture)
00183     {
00184         case PROCESSOR_ARCHITECTURE_ALPHA:
00185             pExtensionArchitecture = ExtensionArchitecturealpha;
00186             break;
00187         case PROCESSOR_ARCHITECTURE_AMD64:
00188             pExtensionArchitecture = ExtensionArchitectureamd64;
00189             break;
00190         case PROCESSOR_ARCHITECTURE_IA64:
00191             pExtensionArchitecture = ExtensionArchitectureia64;
00192             break;
00193         case PROCESSOR_ARCHITECTURE_INTEL:
00194             pExtensionArchitecture = ExtensionArchitecturex86;
00195             break;
00196         case PROCESSOR_ARCHITECTURE_MIPS:
00197             pExtensionArchitecture = ExtensionArchitecturemips;
00198             break;
00199         case PROCESSOR_ARCHITECTURE_PPC:
00200             pExtensionArchitecture = ExtensionArchitectureppc;
00201             break;
00202         default:
00203             ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
00204         case PROCESSOR_ARCHITECTURE_UNKNOWN:
00205             pExtensionArchitecture = ExtensionArchitectureNone;
00206             break;
00207     }
00208 
00209     /*
00210      * Field[0] Platform
00211      * Field[1] Architecture
00212      * Field[2] Major version
00213      * Field[3] Minor version
00214      * Field[4] Product type
00215      * Field[5] Suite mask
00216      * Remark: lastests fields may be NULL if the information is not provided
00217      */
00218     Fields[0] = Section;
00219     if (Fields[0] == NULL)
00220     {
00221         TRACE("No extension found\n");
00222         *ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
00223         ret = TRUE;
00224         goto cleanup;
00225     }
00226     Fields[1] = Fields[0] + 1;
00227     Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
00228     for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
00229     {
00230         Fields[i] = wcschr(Fields[i - 1], '.');
00231         if (Fields[i])
00232         {
00233             Fields[i]++;
00234             *(Fields[i] - 1) = UNICODE_NULL;
00235         }
00236     }
00237     /* Take care of first 2 fields */
00238     if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
00239     {
00240         if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
00241         {
00242             TRACE("Mismatch on platform field\n");
00243             goto cleanup;
00244         }
00245         Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
00246     }
00247     else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
00248     {
00249         if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
00250         {
00251             TRACE("Mismatch on platform field\n");
00252             goto cleanup;
00253         }
00254         Fields[1] += wcslen(ExtensionPlatformNT) - 1;
00255     }
00256     else
00257     {
00258         /* No platform specified */
00259         *ScorePlatform |= 0x02;
00260     }
00261     if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
00262     {
00263         /* No architecture specified */
00264         *ScorePlatform |= 0x01;
00265     }
00266     else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
00267     {
00268         TRACE("Mismatch on architecture field ('%s' and '%s')\n",
00269             debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
00270         goto cleanup;
00271     }
00272 
00273     /* Check if informations are matching */
00274     if (Fields[2] && *Fields[2])
00275     {
00276         DWORD MajorVersion, MinorVersion = 0;
00277         MajorVersion = strtoulW(Fields[2], NULL, 0);
00278         if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
00279             (errno == ERANGE || errno == EINVAL))
00280         {
00281             TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
00282             goto cleanup;
00283         }
00284         if (Fields[3] && *Fields[3])
00285         {
00286             MinorVersion = strtoulW(Fields[3], NULL, 0);
00287             if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
00288                 (errno == ERANGE || errno == EINVAL))
00289             {
00290                 TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
00291                 goto cleanup;
00292             }
00293         }
00294         if (PlatformInfo->MajorVersion < MajorVersion ||
00295             (PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
00296         {
00297             TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
00298                 MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
00299             goto cleanup;
00300         }
00301         *ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
00302         if (MajorVersion == PlatformInfo->MajorVersion)
00303             *ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
00304         else
00305             *ScoreMinorVersion = MinorVersion;
00306     }
00307     else if (Fields[3] && *Fields[3])
00308     {
00309         TRACE("Minor version found without major version\n");
00310         goto cleanup;
00311     }
00312     else
00313     {
00314         *ScoreMajorVersion = PlatformInfo->MajorVersion;
00315         *ScoreMinorVersion = PlatformInfo->MinorVersion;
00316     }
00317 
00318     if (Fields[4] && *Fields[4])
00319     {
00320         DWORD CurrentProductType;
00321         CurrentProductType = strtoulW(Fields[4], NULL, 0);
00322         if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
00323             (errno == ERANGE || errno == EINVAL))
00324         {
00325             TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
00326             goto cleanup;
00327         }
00328         if (CurrentProductType != ProductType)
00329         {
00330             TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
00331                 CurrentProductType, ProductType);
00332             goto cleanup;
00333         }
00334     }
00335     else
00336         *ScoreProductType = 1;
00337 
00338     if (Fields[5] && *Fields[5])
00339     {
00340         DWORD CurrentSuiteMask;
00341         CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
00342         if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
00343             (errno == ERANGE || errno == EINVAL))
00344         {
00345             TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
00346             goto cleanup;
00347         }
00348         if ((CurrentSuiteMask & ~SuiteMask) != 0)
00349         {
00350             TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
00351                 CurrentSuiteMask, SuiteMask);
00352             goto cleanup;
00353         }
00354         *ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
00355     }
00356     else
00357         *ScoreSuiteMask = SuiteMask;
00358 
00359     ret = TRUE;
00360 
00361 cleanup:
00362     MyFree(Section);
00363     return ret;
00364 }
00365 
00366 static BOOL
00367 GetSectionCallback(
00368     IN LPCWSTR SectionName,
00369     IN PVOID Context)
00370 {
00371     struct GetSectionCallbackInfo *info = Context;
00372     DWORD Score1, Score2, Score3, Score4, Score5;
00373     BOOL ret;
00374 
00375     if (SectionName[info->PrefixLength] != '.')
00376         return TRUE;
00377 
00378     ret = CheckSectionValid(
00379         &SectionName[info->PrefixLength],
00380         info->PlatformInfo,
00381         info->ProductType,
00382         info->SuiteMask,
00383         &Score1, &Score2, &Score3, &Score4, &Score5);
00384     if (!ret)
00385     {
00386         TRACE("Section %s not compatible\n", debugstr_w(SectionName));
00387         return TRUE;
00388     }
00389     if (Score1 > info->BestScore1) goto done;
00390     if (Score1 < info->BestScore1) goto bettersection;
00391     if (Score2 > info->BestScore2) goto done;
00392     if (Score2 < info->BestScore2) goto bettersection;
00393     if (Score3 > info->BestScore3) goto done;
00394     if (Score3 < info->BestScore3) goto bettersection;
00395     if (Score4 > info->BestScore4) goto done;
00396     if (Score4 < info->BestScore4) goto bettersection;
00397     if (Score5 > info->BestScore5) goto done;
00398     if (Score5 < info->BestScore5) goto bettersection;
00399     goto done;
00400 
00401 bettersection:
00402     strcpyW(info->BestSection, SectionName);
00403     info->BestScore1 = Score1;
00404     info->BestScore2 = Score2;
00405     info->BestScore3 = Score3;
00406     info->BestScore4 = Score4;
00407     info->BestScore5 = Score5;
00408 
00409 done:
00410     return TRUE;
00411 }
00412 
00413 /***********************************************************************
00414  *      SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
00415  */
00416 BOOL WINAPI
00417 SetupDiGetActualSectionToInstallExW(
00418     IN HINF InfHandle,
00419     IN PCWSTR InfSectionName,
00420     IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
00421     OUT PWSTR InfSectionWithExt OPTIONAL,
00422     IN DWORD InfSectionWithExtSize,
00423     OUT PDWORD RequiredSize OPTIONAL,
00424     OUT PWSTR* Extension OPTIONAL,
00425     IN PVOID Reserved)
00426 {
00427     BOOL ret = FALSE;
00428 
00429     TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
00430         AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
00431         RequiredSize, Extension, Reserved);
00432 
00433     if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
00434         SetLastError(ERROR_INVALID_HANDLE);
00435     else if (!InfSectionName)
00436         SetLastError(ERROR_INVALID_PARAMETER);
00437     else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
00438         SetLastError(ERROR_INVALID_USER_BUFFER);
00439     else if (Reserved != NULL)
00440         SetLastError(ERROR_INVALID_PARAMETER);
00441     else
00442     {
00443         static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
00444         static BYTE CurrentProductType = 0;
00445         static WORD CurrentSuiteMask = 0;
00446         PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
00447         struct GetSectionCallbackInfo CallbackInfo;
00448         DWORD dwFullLength;
00449         BYTE ProductType;
00450         WORD SuiteMask;
00451 
00452         /* Fill platform info if needed */
00453         if (AlternatePlatformInfo)
00454         {
00455             pPlatformInfo = AlternatePlatformInfo;
00456             ProductType = 0;
00457             SuiteMask = 0;
00458         }
00459         else
00460         {
00461             if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
00462             {
00463                 /* That's the first time we go here. We need to fill in the structure */
00464                 OSVERSIONINFOEX VersionInfo;
00465                 SYSTEM_INFO SystemInfo;
00466                 VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00467                 ret = GetVersionExW((OSVERSIONINFO*)&VersionInfo);
00468                 if (!ret)
00469                     goto done;
00470                 GetSystemInfo(&SystemInfo);
00471                 CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
00472                 CurrentPlatform.Platform = VersionInfo.dwPlatformId;
00473                 CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
00474                 CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
00475                 CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
00476                 CurrentPlatform.Reserved = 0;
00477                 CurrentProductType = VersionInfo.wProductType;
00478                 CurrentSuiteMask = VersionInfo.wSuiteMask;
00479             }
00480             ProductType = CurrentProductType;
00481             SuiteMask = CurrentSuiteMask;
00482         }
00483 
00484         CallbackInfo.PlatformInfo = pPlatformInfo;
00485         CallbackInfo.ProductType = ProductType;
00486         CallbackInfo.SuiteMask = SuiteMask;
00487         CallbackInfo.PrefixLength = strlenW(InfSectionName);
00488         CallbackInfo.BestScore1 = ULONG_MAX;
00489         CallbackInfo.BestScore2 = ULONG_MAX;
00490         CallbackInfo.BestScore3 = ULONG_MAX;
00491         CallbackInfo.BestScore4 = ULONG_MAX;
00492         CallbackInfo.BestScore5 = ULONG_MAX;
00493         strcpyW(CallbackInfo.BestSection, InfSectionName);
00494         if (!EnumerateSectionsStartingWith(
00495             InfHandle,
00496             InfSectionName,
00497             GetSectionCallback,
00498             &CallbackInfo))
00499         {
00500             SetLastError(ERROR_GEN_FAILURE);
00501             goto done;
00502         }
00503 
00504         dwFullLength = lstrlenW(CallbackInfo.BestSection);
00505         if (RequiredSize != NULL)
00506             *RequiredSize = dwFullLength + 1;
00507 
00508         if (InfSectionWithExtSize > 0)
00509         {
00510             if (InfSectionWithExtSize < dwFullLength + 1)
00511             {
00512                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
00513                 goto done;
00514             }
00515             strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
00516             if (Extension)
00517             {
00518                 DWORD dwLength = lstrlenW(InfSectionName);
00519                 *Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
00520             }
00521         }
00522 
00523         ret = TRUE;
00524     }
00525 
00526 done:
00527     TRACE("Returning %d\n", ret);
00528     return ret;
00529 }
00530 
00531 
00532 BOOL
00533 CreateDeviceInfo(
00534     IN struct DeviceInfoSet *list,
00535     IN LPCWSTR InstancePath,
00536     IN LPCGUID pClassGuid,
00537     OUT struct DeviceInfo **pDeviceInfo)
00538 {
00539     DWORD size;
00540     CONFIGRET cr;
00541     struct DeviceInfo *deviceInfo;
00542 
00543     *pDeviceInfo = NULL;
00544 
00545     size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
00546     deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
00547     if (!deviceInfo)
00548     {
00549         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00550         return FALSE;
00551     }
00552     ZeroMemory(deviceInfo, size);
00553 
00554     cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
00555     if (cr != CR_SUCCESS)
00556     {
00557         SetLastError(GetErrorCodeFromCrCode(cr));
00558         return FALSE;
00559     }
00560 
00561     deviceInfo->set = list;
00562     deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
00563     strcpyW(deviceInfo->Data, InstancePath);
00564     deviceInfo->instanceId = deviceInfo->Data;
00565     deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
00566     deviceInfo->DeviceDescription = NULL;
00567     memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
00568     deviceInfo->CreationFlags = 0;
00569     InitializeListHead(&deviceInfo->DriverListHead);
00570     InitializeListHead(&deviceInfo->InterfaceListHead);
00571 
00572     *pDeviceInfo = deviceInfo;
00573     return TRUE;
00574 }
00575 
00576 
00577 static BOOL
00578 DestroyClassInstallParams(struct ClassInstallParams* installParams)
00579 {
00580     HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
00581     HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
00582     return TRUE;
00583 }
00584 
00585 static BOOL
00586 DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
00587 {
00588     PLIST_ENTRY ListEntry;
00589     struct DriverInfoElement *driverInfo;
00590     struct DeviceInterface *deviceInterface;
00591 
00592     while (!IsListEmpty(&deviceInfo->DriverListHead))
00593     {
00594         ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
00595         driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
00596         if (!DestroyDriverInfoElement(driverInfo))
00597             return FALSE;
00598     }
00599     while (!IsListEmpty(&deviceInfo->InterfaceListHead))
00600     {
00601         ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
00602         deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
00603         if (!DestroyDeviceInterface(deviceInterface))
00604             return FALSE;
00605     }
00606     DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
00607     return HeapFree(GetProcessHeap(), 0, deviceInfo);
00608 }
00609 
00610 static BOOL
00611 DestroyDeviceInfoSet(struct DeviceInfoSet* list)
00612 {
00613     PLIST_ENTRY ListEntry;
00614     struct DeviceInfo *deviceInfo;
00615 
00616     while (!IsListEmpty(&list->ListHead))
00617     {
00618         ListEntry = RemoveHeadList(&list->ListHead);
00619         deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
00620         if (!DestroyDeviceInfo(deviceInfo))
00621             return FALSE;
00622     }
00623     if (list->HKLM != HKEY_LOCAL_MACHINE)
00624         RegCloseKey(list->HKLM);
00625     CM_Disconnect_Machine(list->hMachine);
00626     DestroyClassInstallParams(&list->ClassInstallParams);
00627     return HeapFree(GetProcessHeap(), 0, list);
00628 }
00629 
00630 /***********************************************************************
00631  *              SetupDiBuildClassInfoList  (SETUPAPI.@)
00632  *
00633  * Returns a list of setup class GUIDs that identify the classes
00634  * that are installed on a local machine.
00635  *
00636  * PARAMS
00637  *   Flags [I] control exclusion of classes from the list.
00638  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
00639  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
00640  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
00641  *
00642  * RETURNS
00643  *   Success: TRUE.
00644  *   Failure: FALSE.
00645  */
00646 BOOL WINAPI SetupDiBuildClassInfoList(
00647         DWORD Flags,
00648         LPGUID ClassGuidList,
00649         DWORD ClassGuidListSize,
00650         PDWORD RequiredSize)
00651 {
00652     TRACE("\n");
00653     return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
00654                                         ClassGuidListSize, RequiredSize,
00655                                         NULL, NULL);
00656 }
00657 
00658 /***********************************************************************
00659  *              SetupDiBuildClassInfoListExA  (SETUPAPI.@)
00660  *
00661  * Returns a list of setup class GUIDs that identify the classes
00662  * that are installed on a local or remote macine.
00663  *
00664  * PARAMS
00665  *   Flags [I] control exclusion of classes from the list.
00666  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
00667  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
00668  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
00669  *   MachineName [I] name of a remote machine.
00670  *   Reserved [I] must be NULL.
00671  *
00672  * RETURNS
00673  *   Success: TRUE.
00674  *   Failure: FALSE.
00675  */
00676 BOOL WINAPI SetupDiBuildClassInfoListExA(
00677         DWORD Flags,
00678         LPGUID ClassGuidList,
00679         DWORD ClassGuidListSize,
00680         PDWORD RequiredSize,
00681         LPCSTR MachineName,
00682         PVOID Reserved)
00683 {
00684     LPWSTR MachineNameW = NULL;
00685     BOOL bResult;
00686 
00687     TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
00688         ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
00689 
00690     if (MachineName)
00691     {
00692         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
00693         if (MachineNameW == NULL) return FALSE;
00694     }
00695 
00696     bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
00697                                            ClassGuidListSize, RequiredSize,
00698                                            MachineNameW, Reserved);
00699 
00700     MyFree(MachineNameW);
00701 
00702     return bResult;
00703 }
00704 
00705 /***********************************************************************
00706  *              SetupDiBuildClassInfoListExW  (SETUPAPI.@)
00707  *
00708  * Returns a list of setup class GUIDs that identify the classes
00709  * that are installed on a local or remote macine.
00710  *
00711  * PARAMS
00712  *   Flags [I] control exclusion of classes from the list.
00713  *   ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
00714  *   ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
00715  *   RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
00716  *   MachineName [I] name of a remote machine.
00717  *   Reserved [I] must be NULL.
00718  *
00719  * RETURNS
00720  *   Success: TRUE.
00721  *   Failure: FALSE.
00722  */
00723 BOOL WINAPI SetupDiBuildClassInfoListExW(
00724         DWORD Flags,
00725         LPGUID ClassGuidList,
00726         DWORD ClassGuidListSize,
00727         PDWORD RequiredSize,
00728         LPCWSTR MachineName,
00729         PVOID Reserved)
00730 {
00731     WCHAR szKeyName[40];
00732     HKEY hClassesKey = INVALID_HANDLE_VALUE;
00733     HKEY hClassKey;
00734     DWORD dwLength;
00735     DWORD dwIndex;
00736     LONG lError;
00737     DWORD dwGuidListIndex = 0;
00738 
00739     TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
00740         ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
00741 
00742     if (!RequiredSize)
00743     {
00744         SetLastError(ERROR_INVALID_PARAMETER);
00745         return FALSE;
00746     }
00747     else if (!ClassGuidList && ClassGuidListSize > 0)
00748     {
00749         SetLastError(ERROR_INVALID_PARAMETER);
00750         return FALSE;
00751     }
00752 
00753     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
00754                                             KEY_ENUMERATE_SUB_KEYS,
00755                                             DIOCR_INSTALLER,
00756                                             MachineName,
00757                                             Reserved);
00758     if (hClassesKey == INVALID_HANDLE_VALUE)
00759     {
00760         return FALSE;
00761     }
00762 
00763     for (dwIndex = 0; ; dwIndex++)
00764     {
00765         dwLength = 40;
00766         lError = RegEnumKeyExW(hClassesKey,
00767                                dwIndex,
00768                                szKeyName,
00769                                &dwLength,
00770                                NULL,
00771                                NULL,
00772                                NULL,
00773                                NULL);
00774         TRACE("RegEnumKeyExW() returns %d\n", lError);
00775         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
00776         {
00777             TRACE("Key name: %s\n", debugstr_w(szKeyName));
00778 
00779             if (RegOpenKeyExW(hClassesKey,
00780                               szKeyName,
00781                               0,
00782                               KEY_QUERY_VALUE,
00783                               &hClassKey))
00784             {
00785                 RegCloseKey(hClassesKey);
00786                 return FALSE;
00787             }
00788 
00789             if (!RegQueryValueExW(hClassKey,
00790                                   REGSTR_VAL_NOUSECLASS,
00791                                   NULL,
00792                                   NULL,
00793                                   NULL,
00794                                   NULL))
00795             {
00796                 TRACE("'NoUseClass' value found!\n");
00797                 RegCloseKey(hClassKey);
00798                 continue;
00799             }
00800 
00801             if ((Flags & DIBCI_NOINSTALLCLASS) &&
00802                 (!RegQueryValueExW(hClassKey,
00803                                    REGSTR_VAL_NOINSTALLCLASS,
00804                                    NULL,
00805                                    NULL,
00806                                    NULL,
00807                                    NULL)))
00808             {
00809                 TRACE("'NoInstallClass' value found!\n");
00810                 RegCloseKey(hClassKey);
00811                 continue;
00812             }
00813 
00814             if ((Flags & DIBCI_NODISPLAYCLASS) &&
00815                 (!RegQueryValueExW(hClassKey,
00816                                    REGSTR_VAL_NODISPLAYCLASS,
00817                                    NULL,
00818                                    NULL,
00819                                    NULL,
00820                                    NULL)))
00821             {
00822                 TRACE("'NoDisplayClass' value found!\n");
00823                 RegCloseKey(hClassKey);
00824                 continue;
00825             }
00826 
00827             RegCloseKey(hClassKey);
00828 
00829             TRACE("Guid: %s\n", debugstr_w(szKeyName));
00830             if (dwGuidListIndex < ClassGuidListSize)
00831             {
00832                 if (szKeyName[0] == '{' && szKeyName[37] == '}')
00833                 {
00834                     szKeyName[37] = 0;
00835                 }
00836                 TRACE("Guid: %p\n", &szKeyName[1]);
00837 
00838                 UuidFromStringW(&szKeyName[1],
00839                                 &ClassGuidList[dwGuidListIndex]);
00840             }
00841 
00842             dwGuidListIndex++;
00843         }
00844 
00845         if (lError != ERROR_SUCCESS)
00846             break;
00847     }
00848 
00849     RegCloseKey(hClassesKey);
00850 
00851     if (RequiredSize != NULL)
00852         *RequiredSize = dwGuidListIndex;
00853 
00854     if (ClassGuidListSize < dwGuidListIndex)
00855     {
00856         SetLastError(ERROR_INSUFFICIENT_BUFFER);
00857         return FALSE;
00858     }
00859 
00860     return TRUE;
00861 }
00862 
00863 /***********************************************************************
00864  *      SetupDiClassGuidsFromNameA  (SETUPAPI.@)
00865  */
00866 BOOL WINAPI SetupDiClassGuidsFromNameA(
00867         LPCSTR ClassName,
00868         LPGUID ClassGuidList,
00869         DWORD ClassGuidListSize,
00870         PDWORD RequiredSize)
00871 {
00872     return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
00873                                         ClassGuidListSize, RequiredSize,
00874                                         NULL, NULL);
00875 }
00876 
00877 /***********************************************************************
00878  *      SetupDiClassGuidsFromNameW  (SETUPAPI.@)
00879  */
00880 BOOL WINAPI SetupDiClassGuidsFromNameW(
00881         LPCWSTR ClassName,
00882         LPGUID ClassGuidList,
00883         DWORD ClassGuidListSize,
00884         PDWORD RequiredSize)
00885 {
00886     return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
00887                                         ClassGuidListSize, RequiredSize,
00888                                         NULL, NULL);
00889 }
00890 
00891 /***********************************************************************
00892  *      SetupDiClassGuidsFromNameExA  (SETUPAPI.@)
00893  */
00894 BOOL WINAPI SetupDiClassGuidsFromNameExA(
00895         LPCSTR ClassName,
00896         LPGUID ClassGuidList,
00897         DWORD ClassGuidListSize,
00898         PDWORD RequiredSize,
00899         LPCSTR MachineName,
00900         PVOID Reserved)
00901 {
00902     LPWSTR ClassNameW = NULL;
00903     LPWSTR MachineNameW = NULL;
00904     BOOL bResult;
00905 
00906     TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName), ClassGuidList,
00907         ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
00908 
00909     if (!ClassName)
00910     {
00911         SetLastError(ERROR_INVALID_PARAMETER);
00912         return FALSE;
00913     }
00914 
00915     ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
00916     if (ClassNameW == NULL)
00917         return FALSE;
00918 
00919     if (MachineName)
00920     {
00921         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
00922         if (MachineNameW == NULL)
00923         {
00924             MyFree(ClassNameW);
00925             return FALSE;
00926         }
00927     }
00928 
00929     bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
00930                                            ClassGuidListSize, RequiredSize,
00931                                            MachineNameW, Reserved);
00932 
00933     MyFree(MachineNameW);
00934     MyFree(ClassNameW);
00935 
00936     return bResult;
00937 }
00938 
00939 /***********************************************************************
00940  *      SetupDiClassGuidsFromNameExW  (SETUPAPI.@)
00941  */
00942 BOOL WINAPI SetupDiClassGuidsFromNameExW(
00943         LPCWSTR ClassName,
00944         LPGUID ClassGuidList,
00945         DWORD ClassGuidListSize,
00946         PDWORD RequiredSize,
00947         LPCWSTR MachineName,
00948         PVOID Reserved)
00949 {
00950     WCHAR szKeyName[40];
00951     WCHAR szClassName[MAX_CLASS_NAME_LEN];
00952     HKEY hClassesKey;
00953     HKEY hClassKey;
00954     DWORD dwLength;
00955     DWORD dwIndex;
00956     LONG lError;
00957     DWORD dwGuidListIndex = 0;
00958 
00959     TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
00960         ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
00961 
00962     if (!ClassName || !RequiredSize)
00963     {
00964         SetLastError(ERROR_INVALID_PARAMETER);
00965         return FALSE;
00966     }
00967     if (!ClassGuidList && ClassGuidListSize > 0)
00968     {
00969         SetLastError(ERROR_INVALID_PARAMETER);
00970         return FALSE;
00971     }
00972     *RequiredSize = 0;
00973 
00974     hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
00975                                             KEY_ENUMERATE_SUB_KEYS,
00976                                             DIOCR_INSTALLER,
00977                                             MachineName,
00978                                             Reserved);
00979     if (hClassesKey == INVALID_HANDLE_VALUE)
00980     {
00981         return FALSE;
00982     }
00983 
00984     for (dwIndex = 0; ; dwIndex++)
00985     {
00986         dwLength = 40;
00987         lError = RegEnumKeyExW(hClassesKey,
00988                                dwIndex,
00989                                szKeyName,
00990                                &dwLength,
00991                                NULL,
00992                                NULL,
00993                                NULL,
00994                                NULL);
00995         TRACE("RegEnumKeyExW() returns %d\n", lError);
00996         if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
00997         {
00998             TRACE("Key name: %p\n", szKeyName);
00999 
01000             if (RegOpenKeyExW(hClassesKey,
01001                               szKeyName,
01002                               0,
01003                               KEY_QUERY_VALUE,
01004                               &hClassKey))
01005             {
01006                 RegCloseKey(hClassesKey);
01007                 return FALSE;
01008             }
01009 
01010             dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
01011             if (!RegQueryValueExW(hClassKey,
01012                                   Class,
01013                                   NULL,
01014                                   NULL,
01015                                   (LPBYTE)szClassName,
01016                                   &dwLength))
01017             {
01018                 TRACE("Class name: %p\n", szClassName);
01019 
01020                 if (strcmpiW(szClassName, ClassName) == 0)
01021                 {
01022                     TRACE("Found matching class name\n");
01023 
01024                     TRACE("Guid: %p\n", szKeyName);
01025                     if (dwGuidListIndex < ClassGuidListSize)
01026                     {
01027                         if (szKeyName[0] == '{' && szKeyName[37] == '}')
01028                         {
01029                             szKeyName[37] = 0;
01030                         }
01031                         TRACE("Guid: %p\n", &szKeyName[1]);
01032 
01033                         UuidFromStringW(&szKeyName[1],
01034                                         &ClassGuidList[dwGuidListIndex]);
01035                     }
01036 
01037                     dwGuidListIndex++;
01038                 }
01039             }
01040 
01041             RegCloseKey(hClassKey);
01042         }
01043 
01044         if (lError != ERROR_SUCCESS)
01045             break;
01046     }
01047 
01048     RegCloseKey(hClassesKey);
01049 
01050     if (RequiredSize != NULL)
01051         *RequiredSize = dwGuidListIndex;
01052 
01053     if (ClassGuidListSize < dwGuidListIndex)
01054     {
01055         SetLastError(ERROR_INSUFFICIENT_BUFFER);
01056         return FALSE;
01057     }
01058 
01059     return TRUE;
01060 }
01061 
01062 /***********************************************************************
01063  *              SetupDiClassNameFromGuidA  (SETUPAPI.@)
01064  */
01065 BOOL WINAPI SetupDiClassNameFromGuidA(
01066         const GUID* ClassGuid,
01067         PSTR ClassName,
01068         DWORD ClassNameSize,
01069         PDWORD RequiredSize)
01070 {
01071     return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
01072                                        ClassNameSize, RequiredSize,
01073                                        NULL, NULL);
01074 }
01075 
01076 /***********************************************************************
01077  *              SetupDiClassNameFromGuidW  (SETUPAPI.@)
01078  */
01079 BOOL WINAPI SetupDiClassNameFromGuidW(
01080         const GUID* ClassGuid,
01081         PWSTR ClassName,
01082         DWORD ClassNameSize,
01083         PDWORD RequiredSize)
01084 {
01085     return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
01086                                        ClassNameSize, RequiredSize,
01087                                        NULL, NULL);
01088 }
01089 
01090 /***********************************************************************
01091  *              SetupDiClassNameFromGuidExA  (SETUPAPI.@)
01092  */
01093 BOOL WINAPI SetupDiClassNameFromGuidExA(
01094         const GUID* ClassGuid,
01095         PSTR ClassName,
01096         DWORD ClassNameSize,
01097         PDWORD RequiredSize,
01098         PCSTR MachineName,
01099         PVOID Reserved)
01100 {
01101     WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
01102     LPWSTR MachineNameW = NULL;
01103     BOOL ret;
01104 
01105     if (MachineName)
01106         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
01107     ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
01108                                       RequiredSize, MachineNameW, Reserved);
01109     if (ret)
01110     {
01111         int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
01112                                       ClassNameSize, NULL, NULL);
01113         if (len == 0 || len > ClassNameSize)
01114         {
01115             SetLastError(ERROR_INSUFFICIENT_BUFFER);
01116             ret = FALSE;
01117         }
01118     }
01119     MyFree(MachineNameW);
01120     return ret;
01121 }
01122 
01123 /***********************************************************************
01124  *      SetupDiClassNameFromGuidExW  (SETUPAPI.@)
01125  */
01126 BOOL WINAPI SetupDiClassNameFromGuidExW(
01127         const GUID* ClassGuid,
01128         PWSTR ClassName,
01129         DWORD ClassNameSize,
01130         PDWORD RequiredSize,
01131         PCWSTR MachineName,
01132         PVOID Reserved)
01133 {
01134     HKEY hKey;
01135     DWORD dwLength;
01136     DWORD dwRegType;
01137     LONG rc;
01138     PWSTR Buffer;
01139 
01140     TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
01141         ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
01142 
01143     /* Make sure there's a GUID */
01144     if (ClassGuid == NULL)
01145     {
01146         SetLastError(ERROR_INVALID_CLASS);  /* On Vista: ERROR_INVALID_USER_BUFFER */
01147         return FALSE;
01148     }
01149 
01150     /* Make sure there's a real buffer when there's a size */
01151     if ((ClassNameSize > 0) && (ClassName == NULL))
01152     {
01153         SetLastError(ERROR_INVALID_PARAMETER);  /* On Vista: ERROR_INVALID_USER_BUFFER */
01154         return FALSE;
01155     }
01156 
01157     /* Open the key for the GUID */
01158     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved);
01159 
01160     if (hKey == INVALID_HANDLE_VALUE)
01161         return FALSE;
01162 
01163     /* Retrieve the class name data and close the key */
01164     rc = QueryRegistryValue(hKey, Class, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
01165     RegCloseKey(hKey);
01166 
01167     /* Make sure we got the data */
01168     if (rc != ERROR_SUCCESS)
01169     {
01170         SetLastError(rc);
01171         return FALSE;
01172     }
01173 
01174     /* Make sure the data is a string */
01175     if (dwRegType != REG_SZ)
01176     {
01177         MyFree(Buffer);
01178         SetLastError(ERROR_GEN_FAILURE);
01179         return FALSE;
01180     }
01181 
01182     /* Determine the length of the class name */
01183     dwLength /= sizeof(WCHAR);
01184 
01185     if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
01186         /* Count the null-terminator */
01187         dwLength++;
01188 
01189     /* Inform the caller about the class name */
01190     if ((ClassName != NULL) && (dwLength <= ClassNameSize))
01191     {
01192         memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
01193         ClassName[dwLength - 1] = UNICODE_NULL;
01194     }
01195 
01196     /* Inform the caller about the required size */
01197     if (RequiredSize != NULL)
01198         *RequiredSize = dwLength;
01199 
01200     /* Clean up the buffer */
01201     MyFree(Buffer);
01202 
01203     /* Make sure the buffer was large enough */
01204     if ((ClassName == NULL) || (dwLength > ClassNameSize))
01205     {
01206         SetLastError(ERROR_INSUFFICIENT_BUFFER);
01207         return FALSE;
01208     }
01209 
01210     return TRUE;
01211 }
01212 
01213 /***********************************************************************
01214  *      SetupDiCreateDeviceInfoList (SETUPAPI.@)
01215  */
01216 HDEVINFO WINAPI
01217 SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
01218         HWND hwndParent)
01219 {
01220     return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
01221 }
01222 
01223 /***********************************************************************
01224  *      SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
01225  */
01226 HDEVINFO WINAPI
01227 SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
01228         HWND hwndParent,
01229         PCSTR MachineName,
01230         PVOID Reserved)
01231 {
01232     LPWSTR MachineNameW = NULL;
01233     HDEVINFO hDevInfo;
01234 
01235     TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
01236       debugstr_a(MachineName), Reserved);
01237 
01238     if (MachineName)
01239     {
01240         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
01241         if (MachineNameW == NULL)
01242             return INVALID_HANDLE_VALUE;
01243     }
01244 
01245     hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
01246                                               MachineNameW, Reserved);
01247 
01248     MyFree(MachineNameW);
01249 
01250     return hDevInfo;
01251 }
01252 
01253 /***********************************************************************
01254  *      SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
01255  *
01256  * Create an empty DeviceInfoSet list.
01257  *
01258  * PARAMS
01259  *   ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
01260  *                 with this list.
01261  *   hwndParent [I] hwnd needed for interface related actions.
01262  *   MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
01263  *                   local registry will be used.
01264  *   Reserved [I] must be NULL
01265  *
01266  * RETURNS
01267  *   Success: empty list.
01268  *   Failure: INVALID_HANDLE_VALUE.
01269  */
01270 HDEVINFO WINAPI
01271 SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
01272         HWND hwndParent,
01273         PCWSTR MachineName,
01274         PVOID Reserved)
01275 {
01276     struct DeviceInfoSet *list = NULL;
01277     DWORD size = FIELD_OFFSET(struct DeviceInfoSet, szData);
01278     DWORD rc;
01279     CONFIGRET cr;
01280     HDEVINFO ret = INVALID_HANDLE_VALUE;
01281 
01282     TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
01283       debugstr_w(MachineName), Reserved);
01284 
01285     if (MachineName != NULL)
01286     {
01287         SIZE_T len = strlenW(MachineName);
01288         if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
01289         {
01290             SetLastError(ERROR_INVALID_MACHINENAME);
01291             goto cleanup;
01292         }
01293         if(len > 0)
01294             size += (len + 3) * sizeof(WCHAR);
01295         else
01296             MachineName = NULL;
01297     }
01298 
01299     if (Reserved != NULL)
01300     {
01301         SetLastError(ERROR_INVALID_PARAMETER);
01302         return INVALID_HANDLE_VALUE;
01303     }
01304 
01305     list = MyMalloc(size);
01306     if (!list)
01307     {
01308         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01309         return INVALID_HANDLE_VALUE;
01310     }
01311     ZeroMemory(list, FIELD_OFFSET(struct DeviceInfoSet, szData));
01312 
01313     list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
01314     memcpy(&list->ClassGuid,
01315             ClassGuid ? ClassGuid : &GUID_NULL,
01316             sizeof(list->ClassGuid));
01317     list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
01318     list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
01319     list->InstallParams.hwndParent = hwndParent;
01320     if (MachineName)
01321     {
01322         rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
01323         if (rc != ERROR_SUCCESS)
01324         {
01325             SetLastError(ERROR_INVALID_MACHINENAME);
01326             goto cleanup;
01327         }
01328 
01329         list->szData[0] = list->szData[1] = '\\';
01330         strcpyW(list->szData + 2, MachineName);
01331         list->MachineName = list->szData;
01332     }
01333     else
01334     {
01335         list->HKLM = HKEY_LOCAL_MACHINE;
01336         list->MachineName = NULL;
01337     }
01338     cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
01339     if (cr != CR_SUCCESS)
01340     {
01341         SetLastError(GetErrorCodeFromCrCode(cr));
01342         goto cleanup;
01343     }
01344     InitializeListHead(&list->DriverListHead);
01345     InitializeListHead(&list->ListHead);
01346 
01347     return (HDEVINFO)list;
01348 
01349 cleanup:
01350     if (ret == INVALID_HANDLE_VALUE)
01351     {
01352         if (list)
01353         {
01354             if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
01355                 RegCloseKey(list->HKLM);
01356             MyFree(list);
01357         }
01358     }
01359     return ret;
01360 }
01361 
01362 /***********************************************************************
01363  *              SetupDiCreateDevRegKeyA (SETUPAPI.@)
01364  */
01365 HKEY WINAPI SetupDiCreateDevRegKeyA(
01366         HDEVINFO DeviceInfoSet,
01367         PSP_DEVINFO_DATA DeviceInfoData,
01368         DWORD Scope,
01369         DWORD HwProfile,
01370         DWORD KeyType,
01371         HINF InfHandle,
01372         PCSTR InfSectionName)
01373 {
01374     PWSTR InfSectionNameW = NULL;
01375     HKEY key;
01376 
01377     TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
01378             HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
01379 
01380     if (InfHandle)
01381     {
01382         if (!InfSectionName)
01383         {
01384             SetLastError(ERROR_INVALID_PARAMETER);
01385             return INVALID_HANDLE_VALUE;
01386         }
01387         else
01388         {
01389             InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
01390             if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
01391         }
01392     }
01393     key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
01394             HwProfile, KeyType, InfHandle, InfSectionNameW);
01395     MyFree(InfSectionNameW);
01396     return key;
01397 }
01398 
01399 static HKEY
01400 OpenHardwareProfileKey(
01401     IN HKEY HKLM,
01402     IN DWORD HwProfile,
01403     IN DWORD samDesired);
01404 
01405 /***********************************************************************
01406  *              SetupDiCreateDevRegKeyW (SETUPAPI.@)
01407  */
01408 HKEY WINAPI SetupDiCreateDevRegKeyW(
01409         HDEVINFO DeviceInfoSet,
01410         PSP_DEVINFO_DATA DeviceInfoData,
01411         DWORD Scope,
01412         DWORD HwProfile,
01413         DWORD KeyType,
01414         HINF InfHandle,
01415         PCWSTR InfSectionName)
01416 {
01417     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
01418     HKEY key = INVALID_HANDLE_VALUE;
01419     LPWSTR lpGuidString = NULL;
01420     LPWSTR DriverKey = NULL; /* {GUID}\Index */
01421     LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
01422     DWORD Index; /* Index used in the DriverKey name */
01423     DWORD dwSize;
01424     DWORD Disposition;
01425     DWORD rc;
01426     HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
01427     HKEY hEnumKey = NULL;
01428     HKEY hClassKey = NULL;
01429     HKEY hDeviceKey = INVALID_HANDLE_VALUE;
01430     HKEY hKey = NULL;
01431     HKEY RootKey;
01432 
01433     TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
01434             HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
01435 
01436     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
01437     {
01438         SetLastError(ERROR_INVALID_HANDLE);
01439         return INVALID_HANDLE_VALUE;
01440     }
01441     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
01442     {
01443         SetLastError(ERROR_INVALID_HANDLE);
01444         return INVALID_HANDLE_VALUE;
01445     }
01446     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
01447             || !DeviceInfoData->Reserved)
01448     {
01449         SetLastError(ERROR_INVALID_PARAMETER);
01450         return INVALID_HANDLE_VALUE;
01451     }
01452     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
01453     {
01454         SetLastError(ERROR_INVALID_FLAGS);
01455         return INVALID_HANDLE_VALUE;
01456     }
01457     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
01458     {
01459         SetLastError(ERROR_INVALID_FLAGS);
01460         return INVALID_HANDLE_VALUE;
01461     }
01462     if (InfHandle && !InfSectionName)
01463     {
01464         SetLastError(ERROR_INVALID_PARAMETER);
01465         return INVALID_HANDLE_VALUE;
01466     }
01467     if (!InfHandle && InfSectionName)
01468     {
01469         SetLastError(ERROR_INVALID_PARAMETER);
01470         return INVALID_HANDLE_VALUE;
01471     }
01472 
01473         if (Scope == DICS_FLAG_GLOBAL)
01474             RootKey = set->HKLM;
01475         else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
01476         {
01477             hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
01478             if (hHWProfileKey == INVALID_HANDLE_VALUE)
01479                 goto cleanup;
01480             RootKey = hHWProfileKey;
01481         }
01482 
01483         if (KeyType == DIREG_DEV)
01484         {
01485             struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
01486 
01487             rc = RegCreateKeyExW(
01488                 RootKey,
01489                 REGSTR_PATH_SYSTEMENUM,
01490                 0,
01491                 NULL,
01492                 REG_OPTION_NON_VOLATILE,
01493                 KEY_CREATE_SUB_KEY,
01494                 NULL,
01495                 &hEnumKey,
01496                 NULL);
01497             if (rc != ERROR_SUCCESS)
01498             {
01499                 SetLastError(rc);
01500                 goto cleanup;
01501             }
01502             rc = RegCreateKeyExW(
01503                 hEnumKey,
01504                 deviceInfo->instanceId,
01505                 0,
01506                 NULL,
01507                 REG_OPTION_NON_VOLATILE,
01508 #if _WIN32_WINNT >= 0x502
01509                 KEY_READ | KEY_WRITE,
01510 #else
01511                 KEY_ALL_ACCESS,
01512 #endif
01513                 NULL,
01514                 &hKey,
01515                 NULL);
01516             if (rc != ERROR_SUCCESS)
01517             {
01518                 SetLastError(rc);
01519                 goto cleanup;
01520             }
01521         }
01522         else /* KeyType == DIREG_DRV */
01523         {
01524             /* Open device key, to read Driver value */
01525             hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
01526             if (hDeviceKey == INVALID_HANDLE_VALUE)
01527                 goto cleanup;
01528 
01529             rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
01530             if (rc != ERROR_SUCCESS)
01531             {
01532                 SetLastError(rc);
01533                 goto cleanup;
01534             }
01535 
01536             rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
01537             if (rc != ERROR_SUCCESS)
01538             {
01539                 /* Create a new driver key */
01540 
01541                 if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
01542                     goto cleanup;
01543 
01544                 /* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
01545                 DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
01546                 if (!DriverKey)
01547                 {
01548                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01549                     goto cleanup;
01550                 }
01551 
01552                 DriverKey[0] = '{';
01553                 strcpyW(&DriverKey[1], lpGuidString);
01554                 pDeviceInstance = &DriverKey[strlenW(DriverKey)];
01555                 *pDeviceInstance++ = '}';
01556                 *pDeviceInstance++ = '\\';
01557 
01558                 /* Try all values for Index between 0 and 9999 */
01559                 Index = 0;
01560                 while (Index <= 9999)
01561                 {
01562                     sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
01563                     rc = RegCreateKeyExW(hClassKey,
01564                         DriverKey,
01565                         0,
01566                         NULL,
01567                         REG_OPTION_NON_VOLATILE,
01568 #if _WIN32_WINNT >= 0x502
01569                         KEY_READ | KEY_WRITE,
01570 #else
01571                         KEY_ALL_ACCESS,
01572 #endif
01573                         NULL,
01574                         &hKey,
01575                         &Disposition);
01576                     if (rc != ERROR_SUCCESS)
01577                     {
01578                         SetLastError(rc);
01579                         goto cleanup;
01580                     }
01581                     if (Disposition == REG_CREATED_NEW_KEY)
01582                         break;
01583                     RegCloseKey(hKey);
01584                     hKey = NULL;
01585                     Index++;
01586                 }
01587 
01588                 if (Index > 9999)
01589                 {
01590                     /* Unable to create more than 9999 devices within the same class */
01591                     SetLastError(ERROR_GEN_FAILURE);
01592                     goto cleanup;
01593                 }
01594 
01595                 /* Write the new Driver value */
01596                 rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
01597                 if (rc != ERROR_SUCCESS)
01598                 {
01599                     SetLastError(rc);
01600                     goto cleanup;
01601                 }
01602 
01603             }
01604             else
01605             {
01606                 /* Open the existing driver key */
01607 
01608                 DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
01609                 if (!DriverKey)
01610                 {
01611                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01612                     goto cleanup;
01613                 }
01614 
01615                 rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
01616                 if (rc != ERROR_SUCCESS)
01617                 {
01618                     SetLastError(rc);
01619                     goto cleanup;
01620                 }
01621 
01622                 rc = RegCreateKeyExW(hClassKey,
01623                     DriverKey,
01624                     0,
01625                     NULL,
01626                     REG_OPTION_NON_VOLATILE,
01627 #if _WIN32_WINNT >= 0x502
01628                     KEY_READ | KEY_WRITE,
01629 #else
01630                     KEY_ALL_ACCESS,
01631 #endif
01632                     NULL,
01633                     &hKey,
01634                     &Disposition);
01635                 if (rc != ERROR_SUCCESS)
01636                 {
01637                     SetLastError(rc);
01638                     goto cleanup;
01639                 }
01640             }
01641         }
01642 
01643         /* Do installation of the specified section */
01644         if (InfHandle)
01645         {
01646             FIXME("Need to install section %s in file %p\n",
01647                 debugstr_w(InfSectionName), InfHandle);
01648         }
01649         key = hKey;
01650 
01651 cleanup:
01652         if (lpGuidString)
01653             RpcStringFreeW(&lpGuidString);
01654         HeapFree(GetProcessHeap(), 0, DriverKey);
01655         if (hHWProfileKey != INVALID_HANDLE_VALUE)
01656             RegCloseKey(hHWProfileKey);
01657         if (hEnumKey != NULL)
01658             RegCloseKey(hEnumKey);
01659         if (hClassKey != NULL)
01660             RegCloseKey(hClassKey);
01661         if (hDeviceKey != INVALID_HANDLE_VALUE)
01662             RegCloseKey(hDeviceKey);
01663         if (hKey != NULL && hKey != key)
01664             RegCloseKey(hKey);
01665 
01666     TRACE("Returning 0x%p\n", key);
01667     return key;
01668 }
01669 
01670 /***********************************************************************
01671  *              SetupDiCreateDeviceInfoA (SETUPAPI.@)
01672  */
01673 BOOL WINAPI SetupDiCreateDeviceInfoA(
01674         HDEVINFO DeviceInfoSet,
01675         PCSTR DeviceName,
01676         CONST GUID *ClassGuid,
01677         PCSTR DeviceDescription,
01678         HWND hwndParent,
01679         DWORD CreationFlags,
01680         PSP_DEVINFO_DATA DeviceInfoData)
01681 {
01682     BOOL ret;
01683     LPWSTR DeviceNameW = NULL;
01684     LPWSTR DeviceDescriptionW = NULL;
01685 
01686     TRACE("\n");
01687 
01688     if (DeviceName)
01689     {
01690         DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
01691         if (DeviceNameW == NULL) return FALSE;
01692     }
01693     if (DeviceDescription)
01694     {
01695         DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
01696         if (DeviceDescriptionW == NULL)
01697         {
01698             MyFree(DeviceNameW);
01699             return FALSE;
01700         }
01701     }
01702 
01703     ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
01704             hwndParent, CreationFlags, DeviceInfoData);
01705 
01706     MyFree(DeviceNameW);
01707     MyFree(DeviceDescriptionW);
01708 
01709     return ret;
01710 }
01711 
01712 /***********************************************************************
01713  *              SetupDiCreateDeviceInfoW (SETUPAPI.@)
01714  */
01715 BOOL WINAPI SetupDiCreateDeviceInfoW(
01716         HDEVINFO DeviceInfoSet,
01717         PCWSTR DeviceName,
01718         CONST GUID *ClassGuid,
01719         PCWSTR DeviceDescription,
01720         HWND hwndParent,
01721         DWORD CreationFlags,
01722         PSP_DEVINFO_DATA DeviceInfoData)
01723 {
01724     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
01725     struct DeviceInfo *deviceInfo = NULL;
01726     BOOL ret = FALSE;
01727     CONFIGRET cr;
01728     DEVINST RootDevInst;
01729     DEVINST DevInst;
01730 
01731     TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
01732         debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
01733         hwndParent, CreationFlags, DeviceInfoData);
01734 
01735     if (!DeviceName)
01736     {
01737         SetLastError(ERROR_INVALID_DEVINST_NAME);
01738         return FALSE;
01739     }
01740     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
01741     {
01742         SetLastError(ERROR_INVALID_HANDLE);
01743         return FALSE;
01744     }
01745     if (!ClassGuid)
01746     {
01747         SetLastError(ERROR_INVALID_PARAMETER);
01748         return FALSE;
01749     }
01750     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
01751     {
01752         SetLastError(ERROR_INVALID_HANDLE);
01753         return FALSE;
01754     }
01755     if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
01756         !IsEqualGUID(ClassGuid, &set->ClassGuid))
01757     {
01758         SetLastError(ERROR_CLASS_MISMATCH);
01759         return FALSE;
01760     }
01761     if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
01762     {
01763         TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
01764         SetLastError(ERROR_INVALID_FLAGS);
01765         return FALSE;
01766     }
01767 
01768     /* Get the root device instance */
01769     cr = CM_Locate_DevInst_ExW(&RootDevInst,
01770                                NULL,
01771                                CM_LOCATE_DEVINST_NORMAL,
01772                                set->hMachine);
01773     if (cr != CR_SUCCESS)
01774     {
01775         SetLastError(ERROR_INVALID_DATA);
01776         return FALSE;
01777     }
01778 
01779     /* Create the new device instance */
01780     cr = CM_Create_DevInst_ExW(&DevInst,
01781                                (DEVINSTID)DeviceName,
01782                                RootDevInst,
01783                                0,
01784                                set->hMachine);
01785     if (cr != CR_SUCCESS)
01786     {
01787         SetLastError(GetErrorCodeFromCrCode(cr));
01788         return FALSE;
01789     }
01790 
01791     if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
01792     {
01793         InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
01794 
01795         if (!DeviceInfoData)
01796             ret = TRUE;
01797         else
01798         {
01799             if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
01800             {
01801                 SetLastError(ERROR_INVALID_USER_BUFFER);
01802             }
01803             else
01804             {
01805                 memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
01806                 DeviceInfoData->DevInst = deviceInfo->dnDevInst;
01807                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
01808                 ret = TRUE;
01809             }
01810         }
01811     }
01812 
01813     if (ret == FALSE)
01814     {
01815         if (deviceInfo != NULL)
01816         {
01817             /* Remove deviceInfo from List */
01818             RemoveEntryList(&deviceInfo->ListEntry);
01819 
01820             /* Destroy deviceInfo */
01821             DestroyDeviceInfo(deviceInfo);
01822         }
01823     }
01824 
01825     TRACE("Returning %d\n", ret);
01826     return ret;
01827 }
01828 
01829 /***********************************************************************
01830  *      SetupDiRegisterDeviceInfo (SETUPAPI.@)
01831  */
01832 BOOL WINAPI SetupDiRegisterDeviceInfo(
01833         HDEVINFO DeviceInfoSet,
01834         PSP_DEVINFO_DATA DeviceInfoData,
01835         DWORD Flags,
01836         PSP_DETSIG_CMPPROC CompareProc,
01837         PVOID CompareContext,
01838         PSP_DEVINFO_DATA DupDeviceInfoData)
01839 {
01840     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
01841     WCHAR DevInstId[MAX_DEVICE_ID_LEN];
01842     DEVINST ParentDevInst;
01843     CONFIGRET cr;
01844     DWORD dwError = ERROR_SUCCESS;
01845 
01846     TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
01847             CompareProc, CompareContext, DupDeviceInfoData);
01848 
01849     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
01850     {
01851         SetLastError(ERROR_INVALID_HANDLE);
01852         return FALSE;
01853     }
01854     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
01855     {
01856         SetLastError(ERROR_INVALID_HANDLE);
01857         return FALSE;
01858     }
01859     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
01860             || !DeviceInfoData->Reserved)
01861     {
01862         SetLastError(ERROR_INVALID_PARAMETER);
01863         return FALSE;
01864     }
01865 
01866     if (Flags & ~SPRDI_FIND_DUPS)
01867     {
01868         TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
01869         SetLastError(ERROR_INVALID_FLAGS);
01870         return FALSE;
01871     }
01872 
01873     if (Flags & SPRDI_FIND_DUPS)
01874     {
01875         FIXME("Unimplemented codepath!\n");
01876     }
01877 
01878     CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
01879                         DevInstId,
01880                         MAX_DEVICE_ID_LEN,
01881                         0,
01882                         set->hMachine);
01883 
01884     CM_Get_Parent_Ex(&ParentDevInst,
01885                      DeviceInfoData->DevInst,
01886                      0,
01887                      set->hMachine);
01888 
01889     cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
01890                               DevInstId,
01891                               ParentDevInst,
01892                               CM_CREATE_DEVINST_NORMAL | CM_CREATE_DEVINST_DO_NOT_INSTALL,
01893                               set->hMachine);
01894     if (cr != CR_SUCCESS)
01895     {
01896         dwError = ERROR_NO_SUCH_DEVINST;
01897     }
01898 
01899     SetLastError(dwError);
01900 
01901     return (dwError == ERROR_SUCCESS);
01902 }
01903 
01904 /***********************************************************************
01905  *      SetupDiEnumDeviceInfo (SETUPAPI.@)
01906  */
01907 BOOL WINAPI SetupDiEnumDeviceInfo(
01908         HDEVINFO  devinfo,
01909         DWORD  index,
01910         PSP_DEVINFO_DATA info)
01911 {
01912     BOOL ret = FALSE;
01913 
01914     TRACE("%p %d %p\n", devinfo, index, info);
01915 
01916     if(info==NULL)
01917     {
01918         SetLastError(ERROR_INVALID_PARAMETER);
01919         return FALSE;
01920     }
01921     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
01922     {
01923         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
01924         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
01925         {
01926             if (info->cbSize != sizeof(SP_DEVINFO_DATA))
01927                 SetLastError(ERROR_INVALID_USER_BUFFER);
01928             else
01929             {
01930                 PLIST_ENTRY ItemList = list->ListHead.Flink;
01931                 while (ItemList != &list->ListHead && index-- > 0)
01932                     ItemList = ItemList->Flink;
01933                 if (ItemList == &list->ListHead)
01934                     SetLastError(ERROR_NO_MORE_ITEMS);
01935                 else
01936                 {
01937                     struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
01938                     memcpy(&info->ClassGuid,
01939                         &DevInfo->ClassGuid,
01940                         sizeof(GUID));
01941                     info->DevInst = DevInfo->dnDevInst;
01942                     info->Reserved = (ULONG_PTR)DevInfo;
01943                     ret = TRUE;
01944                 }
01945             }
01946         }
01947         else
01948             SetLastError(ERROR_INVALID_HANDLE);
01949     }
01950     else
01951         SetLastError(ERROR_INVALID_HANDLE);
01952     return ret;
01953 }
01954 
01955 /***********************************************************************
01956  *      SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
01957  */
01958 BOOL WINAPI SetupDiGetDeviceInstanceIdA(
01959         HDEVINFO DeviceInfoSet,
01960         PSP_DEVINFO_DATA DeviceInfoData,
01961         PSTR DeviceInstanceId,
01962         DWORD DeviceInstanceIdSize,
01963         PDWORD RequiredSize)
01964 {
01965     BOOL ret = FALSE;
01966     DWORD size;
01967     PWSTR instanceId;
01968 
01969     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
01970             DeviceInstanceIdSize, RequiredSize);
01971 
01972     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
01973     {
01974         SetLastError(ERROR_INVALID_PARAMETER);
01975         return FALSE;
01976     }
01977 
01978     ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
01979                                 DeviceInfoData,
01980                                 NULL,
01981                                 0,
01982                                 &size);
01983     if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
01984         return FALSE;
01985     instanceId = MyMalloc(size * sizeof(WCHAR));
01986     if (instanceId)
01987     {
01988         ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
01989                                           DeviceInfoData,
01990                                           instanceId,
01991                                           size,
01992                                           &size);
01993         if (ret)
01994         {
01995             int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
01996                                           DeviceInstanceId,
01997                                           DeviceInstanceIdSize, NULL, NULL);
01998 
01999             if (!len)
02000                 ret = FALSE;
02001             else
02002             {
02003                 if (len > DeviceInstanceIdSize)
02004                 {
02005                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
02006                     ret = FALSE;
02007                 }
02008                 if (RequiredSize)
02009                     *RequiredSize = len;
02010             }
02011         }
02012         MyFree(instanceId);
02013     }
02014     else
02015     {
02016         if (RequiredSize)
02017             *RequiredSize = size;
02018         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02019         ret = FALSE;
02020     }
02021     return ret;
02022 }
02023 
02024 /***********************************************************************
02025  *      SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
02026  */
02027 BOOL WINAPI SetupDiGetDeviceInstanceIdW(
02028         HDEVINFO DeviceInfoSet,
02029         PSP_DEVINFO_DATA DeviceInfoData,
02030         PWSTR DeviceInstanceId,
02031         DWORD DeviceInstanceIdSize,
02032         PDWORD RequiredSize)
02033 {
02034     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02035     struct DeviceInfo *devInfo;
02036 
02037     TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
02038             DeviceInstanceIdSize, RequiredSize);
02039 
02040     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
02041     {
02042         SetLastError(ERROR_INVALID_HANDLE);
02043         return FALSE;
02044     }
02045     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02046     {
02047         SetLastError(ERROR_INVALID_HANDLE);
02048         return FALSE;
02049     }
02050     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
02051             || !DeviceInfoData->Reserved)
02052     {
02053         SetLastError(ERROR_INVALID_PARAMETER);
02054         return FALSE;
02055     }
02056     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
02057     if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
02058     {
02059         SetLastError(ERROR_INVALID_PARAMETER);
02060         return FALSE;
02061     }
02062     if (DeviceInstanceId && DeviceInstanceIdSize == 0)
02063     {
02064         SetLastError(ERROR_INVALID_PARAMETER);
02065         return FALSE;
02066     }
02067     TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
02068     if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
02069     {
02070         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02071         if (RequiredSize)
02072             *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
02073         return FALSE;
02074     }
02075     lstrcpyW(DeviceInstanceId, devInfo->instanceId);
02076     if (RequiredSize)
02077         *RequiredSize = lstrlenW(devInfo->instanceId) + 1;
02078     return TRUE;
02079 }
02080 
02081 /***********************************************************************
02082  *      SetupDiGetActualSectionToInstallA (SETUPAPI.@)
02083  */
02084 BOOL WINAPI SetupDiGetActualSectionToInstallA(
02085         HINF InfHandle,
02086         PCSTR InfSectionName,
02087         PSTR InfSectionWithExt,
02088         DWORD InfSectionWithExtSize,
02089         PDWORD RequiredSize,
02090         PSTR *Extension)
02091 {
02092     return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
02093         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
02094         Extension, NULL);
02095 }
02096 
02097 /***********************************************************************
02098  *      SetupDiGetActualSectionToInstallW (SETUPAPI.@)
02099  */
02100 BOOL WINAPI SetupDiGetActualSectionToInstallW(
02101         HINF InfHandle,
02102         PCWSTR InfSectionName,
02103         PWSTR InfSectionWithExt,
02104         DWORD InfSectionWithExtSize,
02105         PDWORD RequiredSize,
02106         PWSTR *Extension)
02107 {
02108     return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
02109         NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
02110         Extension, NULL);
02111 }
02112 
02113 /***********************************************************************
02114  *      SetupDiGetActualSectionToInstallExA  (SETUPAPI.@)
02115  */
02116 BOOL WINAPI
02117 SetupDiGetActualSectionToInstallExA(
02118         IN HINF InfHandle,
02119         IN PCSTR InfSectionName,
02120         IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
02121         OUT PSTR InfSectionWithExt OPTIONAL,
02122         IN DWORD InfSectionWithExtSize,
02123         OUT PDWORD RequiredSize OPTIONAL,
02124         OUT PSTR* Extension OPTIONAL,
02125         IN PVOID Reserved)
02126 {
02127     LPWSTR InfSectionNameW = NULL;
02128     LPWSTR InfSectionWithExtW = NULL;
02129     PWSTR ExtensionW;
02130     BOOL bResult = FALSE;
02131 
02132     TRACE("\n");
02133 
02134     if (InfSectionName)
02135     {
02136         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
02137         if (InfSectionNameW == NULL)
02138             goto cleanup;
02139     }
02140     if (InfSectionWithExt)
02141     {
02142         InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
02143         if (InfSectionWithExtW == NULL)
02144             goto cleanup;
02145     }
02146 
02147     bResult = SetupDiGetActualSectionToInstallExW(
02148         InfHandle, InfSectionNameW, AlternatePlatformInfo,
02149         InfSectionWithExt ? InfSectionWithExtW : NULL,
02150         InfSectionWithExtSize,
02151         RequiredSize,
02152         Extension ? &ExtensionW : NULL,
02153         Reserved);
02154 
02155     if (bResult && InfSectionWithExt)
02156     {
02157          bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
02158              InfSectionWithExtSize, NULL, NULL) != 0;
02159     }
02160     if (bResult && Extension)
02161     {
02162         if (ExtensionW == NULL)
02163             *Extension = NULL;
02164          else
02165             *Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
02166     }
02167 
02168 cleanup:
02169     MyFree(InfSectionNameW);
02170     MyFree(InfSectionWithExtW);
02171 
02172     return bResult;
02173 }
02174 
02175 /***********************************************************************
02176  *      SetupDiGetClassDescriptionA  (SETUPAPI.@)
02177  */
02178 BOOL WINAPI SetupDiGetClassDescriptionA(
02179         const GUID* ClassGuid,
02180         PSTR ClassDescription,
02181         DWORD ClassDescriptionSize,
02182         PDWORD RequiredSize)
02183 {
02184     return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
02185                                          ClassDescriptionSize,
02186                                          RequiredSize, NULL, NULL);
02187 }
02188 
02189 /***********************************************************************
02190  *      SetupDiGetClassDescriptionW  (SETUPAPI.@)
02191  */
02192 BOOL WINAPI SetupDiGetClassDescriptionW(
02193         const GUID* ClassGuid,
02194         PWSTR ClassDescription,
02195         DWORD ClassDescriptionSize,
02196         PDWORD RequiredSize)
02197 {
02198     return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
02199                                          ClassDescriptionSize,
02200                                          RequiredSize, NULL, NULL);
02201 }
02202 
02203 /***********************************************************************
02204  *      SetupDiGetClassDescriptionExA  (SETUPAPI.@)
02205  */
02206 BOOL WINAPI SetupDiGetClassDescriptionExA(
02207         const GUID* ClassGuid,
02208         PSTR ClassDescription,
02209         DWORD ClassDescriptionSize,
02210         PDWORD RequiredSize,
02211         PCSTR MachineName,
02212         PVOID Reserved)
02213 {
02214     PWCHAR ClassDescriptionW = NULL;
02215     LPWSTR MachineNameW = NULL;
02216     BOOL ret = FALSE;
02217 
02218     TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
02219         ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
02220 
02221     if (ClassDescriptionSize > 0)
02222     {
02223         ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
02224         if (!ClassDescriptionW)
02225         {
02226             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02227             goto cleanup;
02228         }
02229     }
02230 
02231     if (MachineName)
02232     {
02233         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
02234         if (!MachineNameW)
02235         {
02236             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02237             goto cleanup;
02238         }
02239     }
02240 
02241     ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
02242         ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
02243     if (ret)
02244     {
02245         DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
02246             ClassDescriptionSize, NULL, NULL);
02247         if (len == 0 || len > ClassDescriptionSize)
02248         {
02249             SetLastError(ERROR_INSUFFICIENT_BUFFER);
02250             ret = FALSE;
02251         }
02252     }
02253 
02254 cleanup:
02255     MyFree(ClassDescriptionW);
02256     MyFree(MachineNameW);
02257     return ret;
02258 }
02259 
02260 /***********************************************************************
02261  *      SetupDiGetClassDescriptionExW  (SETUPAPI.@)
02262  */
02263 BOOL WINAPI SetupDiGetClassDescriptionExW(
02264         const GUID* ClassGuid,
02265         PWSTR ClassDescription,
02266         DWORD ClassDescriptionSize,
02267         PDWORD RequiredSize,
02268         PCWSTR MachineName,
02269         PVOID Reserved)
02270 {
02271     HKEY hKey;
02272     DWORD dwLength;
02273     DWORD dwRegType;
02274     LONG rc;
02275     PWSTR Buffer;
02276 
02277     TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
02278         ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
02279 
02280     /* Make sure there's a GUID */
02281     if (!ClassGuid)
02282     {
02283         SetLastError(ERROR_INVALID_PARAMETER);
02284         return FALSE;
02285     }
02286 
02287     /* Make sure there's a real buffer when there's a size */
02288     if (!ClassDescription && ClassDescriptionSize > 0)
02289     {
02290         SetLastError(ERROR_INVALID_PARAMETER);
02291         return FALSE;
02292     }
02293 
02294     /* Open the key for the GUID */
02295     hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
02296                                      KEY_QUERY_VALUE,
02297                                      DIOCR_INSTALLER,
02298                                      MachineName,
02299                                      Reserved);
02300     if (hKey == INVALID_HANDLE_VALUE)
02301         return FALSE;
02302 
02303     /* Retrieve the class description data and close the key */
02304     rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
02305     RegCloseKey(hKey);
02306 
02307     /* Make sure we got the data */
02308     if (rc != ERROR_SUCCESS)
02309     {
02310         SetLastError(rc);
02311         return FALSE;
02312     }
02313 
02314     /* Make sure the data is a string */
02315     if (dwRegType != REG_SZ)
02316     {
02317         MyFree(Buffer);
02318         SetLastError(ERROR_GEN_FAILURE);
02319         return FALSE;
02320     }
02321 
02322     /* Determine the length of the class description */
02323     dwLength /= sizeof(WCHAR);
02324 
02325     /* Count the null-terminator if none is present */
02326     if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
02327         dwLength++;
02328 
02329     /* Inform the caller about the class description */
02330     if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
02331     {
02332         memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
02333         ClassDescription[dwLength - 1] = UNICODE_NULL;
02334     }
02335 
02336     /* Inform the caller about the required size */
02337     if (RequiredSize != NULL)
02338         *RequiredSize = dwLength;
02339 
02340     /* Clean up the buffer */
02341     MyFree(Buffer);
02342 
02343     /* Make sure the buffer was large enough */
02344     if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
02345     {
02346         SetLastError(ERROR_INSUFFICIENT_BUFFER);
02347         return FALSE;
02348     }
02349 
02350     return TRUE;
02351 }
02352 
02353 /***********************************************************************
02354  *      SetupDiGetClassDevsA (SETUPAPI.@)
02355  */
02356 HDEVINFO WINAPI SetupDiGetClassDevsA(
02357         CONST GUID *class,
02358         LPCSTR enumstr,
02359         HWND parent,
02360         DWORD flags)
02361 {
02362     return SetupDiGetClassDevsExA(class, enumstr, parent,
02363                                   flags, NULL, NULL, NULL);
02364 }
02365 
02366 /***********************************************************************
02367  *        SetupDiGetClassDevsExA (SETUPAPI.@)
02368  */
02369 HDEVINFO WINAPI SetupDiGetClassDevsExA(
02370         const GUID *class,
02371         PCSTR enumstr,
02372         HWND parent,
02373         DWORD flags,
02374         HDEVINFO deviceset,
02375         PCSTR machine,
02376         PVOID reserved)
02377 {
02378     HDEVINFO ret;
02379     LPWSTR enumstrW = NULL, machineW = NULL;
02380 
02381     if (enumstr)
02382     {
02383         enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
02384         if (!enumstrW)
02385         {
02386             ret = INVALID_HANDLE_VALUE;
02387             goto end;
02388         }
02389     }
02390     if (machine)
02391     {
02392         machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
02393         if (!machineW)
02394         {
02395             MyFree(enumstrW);
02396             ret = INVALID_HANDLE_VALUE;
02397             goto end;
02398         }
02399     }
02400     ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
02401             machineW, reserved);
02402     MyFree(enumstrW);
02403     MyFree(machineW);
02404 
02405 end:
02406     return ret;
02407 }
02408 
02409 /***********************************************************************
02410  *      SetupDiGetClassDevsW (SETUPAPI.@)
02411  */
02412 HDEVINFO WINAPI SetupDiGetClassDevsW(
02413         CONST GUID *class,
02414         LPCWSTR enumstr,
02415         HWND parent,
02416         DWORD flags)
02417 {
02418     return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
02419             NULL);
02420 }
02421 
02422 /***********************************************************************
02423  *              SetupDiGetClassDevsExW (SETUPAPI.@)
02424  */
02425 HDEVINFO WINAPI SetupDiGetClassDevsExW(
02426         CONST GUID *class,
02427         PCWSTR enumstr,
02428         HWND parent,
02429         DWORD flags,
02430         HDEVINFO deviceset,
02431         PCWSTR machine,
02432         PVOID reserved)
02433 {
02434     HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
02435     struct DeviceInfoSet *list;
02436     CONST GUID *pClassGuid;
02437     LONG rc;
02438     HDEVINFO set = INVALID_HANDLE_VALUE;
02439 
02440     TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
02441             debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
02442             reserved);
02443 
02444     if (!(flags & DIGCF_ALLCLASSES) && !class)
02445     {
02446         SetLastError(ERROR_INVALID_PARAMETER);
02447         return INVALID_HANDLE_VALUE;
02448     }
02449 
02450     /* Create the deviceset if not set */
02451     if (deviceset)
02452     {
02453         list = (struct DeviceInfoSet *)deviceset;
02454         if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02455         {
02456             SetLastError(ERROR_INVALID_HANDLE);
02457             goto cleanup;
02458         }
02459         hDeviceInfo = deviceset;
02460     }
02461     else
02462     {
02463          hDeviceInfo = SetupDiCreateDeviceInfoListExW(
02464              flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
02465              NULL, machine, NULL);
02466          if (hDeviceInfo == INVALID_HANDLE_VALUE)
02467              goto cleanup;
02468          list = (struct DeviceInfoSet *)hDeviceInfo;
02469     }
02470 
02471     if (flags & DIGCF_PROFILE)
02472         FIXME(": flag DIGCF_PROFILE ignored\n");
02473 
02474     if (flags & DIGCF_DEVICEINTERFACE)
02475     {
02476         if (!class)
02477         {
02478             SetLastError(ERROR_INVALID_PARAMETER);
02479             goto cleanup;
02480         }
02481         rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
02482     }
02483     else
02484     {
02485         /* Determine which class(es) should be included in the deviceset */
02486         if (flags & DIGCF_ALLCLASSES)
02487         {
02488             /* The caller wants all classes. Check if
02489              * the deviceset limits us to one class */
02490             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
02491                 pClassGuid = NULL;
02492             else
02493                 pClassGuid = &list->ClassGuid;
02494         }
02495         else if (class)
02496         {
02497             /* The caller wants one class. Check if it matches deviceset class */
02498             if (IsEqualIID(&list->ClassGuid, class)
02499              || IsEqualIID(&list->ClassGuid, &GUID_NULL))
02500             {
02501                 pClassGuid = class;
02502             }
02503             else
02504             {
02505                 SetLastError(ERROR_INVALID_PARAMETER);
02506                 goto cleanup;
02507             }
02508         }
02509         else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
02510         {
02511             /* No class specified. Try to use the one of the deviceset */
02512             if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
02513                 pClassGuid = &list->ClassGuid;
02514             else
02515             {
02516                 SetLastError(ERROR_INVALID_PARAMETER);
02517                 goto cleanup;
02518             }
02519         }
02520         else
02521         {
02522             SetLastError(ERROR_INVALID_PARAMETER);
02523             goto cleanup;
02524         }
02525         rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
02526     }
02527     if (rc != ERROR_SUCCESS)
02528     {
02529         SetLastError(rc);
02530         goto cleanup;
02531     }
02532     set = hDeviceInfo;
02533 
02534 cleanup:
02535     if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
02536         SetupDiDestroyDeviceInfoList(hDeviceInfo);
02537     return set;
02538 }
02539 
02540 /***********************************************************************
02541  *      SetupDiGetDeviceInfoListDetailA  (SETUPAPI.@)
02542  */
02543 BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
02544         HDEVINFO DeviceInfoSet,
02545         PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
02546 {
02547     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02548 
02549     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
02550 
02551     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
02552     {
02553         SetLastError(ERROR_INVALID_HANDLE);
02554         return FALSE;
02555     }
02556     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02557     {
02558         SetLastError(ERROR_INVALID_HANDLE);
02559         return FALSE;
02560     }
02561     if (!DevInfoData ||
02562             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
02563     {
02564         SetLastError(ERROR_INVALID_PARAMETER);
02565         return FALSE;
02566     }
02567     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
02568     DevInfoData->RemoteMachineHandle = set->hMachine;
02569     if (set->MachineName)
02570     {
02571         FIXME("Stub\n");
02572         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
02573         return FALSE;
02574     }
02575     else
02576         DevInfoData->RemoteMachineName[0] = 0;
02577 
02578     return TRUE;
02579 }
02580 
02581 /***********************************************************************
02582  *      SetupDiGetDeviceInfoListDetailW  (SETUPAPI.@)
02583  */
02584 BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
02585         HDEVINFO DeviceInfoSet,
02586         PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
02587 {
02588     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02589 
02590     TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
02591 
02592     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
02593     {
02594         SetLastError(ERROR_INVALID_HANDLE);
02595         return FALSE;
02596     }
02597     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02598     {
02599         SetLastError(ERROR_INVALID_HANDLE);
02600         return FALSE;
02601     }
02602     if (!DevInfoData ||
02603             DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
02604     {
02605         SetLastError(ERROR_INVALID_PARAMETER);
02606         return FALSE;
02607     }
02608     memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
02609     DevInfoData->RemoteMachineHandle = set->hMachine;
02610     if (set->MachineName)
02611         strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
02612     else
02613         DevInfoData->RemoteMachineName[0] = 0;
02614 
02615     return TRUE;
02616 }
02617 
02618 /***********************************************************************
02619  *      SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
02620  */
02621 BOOL WINAPI SetupDiCreateDeviceInterfaceA(
02622         HDEVINFO DeviceInfoSet,
02623         PSP_DEVINFO_DATA DeviceInfoData,
02624         const GUID *InterfaceClassGuid,
02625         PCSTR ReferenceString,
02626         DWORD CreationFlags,
02627         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
02628 {
02629     BOOL ret;
02630     LPWSTR ReferenceStringW = NULL;
02631 
02632     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
02633             debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
02634             CreationFlags, DeviceInterfaceData);
02635 
02636     if (ReferenceString)
02637     {
02638         ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
02639         if (ReferenceStringW == NULL) return FALSE;
02640     }
02641 
02642     ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
02643             InterfaceClassGuid, ReferenceStringW, CreationFlags,
02644             DeviceInterfaceData);
02645 
02646     MyFree(ReferenceStringW);
02647 
02648     return ret;
02649 }
02650 
02651 /***********************************************************************
02652  *      SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
02653  */
02654 BOOL WINAPI SetupDiCreateDeviceInterfaceW(
02655         HDEVINFO DeviceInfoSet,
02656         PSP_DEVINFO_DATA DeviceInfoData,
02657         const GUID *InterfaceClassGuid,
02658         PCWSTR ReferenceString,
02659         DWORD CreationFlags,
02660         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
02661 {
02662     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02663     TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
02664             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
02665             CreationFlags, DeviceInterfaceData);
02666 
02667     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
02668     {
02669         SetLastError(ERROR_INVALID_HANDLE);
02670         return FALSE;
02671     }
02672     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02673     {
02674         SetLastError(ERROR_INVALID_HANDLE);
02675         return FALSE;
02676     }
02677     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
02678             || !DeviceInfoData->Reserved)
02679     {
02680         SetLastError(ERROR_INVALID_PARAMETER);
02681         return FALSE;
02682     }
02683     if (!InterfaceClassGuid)
02684     {
02685         SetLastError(ERROR_INVALID_USER_BUFFER);
02686         return FALSE;
02687     }
02688 
02689     FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
02690             debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
02691             CreationFlags, DeviceInterfaceData);
02692     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
02693     return FALSE;
02694 }
02695 
02696 /***********************************************************************
02697  *      SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
02698  */
02699 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
02700         HDEVINFO DeviceInfoSet,
02701         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
02702         DWORD Reserved,
02703         REGSAM samDesired,
02704         HINF InfHandle,
02705         PCSTR InfSectionName)
02706 {
02707     HKEY key;
02708     PWSTR InfSectionNameW = NULL;
02709 
02710     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
02711             samDesired, InfHandle, InfSectionName);
02712     if (InfHandle)
02713     {
02714         if (!InfSectionName)
02715         {
02716             SetLastError(ERROR_INVALID_PARAMETER);
02717             return INVALID_HANDLE_VALUE;
02718         }
02719         InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
02720         if (!InfSectionNameW)
02721             return INVALID_HANDLE_VALUE;
02722     }
02723     key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
02724             DeviceInterfaceData, Reserved, samDesired, InfHandle,
02725             InfSectionNameW);
02726     MyFree(InfSectionNameW);
02727     return key;
02728 }
02729 
02730 /***********************************************************************
02731  *      SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
02732  */
02733 HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
02734         HDEVINFO DeviceInfoSet,
02735         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
02736         DWORD Reserved,
02737         REGSAM samDesired,
02738         HINF InfHandle,
02739         PCWSTR InfSectionName)
02740 {
02741     HKEY hKey, hDevKey;
02742     LPWSTR SymbolicLink;
02743     DWORD Length, Index;
02744     LONG rc;
02745     WCHAR bracedGuidString[39];
02746     struct DeviceInterface *DevItf;
02747     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02748 
02749     TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
02750             samDesired, InfHandle, InfSectionName);
02751 
02752     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
02753             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02754     {
02755         SetLastError(ERROR_INVALID_HANDLE);
02756         return INVALID_HANDLE_VALUE;
02757     }
02758     if (!DeviceInterfaceData ||
02759             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
02760             !DeviceInterfaceData->Reserved)
02761     {
02762         SetLastError(ERROR_INVALID_PARAMETER);
02763         return INVALID_HANDLE_VALUE;
02764     }
02765     if (InfHandle && !InfSectionName)
02766     {
02767         SetLastError(ERROR_INVALID_PARAMETER);
02768         return INVALID_HANDLE_VALUE;
02769     }
02770 
02771     hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
02772     if (hKey == INVALID_HANDLE_VALUE)
02773     {
02774         hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
02775         if (hKey == INVALID_HANDLE_VALUE)
02776         {
02777             SetLastError(ERROR_INVALID_PARAMETER);
02778             return INVALID_HANDLE_VALUE;
02779         }
02780         SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
02781 
02782         if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
02783         {
02784             SetLastError(ERROR_INVALID_PARAMETER);
02785             return INVALID_HANDLE_VALUE;
02786         }
02787         RegCloseKey(hKey);
02788         hKey = hDevKey;
02789     }
02790 
02791     DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
02792 
02793     Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
02794     SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
02795     if (!SymbolicLink)
02796     {
02797         RegCloseKey(hKey);
02798         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02799         return INVALID_HANDLE_VALUE;
02800     }
02801 
02802     wcscpy(SymbolicLink, DevItf->SymbolicLink);
02803 
02804     Index = 0;
02805     while(SymbolicLink[Index])
02806     {
02807         if (SymbolicLink[Index] == L'\\')
02808         {
02809             SymbolicLink[Index] = L'#';
02810         }
02811         Index++;
02812     }
02813 
02814     rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
02815 
02816     RegCloseKey(hKey);
02817     HeapFree(GetProcessHeap(), 0, SymbolicLink);
02818 
02819     if (rc == ERROR_SUCCESS)
02820     {
02821         if (InfHandle && InfSectionName)
02822         {
02823             if (!SetupInstallFromInfSection(NULL /*FIXME */,
02824                                             InfHandle,
02825                                             InfSectionName,
02826                                             SPINST_INIFILES | SPINST_REGISTRY | SPINST_INI2REG | SPINST_FILES | SPINST_BITREG | SPINST_REGSVR | SPINST_UNREGSVR | SPINST_PROFILEITEMS | SPINST_COPYINF,
02827                                             hDevKey,
02828                                             NULL,
02829                                             0,
02830                                             set->SelectedDevice->InstallParams.InstallMsgHandler,
02831                                             set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
02832                                             INVALID_HANDLE_VALUE,
02833                                             NULL))
02834             {
02835                 RegCloseKey(hDevKey);
02836                 return INVALID_HANDLE_VALUE;
02837             }
02838         }
02839     }
02840 
02841     SetLastError(rc);
02842     return hDevKey;
02843 }
02844 
02845 /***********************************************************************
02846  *      SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
02847  */
02848 BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
02849         HDEVINFO DeviceInfoSet,
02850         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
02851         DWORD Reserved)
02852 {
02853     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02854     BOOL ret = FALSE;
02855 
02856     TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
02857 
02858     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
02859             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02860     {
02861         SetLastError(ERROR_INVALID_HANDLE);
02862         return FALSE;
02863     }
02864     if (!DeviceInterfaceData ||
02865             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
02866             !DeviceInterfaceData->Reserved)
02867     {
02868         SetLastError(ERROR_INVALID_PARAMETER);
02869         return FALSE;
02870     }
02871 
02872     FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
02873     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
02874     return ret;
02875 }
02876 
02877 /***********************************************************************
02878  *      SetupDiEnumDeviceInterfaces (SETUPAPI.@)
02879  *
02880  * PARAMS
02881  *   DeviceInfoSet      [I]    Set of devices from which to enumerate
02882  *                             interfaces
02883  *   DeviceInfoData     [I]    (Optional) If specified, a specific device
02884  *                             instance from which to enumerate interfaces.
02885  *                             If it isn't specified, all interfaces for all
02886  *                             devices in the set are enumerated.
02887  *   InterfaceClassGuid [I]    The interface class to enumerate.
02888  *   MemberIndex        [I]    An index of the interface instance to enumerate.
02889  *                             A caller should start with MemberIndex set to 0,
02890  *                             and continue until the function fails with
02891  *                             ERROR_NO_MORE_ITEMS.
02892  *   DeviceInterfaceData [I/O] Returns an enumerated interface.  Its cbSize
02893  *                             member must be set to
02894  *                             sizeof(SP_DEVICE_INTERFACE_DATA).
02895  *
02896  * RETURNS
02897  *   Success: non-zero value.
02898  *   Failure: FALSE.  Call GetLastError() for more info.
02899  */
02900 BOOL WINAPI SetupDiEnumDeviceInterfaces(
02901         HDEVINFO DeviceInfoSet,
02902         PSP_DEVINFO_DATA DeviceInfoData,
02903         CONST GUID * InterfaceClassGuid,
02904         DWORD MemberIndex,
02905         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
02906 {
02907     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
02908     BOOL ret = FALSE;
02909 
02910     TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
02911      debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
02912 
02913     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
02914             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02915     {
02916         SetLastError(ERROR_INVALID_HANDLE);
02917         return FALSE;
02918     }
02919     if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
02920                 !DeviceInfoData->Reserved))
02921     {
02922         SetLastError(ERROR_INVALID_PARAMETER);
02923         return FALSE;
02924     }
02925     if (!DeviceInterfaceData ||
02926             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
02927     {
02928         SetLastError(ERROR_INVALID_PARAMETER);
02929         return FALSE;
02930     }
02931     if (DeviceInfoData)
02932     {
02933         struct DeviceInfo *devInfo =
02934             (struct DeviceInfo *)DeviceInfoData->Reserved;
02935         BOOL found = FALSE;
02936         PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
02937         while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
02938         {
02939             struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
02940             if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
02941             {
02942                 InterfaceListEntry = InterfaceListEntry->Flink;
02943                 continue;
02944             }
02945             if (MemberIndex-- == 0)
02946             {
02947                 /* return this item */
02948                 memcpy(&DeviceInterfaceData->InterfaceClassGuid,
02949                     &DevItf->InterfaceClassGuid,
02950                     sizeof(GUID));
02951                 DeviceInterfaceData->Flags = DevItf->Flags;
02952                 DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
02953                 found = TRUE;
02954                 ret = TRUE;
02955             }
02956             InterfaceListEntry = InterfaceListEntry->Flink;
02957         }
02958         if (!found)
02959             SetLastError(ERROR_NO_MORE_ITEMS);
02960     }
02961     else
02962     {
02963         BOOL found = FALSE;
02964         PLIST_ENTRY ItemList = set->ListHead.Flink;
02965         while (ItemList != &set->ListHead && !found)
02966         {
02967             PLIST_ENTRY InterfaceListEntry;
02968             struct DeviceInfo *devInfo =
02969                 CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
02970             InterfaceListEntry = devInfo->InterfaceListHead.Flink;
02971             while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
02972             {
02973                 struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
02974                 if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
02975                 {
02976                     InterfaceListEntry = InterfaceListEntry->Flink;
02977                     continue;
02978                 }
02979                 if (MemberIndex-- == 0)
02980                 {
02981                     /* return this item */
02982                     memcpy(&DeviceInterfaceData->InterfaceClassGuid,
02983                         &DevItf->InterfaceClassGuid,
02984                         sizeof(GUID));
02985                     DeviceInterfaceData->Flags = DevItf->Flags;
02986                     DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
02987                     found = TRUE;
02988                     ret = TRUE;
02989                 }
02990                 InterfaceListEntry = InterfaceListEntry->Flink;
02991             }
02992             ItemList = ItemList->Flink;
02993 
02994         }
02995         if (!found)
02996             SetLastError(ERROR_NO_MORE_ITEMS);
02997     }
02998     return ret;
02999 }
03000 
03001 /***********************************************************************
03002  *      SetupDiDestroyDeviceInfoList (SETUPAPI.@)
03003   *
03004  * Destroy a DeviceInfoList and free all used memory of the list.
03005  *
03006  * PARAMS
03007  *   devinfo [I] DeviceInfoList pointer to list to destroy
03008  *
03009  * RETURNS
03010  *   Success: non zero value.
03011  *   Failure: zero value.
03012  */
03013 BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
03014 {
03015     BOOL ret = FALSE;
03016 
03017     TRACE("%p\n", devinfo);
03018     if (devinfo && devinfo != INVALID_HANDLE_VALUE)
03019     {
03020         struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
03021 
03022         if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
03023         {
03024             ret = DestroyDeviceInfoSet(list);
03025         }
03026     }
03027 
03028     if (ret == FALSE)
03029         SetLastError(ERROR_INVALID_HANDLE);
03030 
03031     return ret;
03032 }
03033 
03034 /***********************************************************************
03035  *      SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
03036  */
03037 BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
03038         HDEVINFO DeviceInfoSet,
03039         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
03040         PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
03041         DWORD DeviceInterfaceDetailDataSize,
03042         PDWORD RequiredSize,
03043         PSP_DEVINFO_DATA DeviceInfoData)
03044 {
03045     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
03046     PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
03047     DWORD sizeW = 0, bytesNeeded;
03048     BOOL ret = FALSE;
03049 
03050     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
03051      DeviceInterfaceData, DeviceInterfaceDetailData,
03052      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
03053 
03054     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
03055             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03056     {
03057         SetLastError(ERROR_INVALID_HANDLE);
03058         return FALSE;
03059     }
03060     if (!DeviceInterfaceData ||
03061             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
03062             !DeviceInterfaceData->Reserved)
03063     {
03064         SetLastError(ERROR_INVALID_PARAMETER);
03065         return FALSE;
03066     }
03067     if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
03068     {
03069         SetLastError(ERROR_INVALID_USER_BUFFER);
03070         return FALSE;
03071     }
03072 
03073     if((DeviceInterfaceDetailDataSize != 0) &&
03074         (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
03075     {
03076         SetLastError(ERROR_INVALID_USER_BUFFER);
03077         return FALSE;
03078     }
03079 
03080     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
03081     {
03082         SetLastError(ERROR_INVALID_USER_BUFFER);
03083         return FALSE;
03084     }
03085 
03086 
03087     if (DeviceInterfaceDetailData != NULL)
03088     {
03089         sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
03090             + (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
03091         DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
03092         if (!DeviceInterfaceDetailDataW)
03093         {
03094             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03095         }
03096         DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
03097     }
03098     if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
03099     {
03100         ret = SetupDiGetDeviceInterfaceDetailW(
03101             DeviceInfoSet,
03102             DeviceInterfaceData,
03103             DeviceInterfaceDetailDataW,
03104             sizeW,
03105             &sizeW,
03106             DeviceInfoData);
03107         bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
03108             + FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
03109         if (RequiredSize)
03110             *RequiredSize = bytesNeeded;
03111         if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
03112         {
03113             if (!WideCharToMultiByte(
03114                 CP_ACP, 0,
03115                 DeviceInterfaceDetailDataW->DevicePath, -1,
03116                 DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
03117                 NULL, NULL))
03118             {
03119                 ret = FALSE;
03120             }
03121         }
03122     }
03123     MyFree(DeviceInterfaceDetailDataW);
03124 
03125     return ret;
03126 }
03127 
03128 /***********************************************************************
03129  *      SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
03130  */
03131 BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
03132         HDEVINFO DeviceInfoSet,
03133         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
03134         PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
03135         DWORD DeviceInterfaceDetailDataSize,
03136         PDWORD RequiredSize,
03137         PSP_DEVINFO_DATA DeviceInfoData)
03138 {
03139     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
03140     BOOL ret = FALSE;
03141 
03142     TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
03143      DeviceInterfaceData, DeviceInterfaceDetailData,
03144      DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
03145 
03146     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
03147             set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03148     {
03149         SetLastError(ERROR_INVALID_HANDLE);
03150         return FALSE;
03151     }
03152     if (!DeviceInterfaceData ||
03153             DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
03154             !DeviceInterfaceData->Reserved)
03155     {
03156         SetLastError(ERROR_INVALID_PARAMETER);
03157         return FALSE;
03158     }
03159     if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
03160     {
03161         SetLastError(ERROR_INVALID_USER_BUFFER);
03162         return FALSE;
03163     }
03164     if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
03165     {
03166         SetLastError(ERROR_INVALID_USER_BUFFER);
03167         return FALSE;
03168     }
03169     if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
03170     {
03171         SetLastError(ERROR_INVALID_PARAMETER);
03172         return FALSE;
03173     }
03174     if ((DeviceInterfaceDetailData != NULL)
03175         && (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
03176     {
03177         SetLastError(ERROR_INVALID_PARAMETER);
03178         return FALSE;
03179     }
03180     else
03181     {
03182         struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
03183         LPCWSTR devName = deviceInterface->SymbolicLink;
03184         DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
03185             (lstrlenW(devName) + 1) * sizeof(WCHAR);
03186 
03187         if (sizeRequired > DeviceInterfaceDetailDataSize)
03188         {
03189             SetLastError(ERROR_INSUFFICIENT_BUFFER);
03190             if (RequiredSize)
03191                 *RequiredSize = sizeRequired;
03192         }
03193         else
03194         {
03195             strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
03196             TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
03197             if (DeviceInfoData)
03198             {
03199                 memcpy(&DeviceInfoData->ClassGuid,
03200                     &deviceInterface->DeviceInfo->ClassGuid,
03201                     sizeof(GUID));
03202                 DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
03203                 DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
03204             }
03205             ret = TRUE;
03206         }
03207     }
03208     return ret;
03209 }
03210 
03211 struct PropertyMapEntry
03212 {
03213     DWORD   regType;
03214     LPCSTR  nameA;
03215     LPCWSTR nameW;
03216 };
03217 
03218 static struct PropertyMapEntry PropertyMap[] = {
03219     { REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
03220     { REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
03221     { REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
03222     { 0, NULL, NULL }, /* SPDRP_UNUSED0 */
03223     { REG_SZ, "Service", REGSTR_VAL_SERVICE },
03224     { 0, NULL, NULL }, /* SPDRP_UNUSED1 */
03225     { 0, NULL, NULL }, /* SPDRP_UNUSED2 */
03226     { REG_SZ, "Class", REGSTR_VAL_CLASS },
03227     { REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
03228     { REG_SZ, "Driver", REGSTR_VAL_DRIVER },
03229     { REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
03230     { REG_SZ, "Mfg", REGSTR_VAL_MFG },
03231     { REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
03232     { REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
03233     { 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
03234     { REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
03235     { REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
03236     { REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
03237     { REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
03238     { 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
03239     { 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
03240     { 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
03241     { 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
03242     { REG_BINARY, "Security", REGSTR_SECURITY },
03243     { 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
03244     { 0, NULL, NULL }, /* SPDRP_DEVTYPE */
03245     { 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
03246     { 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
03247     { 0, NULL, NULL }, /* SPDRP_ADDRESS */
03248     { REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
03249     { 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
03250     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
03251     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
03252     { 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
03253     { 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
03254 };
03255 
03256 /***********************************************************************
03257  *      SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
03258  */
03259 BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
03260         HDEVINFO  DeviceInfoSet,
03261         PSP_DEVINFO_DATA  DeviceInfoData,
03262         DWORD   Property,
03263         PDWORD  PropertyRegDataType,
03264         PBYTE   PropertyBuffer,
03265         DWORD   PropertyBufferSize,
03266         PDWORD  RequiredSize)
03267 {
03268     BOOL ret;
03269     BOOL bIsStringProperty;
03270     DWORD RegType;
03271     DWORD RequiredSizeA, RequiredSizeW;
03272     DWORD PropertyBufferSizeW = 0;
03273     PBYTE PropertyBufferW = NULL;
03274 
03275     TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
03276         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
03277         RequiredSize);
03278 
03279     if (PropertyBufferSize != 0)
03280     {
03281         PropertyBufferSizeW = PropertyBufferSize * 2;
03282         PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
03283         if (!PropertyBufferW)
03284         {
03285             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03286             return FALSE;
03287         }
03288     }
03289 
03290     ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
03291                                             DeviceInfoData,
03292                                             Property,
03293                                             &RegType,
03294                                             PropertyBufferW,
03295                                             PropertyBufferSizeW,
03296                                             &RequiredSizeW);
03297 
03298     if (ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
03299     {
03300         bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
03301 
03302         if (bIsStringProperty)
03303            RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
03304         else
03305             RequiredSizeA = RequiredSizeW;
03306         if (RequiredSize)
03307             *RequiredSize = RequiredSizeA;
03308         if (PropertyRegDataType)
03309             *PropertyRegDataType = RegType;
03310     }
03311 
03312     if (!ret)
03313     {
03314         HeapFree(GetProcessHeap(), 0, PropertyBufferW);
03315         return ret;
03316     }
03317 
03318     if (RequiredSizeA <= PropertyBufferSize)
03319     {
03320         if (bIsStringProperty && PropertyBufferSize > 0)
03321         {
03322             if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
03323             {
03324                 /* Last error is already set by WideCharToMultiByte */
03325                 ret = FALSE;
03326             }
03327         }
03328         else
03329             memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
03330     }
03331     else
03332     {
03333         SetLastError(ERROR_INSUFFICIENT_BUFFER);
03334         ret = FALSE;
03335     }
03336 
03337     HeapFree(GetProcessHeap(), 0, PropertyBufferW);
03338     return ret;
03339 }
03340 
03341 /***********************************************************************
03342  *      SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
03343  */
03344 BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
03345         HDEVINFO  DeviceInfoSet,
03346         PSP_DEVINFO_DATA  DeviceInfoData,
03347         DWORD   Property,
03348         PDWORD  PropertyRegDataType,
03349         PBYTE   PropertyBuffer,
03350         DWORD   PropertyBufferSize,
03351         PDWORD  RequiredSize)
03352 {
03353     BOOL ret = FALSE;
03354     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
03355     struct DeviceInfo *devInfo;
03356 
03357     TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
03358         Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
03359         RequiredSize);
03360 
03361     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
03362     {
03363         SetLastError(ERROR_INVALID_HANDLE);
03364         return FALSE;
03365     }
03366     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03367     {
03368         SetLastError(ERROR_INVALID_HANDLE);
03369         return FALSE;
03370     }
03371     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
03372             || !DeviceInfoData->Reserved)
03373     {
03374         SetLastError(ERROR_INVALID_PARAMETER);
03375         return FALSE;
03376     }
03377     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
03378     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
03379         && PropertyMap[Property].nameW)
03380     {
03381         DWORD size = PropertyBufferSize;
03382         HKEY hKey;
03383         LONG l;
03384         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
03385         if (hKey == INVALID_HANDLE_VALUE)
03386             return FALSE;
03387         l = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
03388                 NULL, PropertyRegDataType, PropertyBuffer, &size);
03389         RegCloseKey(hKey);
03390 
03391         if (RequiredSize)
03392             *RequiredSize = size;
03393         switch(l) {
03394             case ERROR_SUCCESS:
03395                 if (PropertyBuffer != NULL || size == 0)
03396                     ret = TRUE;
03397                 else
03398                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
03399                 break;
03400             case ERROR_MORE_DATA:
03401                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
03402                 break;
03403             default:
03404                 SetLastError(l);
03405         }
03406     }
03407     else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
03408     {
03409         DWORD required = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
03410 
03411         if (PropertyRegDataType)
03412             *PropertyRegDataType = REG_SZ;
03413         if (RequiredSize)
03414             *RequiredSize = required;
03415         if (PropertyBufferSize >= required)
03416         {
03417             strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
03418             ret = TRUE;
03419         }
03420         else
03421             SetLastError(ERROR_INSUFFICIENT_BUFFER);
03422     }
03423     else
03424     {
03425         ERR("Property 0x%lx not implemented\n", Property);
03426         SetLastError(ERROR_NOT_SUPPORTED);
03427     }
03428     return ret;
03429 }
03430 
03431 /***********************************************************************
03432  *      SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
03433  */
03434 BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
03435         HDEVINFO DeviceInfoSet,
03436         PSP_DEVINFO_DATA DeviceInfoData,
03437         DWORD Property,
03438         const BYTE *PropertyBuffer,
03439         DWORD PropertyBufferSize)
03440 {
03441     BOOL ret = FALSE;
03442     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
03443 
03444     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
03445         PropertyBuffer, PropertyBufferSize);
03446 
03447     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
03448     {
03449         SetLastError(ERROR_INVALID_HANDLE);
03450         return FALSE;
03451     }
03452     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03453     {
03454         SetLastError(ERROR_INVALID_HANDLE);
03455         return FALSE;
03456     }
03457     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
03458             || !DeviceInfoData->Reserved)
03459     {
03460         SetLastError(ERROR_INVALID_PARAMETER);
03461         return FALSE;
03462     }
03463 
03464     FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
03465         Property, PropertyBuffer, PropertyBufferSize);
03466     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
03467     return ret;
03468 }
03469 
03470 /***********************************************************************
03471  *      SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
03472  */
03473 BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
03474         HDEVINFO DeviceInfoSet,
03475         PSP_DEVINFO_DATA DeviceInfoData,
03476         DWORD Property,
03477         const BYTE *PropertyBuffer,
03478         DWORD PropertyBufferSize)
03479 {
03480     BOOL ret = FALSE;
03481     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
03482 
03483     TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
03484         PropertyBuffer, PropertyBufferSize);
03485 
03486     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
03487     {
03488         SetLastError(ERROR_INVALID_HANDLE);
03489         return FALSE;
03490     }
03491     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03492     {
03493         SetLastError(ERROR_INVALID_HANDLE);
03494         return FALSE;
03495     }
03496     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
03497             || !DeviceInfoData->Reserved)
03498     {
03499         SetLastError(ERROR_INVALID_PARAMETER);
03500         return FALSE;
03501     }
03502     if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
03503         && PropertyMap[Property].nameW)
03504     {
03505         HKEY hKey;
03506         LONG l;
03507         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
03508         if (hKey == INVALID_HANDLE_VALUE)
03509             return FALSE;
03510         /* Write new data */
03511         l = RegSetValueExW(
03512             hKey, PropertyMap[Property].nameW, 0,
03513                 PropertyMap[Property].regType, PropertyBuffer,
03514                 PropertyBufferSize);
03515         if (!l)
03516             ret = TRUE;
03517         else
03518             SetLastError(l);
03519         RegCloseKey(hKey);
03520     }
03521     else
03522     {
03523         ERR("Property 0x%lx not implemented\n", Property);
03524         SetLastError(ERROR_NOT_SUPPORTED);
03525     }
03526 
03527     TRACE("Returning %d\n", ret);
03528     return ret;
03529 }
03530 
03531 /***********************************************************************
03532  *      SetupDiInstallClassA (SETUPAPI.@)
03533  */
03534 BOOL WINAPI SetupDiInstallClassA(
03535         HWND hwndParent,
03536         PCSTR InfFileName,
03537         DWORD Flags,
03538         HSPFILEQ FileQueue)
03539 {
03540     return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
03541 }
03542 
03543 /***********************************************************************
03544  *      SetupDiInstallClassExA (SETUPAPI.@)
03545  */
03546 BOOL WINAPI
03547 SetupDiInstallClassExA(
03548     IN HWND hwndParent OPTIONAL,
03549     IN PCSTR InfFileName OPTIONAL,
03550     IN DWORD Flags,
03551     IN HSPFILEQ FileQueue OPTIONAL,
03552     IN CONST GUID *InterfaceClassGuid OPTIONAL,
03553     IN PVOID Reserved1,
03554     IN PVOID Reserved2)
03555 {
03556     PWSTR InfFileNameW = NULL;
03557     BOOL Result;
03558 
03559     if (!InfFileName)
03560     {
03561         SetLastError(ERROR_INVALID_PARAMETER);
03562         return FALSE;
03563     }
03564     else
03565     {
03566         InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
03567         if (InfFileNameW == NULL)
03568         {
03569             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03570             return FALSE;
03571         }
03572     }
03573 
03574     Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
03575         FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
03576 
03577     MyFree(InfFileNameW);
03578 
03579     return Result;
03580 }
03581 
03582 HKEY SETUP_CreateClassKey(HINF hInf)
03583 {
03584     static const WCHAR slash[] = { '\\',0 };
03585     WCHAR FullBuffer[MAX_PATH];
03586     WCHAR Buffer[MAX_PATH];
03587     DWORD RequiredSize;
03588     HKEY hClassKey;
03589 
03590     if (!SetupGetLineTextW(NULL,
03591                            hInf,
03592                            Version,
03593                            ClassGUID,
03594                            Buffer,
03595                            MAX_PATH,
03596                            &RequiredSize))
03597     {
03598         return INVALID_HANDLE_VALUE;
03599     }
03600 
03601     lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
03602     lstrcatW(FullBuffer, slash);
03603     lstrcatW(FullBuffer, Buffer);
03604 
03605     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
03606                       FullBuffer,
03607                       0,
03608                       KEY_SET_VALUE,
03609                       &hClassKey))
03610     {
03611         if (!SetupGetLineTextW(NULL,
03612                                hInf,
03613                                Version,
03614                                Class,
03615                                Buffer,
03616                                MAX_PATH,
03617                                &RequiredSize))
03618         {
03619             return INVALID_HANDLE_VALUE;
03620         }
03621 
03622         if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
03623                             FullBuffer,
03624                             0,
03625                             NULL,
03626                             REG_OPTION_NON_VOLATILE,
03627                             KEY_SET_VALUE,
03628                             NULL,
03629                             &hClassKey,
03630                             NULL))
03631         {
03632             return INVALID_HANDLE_VALUE;
03633         }
03634     }
03635 
03636     if (RegSetValueExW(hClassKey,
03637                        Class,
03638                        0,
03639                        REG_SZ,
03640                        (LPBYTE)Buffer,
03641                        RequiredSize * sizeof(WCHAR)))
03642     {
03643         RegCloseKey(hClassKey);
03644         RegDeleteKeyW(HKEY_LOCAL_MACHINE,
03645                       FullBuffer);
03646         return INVALID_HANDLE_VALUE;
03647     }
03648 
03649     return hClassKey;
03650 }
03651 
03652 /***********************************************************************
03653  *      SetupDiInstallClassW (SETUPAPI.@)
03654  */
03655 BOOL WINAPI SetupDiInstallClassW(
03656         HWND hwndParent,
03657         PCWSTR InfFileName,
03658         DWORD Flags,
03659         HSPFILEQ FileQueue)
03660 {
03661     return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
03662 }
03663 
03664 
03665 /***********************************************************************
03666  *      SetupDiOpenClassRegKey  (SETUPAPI.@)
03667  */
03668 HKEY WINAPI SetupDiOpenClassRegKey(
03669         const GUID* ClassGuid,
03670         REGSAM samDesired)
03671 {
03672     return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
03673                                      DIOCR_INSTALLER, NULL, NULL);
03674 }
03675 
03676 
03677 /***********************************************************************
03678  *      SetupDiOpenClassRegKeyExA  (SETUPAPI.@)
03679  */
03680 HKEY WINAPI SetupDiOpenClassRegKeyExA(
03681         const GUID* ClassGuid,
03682         REGSAM samDesired,
03683         DWORD Flags,
03684         PCSTR MachineName,
03685         PVOID Reserved)
03686 {
03687     PWSTR MachineNameW = NULL;
03688     HKEY hKey;
03689 
03690     TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
03691         Flags, debugstr_a(MachineName), Reserved);
03692 
03693     if (MachineName)
03694     {
03695         MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
03696         if (MachineNameW == NULL)
03697             return INVALID_HANDLE_VALUE;
03698     }
03699 
03700     hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
03701                                      Flags, MachineNameW, Reserved);
03702 
03703     MyFree(MachineNameW);
03704 
03705     return hKey;
03706 }
03707 
03708 
03709 /***********************************************************************
03710  *      SetupDiOpenClassRegKeyExW  (SETUPAPI.@)
03711  */
03712 HKEY WINAPI SetupDiOpenClassRegKeyExW(
03713         const GUID* ClassGuid,
03714         REGSAM samDesired,
03715         DWORD Flags,
03716         PCWSTR MachineName,
03717         PVOID Reserved)
03718 {
03719     HKEY HKLM;
03720     HKEY hClassesKey;
03721     HKEY key;
03722     LPCWSTR lpKeyName;
03723     LONG l;
03724 
03725     TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
03726         Flags, debugstr_w(MachineName), Reserved);
03727 
03728     if (MachineName != NULL)
03729     {
03730         l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
03731         if (l != ERROR_SUCCESS)
03732         {
03733             SetLastError(l);
03734             return INVALID_HANDLE_VALUE;
03735         }
03736     }
03737     else
03738         HKLM = HKEY_LOCAL_MACHINE;
03739 
03740     if (Flags == DIOCR_INSTALLER)
03741     {
03742         lpKeyName = REGSTR_PATH_CLASS_NT;
03743     }
03744     else if (Flags == DIOCR_INTERFACE)
03745     {
03746         lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
03747     }
03748     else
03749     {
03750         ERR("Invalid Flags parameter!\n");
03751         SetLastError(ERROR_INVALID_FLAGS);
03752         if (MachineName != NULL) RegCloseKey(HKLM);
03753         return INVALID_HANDLE_VALUE;
03754     }
03755 
03756     if (!ClassGuid)
03757     {
03758         if ((l = RegOpenKeyExW(HKLM,
03759                                lpKeyName,
03760                                0,
03761                                samDesired,
03762                                &hClassesKey)))
03763         {
03764             SetLastError(ERROR_INVALID_CLASS);
03765             hClassesKey = INVALID_HANDLE_VALUE;
03766         }
03767         if (MachineName != NULL)
03768             RegCloseKey(HKLM);
03769         key = hClassesKey;
03770     }
03771     else
03772     {
03773         WCHAR bracedGuidString[39];
03774 
03775         SETUPDI_GuidToString(ClassGuid, bracedGuidString);
03776 
03777         if (!(l = RegOpenKeyExW(HKLM,
03778                                 lpKeyName,
03779                                 0,
03780                                 samDesired,
03781                                 &hClassesKey)))
03782         {
03783             if (MachineName != NULL)
03784                 RegCloseKey(HKLM);
03785 
03786             if ((l = RegOpenKeyExW(hClassesKey,
03787                                    bracedGuidString,
03788                                    0,
03789                                    samDesired,
03790                                    &key)))
03791             {
03792                 SetLastError(l);
03793                 key = INVALID_HANDLE_VALUE;
03794             }
03795             RegCloseKey(hClassesKey);
03796         }
03797         else
03798         {
03799             if (MachineName != NULL) RegCloseKey(HKLM);
03800             SetLastError(l);
03801             key = INVALID_HANDLE_VALUE;
03802         }
03803     }
03804 
03805     return key;
03806 }
03807 
03808 /***********************************************************************
03809  *      SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
03810  */
03811 BOOL WINAPI SetupDiOpenDeviceInterfaceW(
03812         HDEVINFO DeviceInfoSet,
03813         PCWSTR DevicePath,
03814         DWORD OpenFlags,
03815         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
03816 {
03817     struct DeviceInfoSet * list;
03818     PCWSTR pEnd;
03819     DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
03820     CLSID ClassId;
03821     WCHAR Buffer[MAX_PATH + 1];
03822     WCHAR SymBuffer[MAX_PATH + 1];
03823     WCHAR InstancePath[MAX_PATH + 1];
03824     HKEY hKey, hDevKey, hSymKey;
03825     struct DeviceInfo * deviceInfo;
03826     struct DeviceInterface *deviceInterface;
03827     BOOL Ret;
03828     PLIST_ENTRY ItemList;
03829     PLIST_ENTRY InterfaceListEntry;
03830 
03831     TRACE("%p %s %08x %p\n",
03832         DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
03833 
03834 
03835     if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
03836     {
03837         SetLastError(ERROR_INVALID_PARAMETER);
03838         return FALSE;
03839     }
03840 
03841     if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
03842     {
03843         SetLastError(ERROR_INVALID_HANDLE);
03844         return FALSE;
03845     }
03846 
03847     list = (struct DeviceInfoSet * )DeviceInfoSet;
03848 
03849     dwLength = wcslen(DevicePath);
03850     if (dwLength < 39)
03851     {
03852         /* path must be at least a guid length + L'\0' */
03853         SetLastError(ERROR_BAD_PATHNAME);
03854         return FALSE;
03855     }
03856 
03857     if (DevicePath[0] != L'\\' ||
03858         DevicePath[1] != L'\\' ||
03859         (DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
03860         DevicePath[3] != L'\\')
03861     {
03862         /* invalid formatted path */
03863         SetLastError(ERROR_BAD_PATHNAME);
03864         return FALSE;
03865     }
03866 
03867     /* check for reference strings */
03868     pEnd = wcschr(&DevicePath[4], L'\\');
03869     if (!pEnd)
03870     {
03871         /* no reference string */
03872         pEnd = DevicePath + dwLength;
03873     }
03874 
03875     /* copy guid */
03876     wcscpy(Buffer, pEnd - 37);
03877     Buffer[36] = L'\0';
03878 
03879     dwError = UuidFromStringW(Buffer, &ClassId);
03880     if (dwError != NOERROR)
03881     {
03882         /* invalid formatted path */
03883         SetLastError(ERROR_BAD_PATHNAME);
03884         return FALSE;
03885     }
03886 
03887     hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
03888 
03889     if (hKey == INVALID_HANDLE_VALUE)
03890     {
03891         /* invalid device class */
03892         return FALSE;
03893     }
03894 
03895     ItemList = list->ListHead.Flink;
03896     while (ItemList != &list->ListHead)
03897     {
03898         deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
03899         InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
03900         while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
03901         {
03902             deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
03903             if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
03904             {
03905                 InterfaceListEntry = InterfaceListEntry->Flink;
03906                 continue;
03907             }
03908 
03909             if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
03910             {
03911                 if (DeviceInterfaceData)
03912                 {
03913                     DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
03914                     DeviceInterfaceData->Flags = deviceInterface->Flags;
03915                     CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
03916                 }
03917 
03918                 return TRUE;
03919             }
03920 
03921         }
03922     }
03923 
03924 
03925     dwIndex = 0;
03926     do
03927     {
03928         Buffer[0] = 0;
03929         dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
03930         dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
03931 
03932         if (dwError != ERROR_SUCCESS)
03933             break;
03934 
03935         if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
03936             break;
03937 
03938         dwSubIndex = 0;
03939         InstancePath[0] = 0;
03940         dwKeyName = sizeof(InstancePath);
03941 
03942         dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
03943 
03944         while(TRUE)
03945         {
03946             Buffer[0] = 0;
03947             dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
03948             dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
03949 
03950             if (dwError != ERROR_SUCCESS)
03951                 break;
03952 
03953             dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
03954             if (dwError != ERROR_SUCCESS)
03955                 break;
03956 
03957             /* query for symbolic link */
03958             dwKeyName = sizeof(SymBuffer);
03959             SymBuffer[0] = L'\0';
03960             dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
03961 
03962             if (dwError != ERROR_SUCCESS)
03963             {
03964                 RegCloseKey(hSymKey);
03965                 break;
03966             }
03967 
03968             if (!wcsicmp(SymBuffer, DevicePath))
03969             {
03970                 Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
03971                 RegCloseKey(hSymKey);
03972                 RegCloseKey(hDevKey);
03973                 RegCloseKey(hKey);
03974 
03975                 if (Ret)
03976                 {
03977                     deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
03978                     if (deviceInterface)
03979                     {
03980 
03981                         CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
03982                         deviceInterface->DeviceInfo = deviceInfo;
03983                         deviceInterface->Flags = SPINT_ACTIVE; //FIXME
03984 
03985                         wcscpy(deviceInterface->SymbolicLink, SymBuffer);
03986 
03987                         InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
03988                         InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
03989 
03990 
03991                         if (DeviceInterfaceData)
03992                         {
03993                             DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
03994                             DeviceInterfaceData->Flags = deviceInterface->Flags;
03995                             CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
03996                         }
03997                         else
03998                         {
03999                             Ret = FALSE;
04000                             SetLastError(ERROR_INVALID_USER_BUFFER);
04001                         }
04002                     }
04003                 }
04004                 else
04005                 {
04006                     HeapFree(GetProcessHeap(), 0, deviceInfo);
04007                     Ret = FALSE;
04008                 }
04009                 return Ret;
04010         }
04011         RegCloseKey(hSymKey);
04012         dwSubIndex++;
04013     }
04014 
04015     RegCloseKey(hDevKey);
04016     dwIndex++;
04017     } while(TRUE);
04018 
04019     RegCloseKey(hKey);
04020     return FALSE;
04021 }
04022 
04023 /***********************************************************************
04024  *      SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
04025  */
04026 BOOL WINAPI SetupDiOpenDeviceInterfaceA(
04027         HDEVINFO DeviceInfoSet,
04028         PCSTR DevicePath,
04029         DWORD OpenFlags,
04030         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
04031 {
04032     LPWSTR DevicePathW = NULL;
04033     BOOL bResult;
04034 
04035     TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
04036 
04037     DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
04038     if (DevicePathW == NULL)
04039         return FALSE;
04040 
04041     bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
04042         DevicePathW, OpenFlags, DeviceInterfaceData);
04043 
04044     MyFree(DevicePathW);
04045 
04046     return bResult;
04047 }
04048 
04049 /***********************************************************************
04050  *      SetupDiSetClassInstallParamsA (SETUPAPI.@)
04051  */
04052 BOOL WINAPI SetupDiSetClassInstallParamsA(
04053         HDEVINFO  DeviceInfoSet,
04054         PSP_DEVINFO_DATA DeviceInfoData,
04055         PSP_CLASSINSTALL_HEADER ClassInstallParams,
04056         DWORD ClassInstallParamsSize)
04057 {
04058     FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
04059           ClassInstallParams->InstallFunction, ClassInstallParamsSize);
04060     return FALSE;
04061 }
04062 
04063 static BOOL WINAPI
04064 IntSetupDiRegisterDeviceInfo(
04065         IN HDEVINFO DeviceInfoSet,
04066         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
04067 {
04068     return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
04069 }
04070 
04071 /***********************************************************************
04072  *      SetupDiCallClassInstaller (SETUPAPI.@)
04073  */
04074 BOOL WINAPI SetupDiCallClassInstaller(
04075         DI_FUNCTION InstallFunction,
04076         HDEVINFO DeviceInfoSet,
04077         PSP_DEVINFO_DATA DeviceInfoData)
04078 {
04079     BOOL ret = FALSE;
04080 
04081     TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
04082 
04083     if (!DeviceInfoSet)
04084         SetLastError(ERROR_INVALID_PARAMETER);
04085     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
04086         SetLastError(ERROR_INVALID_HANDLE);
04087     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04088         SetLastError(ERROR_INVALID_HANDLE);
04089     else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
04090         SetLastError(ERROR_INVALID_HANDLE);
04091     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04092         SetLastError(ERROR_INVALID_USER_BUFFER);
04093     else
04094     {
04095         SP_DEVINSTALL_PARAMS_W InstallParams;
04096 #define CLASS_COINSTALLER  0x1
04097 #define DEVICE_COINSTALLER 0x2
04098 #define CLASS_INSTALLER    0x4
04099         UCHAR CanHandle = 0;
04100         DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
04101 
04102         switch (InstallFunction)
04103         {
04104             case DIF_ADDPROPERTYPAGE_ADVANCED:
04105                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04106                 break;
04107             case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
04108                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04109                 break;
04110             case DIF_ALLOW_INSTALL:
04111                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04112                 break;
04113             case DIF_DETECT:
04114                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04115                 break;
04116             case DIF_DESTROYPRIVATEDATA:
04117                 CanHandle = CLASS_INSTALLER;
04118                 break;
04119             case DIF_INSTALLDEVICE:
04120                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04121                 DefaultHandler = SetupDiInstallDevice;
04122                 break;
04123             case DIF_INSTALLDEVICEFILES:
04124                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04125                 DefaultHandler = SetupDiInstallDriverFiles;
04126                 break;
04127             case DIF_INSTALLINTERFACES:
04128                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04129                 DefaultHandler = SetupDiInstallDeviceInterfaces;
04130                 break;
04131             case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
04132                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04133                 break;
04134             case DIF_NEWDEVICEWIZARD_POSTANALYZE:
04135                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04136                 break;
04137             case DIF_NEWDEVICEWIZARD_PREANALYZE:
04138                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04139                 break;
04140             case DIF_NEWDEVICEWIZARD_PRESELECT:
04141                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04142                 break;
04143             case DIF_NEWDEVICEWIZARD_SELECT:
04144                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04145                 break;
04146             case DIF_POWERMESSAGEWAKE:
04147                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04148                 break;
04149             case DIF_PROPERTYCHANGE:
04150                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04151                 DefaultHandler = SetupDiChangeState;
04152                 break;
04153             case DIF_REGISTER_COINSTALLERS:
04154                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04155                 DefaultHandler = SetupDiRegisterCoDeviceInstallers;
04156                 break;
04157             case DIF_REGISTERDEVICE:
04158                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04159                 DefaultHandler = IntSetupDiRegisterDeviceInfo;
04160                 break;
04161             case DIF_REMOVE:
04162                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04163                 DefaultHandler = SetupDiRemoveDevice;
04164                 break;
04165             case DIF_SELECTBESTCOMPATDRV:
04166                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04167                 DefaultHandler = SetupDiSelectBestCompatDrv;
04168                 break;
04169             case DIF_SELECTDEVICE:
04170                 CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
04171                 DefaultHandler = SetupDiSelectDevice;
04172                 break;
04173             case DIF_TROUBLESHOOTER:
04174                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04175                 break;
04176             case DIF_UNREMOVE:
04177                 CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
04178                 DefaultHandler = SetupDiUnremoveDevice;
04179                 break;
04180             default:
04181                 ERR("Install function %u not supported\n", InstallFunction);
04182                 SetLastError(ERROR_NOT_SUPPORTED);
04183         }
04184 
04185         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
04186         if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
04187             /* Don't process this call, as a parameter is invalid */
04188             CanHandle = 0;
04189 
04190         if (CanHandle != 0)
04191         {
04192             LIST_ENTRY ClassCoInstallersListHead;
04193             LIST_ENTRY DeviceCoInstallersListHead;
04194             HMODULE ClassInstallerLibrary = NULL;
04195             CLASS_INSTALL_PROC ClassInstaller = NULL;
04196             COINSTALLER_CONTEXT_DATA Context;
04197             PLIST_ENTRY ListEntry;
04198             HKEY hKey;
04199             DWORD dwRegType, dwLength;
04200             DWORD rc = NO_ERROR;
04201 
04202             InitializeListHead(&ClassCoInstallersListHead);
04203             InitializeListHead(&DeviceCoInstallersListHead);
04204 
04205             if (CanHandle & DEVICE_COINSTALLER)
04206             {
04207                 hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
04208                 if (hKey != INVALID_HANDLE_VALUE)
04209                 {
04210                     rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
04211                     if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
04212                     {
04213                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
04214                         if (KeyBuffer != NULL)
04215                         {
04216                             rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
04217                             if (rc == ERROR_SUCCESS)
04218                             {
04219                                 LPWSTR ptr;
04220                                 for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
04221                                 {
04222                                     /* Add coinstaller to DeviceCoInstallersListHead list */
04223                                     struct CoInstallerElement *coinstaller;
04224                                     TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
04225                                     coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
04226                                     if (!coinstaller)
04227                                         continue;
04228                                     ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
04229                                     if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
04230                                         InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
04231                                     else
04232                                         HeapFree(GetProcessHeap(), 0, coinstaller);
04233                                 }
04234                             }
04235                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
04236                         }
04237                     }
04238                     RegCloseKey(hKey);
04239                 }
04240             }
04241             if (CanHandle & CLASS_COINSTALLER)
04242             {
04243                 rc = RegOpenKeyExW(
04244                     HKEY_LOCAL_MACHINE,
04245                     REGSTR_PATH_CODEVICEINSTALLERS,
04246                     0, /* Options */
04247                     KEY_QUERY_VALUE,
04248                     &hKey);
04249                 if (rc == ERROR_SUCCESS)
04250                 {
04251                     LPWSTR lpGuidString;
04252                     if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
04253                     {
04254                         rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
04255                         if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
04256                         {
04257                             LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
04258                             if (KeyBuffer != NULL)
04259                             {
04260                                 rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
04261                                 if (rc == ERROR_SUCCESS)
04262                                 {
04263                                     LPWSTR ptr;
04264                                     for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
04265                                     {
04266                                         /* Add coinstaller to ClassCoInstallersListHead list */
04267                                         struct CoInstallerElement *coinstaller;
04268                                         TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
04269                                         coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
04270                                         if (!coinstaller)
04271                                             continue;
04272                                         ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
04273                                         if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
04274                                             InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
04275                                         else
04276                                             HeapFree(GetProcessHeap(), 0, coinstaller);
04277                                     }
04278                                 }
04279                                 HeapFree(GetProcessHeap(), 0, KeyBuffer);
04280                             }
04281                         }
04282                         RpcStringFreeW(&lpGuidString);
04283                     }
04284                     RegCloseKey(hKey);
04285                 }
04286             }
04287             if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
04288             {
04289                 hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
04290                 if (hKey != INVALID_HANDLE_VALUE)
04291                 {
04292                     rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
04293                     if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
04294                     {
04295                         LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
04296                         if (KeyBuffer != NULL)
04297                         {
04298                             rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
04299                             if (rc == ERROR_SUCCESS)
04300                             {
04301                                 /* Get ClassInstaller function pointer */
04302                                 TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
04303                                 if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
04304                                 {
04305                                     InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
04306                                     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
04307                                 }
04308                             }
04309                             HeapFree(GetProcessHeap(), 0, KeyBuffer);
04310                         }
04311                     }
04312                     RegCloseKey(hKey);
04313                 }
04314             }
04315 
04316             /* Call Class co-installers */
04317             Context.PostProcessing = FALSE;
04318             rc = NO_ERROR;
04319             ListEntry = ClassCoInstallersListHead.Flink;
04320             while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
04321             {
04322                 struct CoInstallerElement *coinstaller;
04323                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
04324                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
04325                 coinstaller->PrivateData = Context.PrivateData;
04326                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
04327                 {
04328                     coinstaller->DoPostProcessing = TRUE;
04329                     rc = NO_ERROR;
04330                 }
04331                 ListEntry = ListEntry->Flink;
04332             }
04333 
04334             /* Call Device co-installers */
04335             ListEntry = DeviceCoInstallersListHead.Flink;
04336             while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
04337             {
04338                 struct CoInstallerElement *coinstaller;
04339                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
04340                 rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
04341                 coinstaller->PrivateData = Context.PrivateData;
04342                 if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
04343                 {
04344                     coinstaller->DoPostProcessing = TRUE;
04345                     rc = NO_ERROR;
04346                 }
04347                 ListEntry = ListEntry->Flink;
04348             }
04349 
04350             /* Call Class installer */
04351             if (ClassInstaller)
04352             {
04353                 rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
04354                 FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
04355             }
04356             else
04357                 rc = ERROR_DI_DO_DEFAULT;
04358 
04359             /* Call default handler */
04360             if (rc == ERROR_DI_DO_DEFAULT)
04361             {
04362                 if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
04363                 {
04364                     if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
04365                         rc = NO_ERROR;
04366                     else
04367                         rc = GetLastError();
04368                 }
04369                 else
04370                     rc = NO_ERROR;
04371             }
04372 
04373             /* Call Class co-installers that required postprocessing */
04374             Context.PostProcessing = TRUE;
04375             ListEntry = ClassCoInstallersListHead.Flink;
04376             while (ListEntry != &ClassCoInstallersListHead)
04377             {
04378                 struct CoInstallerElement *coinstaller;
04379                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
04380                 if (coinstaller->DoPostProcessing)
04381                 {
04382                     Context.InstallResult = rc;
04383                     Context.PrivateData = coinstaller->PrivateData;
04384                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
04385                 }
04386                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
04387                 ListEntry = ListEntry->Flink;
04388             }
04389 
04390             /* Call Device co-installers that required postprocessing */
04391             ListEntry = DeviceCoInstallersListHead.Flink;
04392             while (ListEntry != &DeviceCoInstallersListHead)
04393             {
04394                 struct CoInstallerElement *coinstaller;
04395                 coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
04396                 if (coinstaller->DoPostProcessing)
04397                 {
04398                     Context.InstallResult = rc;
04399                     Context.PrivateData = coinstaller->PrivateData;
04400                     rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
04401                 }
04402                 FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
04403                 ListEntry = ListEntry->Flink;
04404             }
04405 
04406             /* Free allocated memory */
04407             while (!IsListEmpty(&ClassCoInstallersListHead))
04408             {
04409                 ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
04410                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
04411             }
04412             while (!IsListEmpty(&DeviceCoInstallersListHead))
04413             {
04414                 ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
04415                 HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
04416             }
04417 
04418             ret = (rc == NO_ERROR);
04419         }
04420     }
04421 
04422     TRACE("Returning %d\n", ret);
04423     return ret;
04424 }
04425 
04426 /***********************************************************************
04427  *      SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
04428  */
04429 BOOL WINAPI SetupDiGetDeviceInstallParamsA(
04430         HDEVINFO DeviceInfoSet,
04431         PSP_DEVINFO_DATA DeviceInfoData,
04432         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
04433 {
04434     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
04435     BOOL ret = FALSE;
04436 
04437     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
04438 
04439     if (DeviceInstallParams == NULL)
04440         SetLastError(ERROR_INVALID_PARAMETER);
04441     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
04442         SetLastError(ERROR_INVALID_USER_BUFFER);
04443     else
04444     {
04445         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
04446         ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
04447 
04448         if (ret)
04449         {
04450             /* Do W->A conversion */
04451             memcpy(
04452                 DeviceInstallParams,
04453                 &deviceInstallParamsW,
04454                 FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
04455             if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
04456                 DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
04457             {
04458                 DeviceInstallParams->DriverPath[0] = '\0';
04459                 ret = FALSE;
04460             }
04461         }
04462     }
04463 
04464     TRACE("Returning %d\n", ret);
04465     return ret;
04466 }
04467 
04468 /***********************************************************************
04469  *      SetupDiGetDeviceInfoListClass  (SETUPAPI.@)
04470  */
04471 BOOL WINAPI
04472 SetupDiGetDeviceInfoListClass(
04473         IN HDEVINFO DeviceInfoSet,
04474         OUT LPGUID ClassGuid)
04475 {
04476     struct DeviceInfoSet *list;
04477     BOOL ret = FALSE;
04478 
04479     TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
04480 
04481     if (!DeviceInfoSet)
04482         SetLastError(ERROR_INVALID_HANDLE);
04483     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04484         SetLastError(ERROR_INVALID_HANDLE);
04485     else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
04486         SetLastError(ERROR_NO_ASSOCIATED_CLASS);
04487     else
04488     {
04489         memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
04490 
04491         ret = TRUE;
04492     }
04493 
04494     TRACE("Returning %d\n", ret);
04495     return ret;
04496 }
04497 
04498 /***********************************************************************
04499  *      SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
04500  */
04501 BOOL WINAPI
04502 SetupDiGetDeviceInstallParamsW(
04503         IN HDEVINFO DeviceInfoSet,
04504         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
04505         OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
04506 {
04507     struct DeviceInfoSet *list;
04508     BOOL ret = FALSE;
04509 
04510     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
04511 
04512     if (!DeviceInfoSet)
04513         SetLastError(ERROR_INVALID_HANDLE);
04514     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04515         SetLastError(ERROR_INVALID_HANDLE);
04516     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04517         SetLastError(ERROR_INVALID_USER_BUFFER);
04518     else if (!DeviceInstallParams)
04519         SetLastError(ERROR_INVALID_PARAMETER);
04520     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
04521         SetLastError(ERROR_INVALID_USER_BUFFER);
04522     else
04523     {
04524         PSP_DEVINSTALL_PARAMS_W Source;
04525 
04526         if (DeviceInfoData)
04527             Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
04528         else
04529             Source = &list->InstallParams;
04530 
04531         ret = TRUE;
04532 
04533         _SEH2_TRY
04534         {
04535             memcpy(DeviceInstallParams, Source, Source->cbSize);
04536         }
04537         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
04538         {
04539             SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
04540             ret = FALSE;
04541         }
04542         _SEH2_END;
04543     }
04544 
04545     TRACE("Returning %d\n", ret);
04546     return ret;
04547 }
04548 
04549 static BOOL
04550 CheckDeviceInstallParameters(
04551         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
04552 {
04553     DWORD SupportedFlags =
04554         DI_NOVCP |                            /* 0x00000008 */
04555         DI_DIDCOMPAT |                        /* 0x00000010 */
04556         DI_DIDCLASS |                         /* 0x00000020 */
04557         DI_NEEDRESTART |                      /* 0x00000080 */
04558         DI_NEEDREBOOT |                       /* 0x00000100 */
04559         DI_RESOURCEPAGE_ADDED |               /* 0x00002000 */
04560         DI_PROPERTIES_CHANGE |                /* 0x00004000 */
04561         DI_ENUMSINGLEINF |                    /* 0x00010000 */
04562         DI_DONOTCALLCONFIGMG |                /* 0x00020000 */
04563         DI_CLASSINSTALLPARAMS |               /* 0x00100000 */
04564         DI_NODI_DEFAULTACTION |               /* 0x00200000 */
04565         DI_QUIETINSTALL |                     /* 0x00800000 */
04566         DI_NOFILECOPY |                       /* 0x01000000 */
04567         DI_DRIVERPAGE_ADDED;                  /* 0x04000000 */
04568     DWORD SupportedFlagsEx =
04569         DI_FLAGSEX_CI_FAILED |                /* 0x00000004 */
04570         DI_FLAGSEX_DIDINFOLIST |              /* 0x00000010 */
04571         DI_FLAGSEX_DIDCOMPATINFO |            /* 0x00000020 */
04572         DI_FLAGSEX_ALLOWEXCLUDEDDRVS |        /* 0x00000800 */
04573         DI_FLAGSEX_NO_DRVREG_MODIFY |         /* 0x00008000 */
04574         DI_FLAGSEX_INSTALLEDDRIVER;           /* 0x04000000 */
04575     BOOL ret = FALSE;
04576 
04577     /* FIXME: add support for more flags */
04578 
04579     /* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
04580      * It should be checked before accessing to other values
04581      * of the SP_DEVINSTALL_PARAMS structure */
04582 
04583     if (DeviceInstallParams->Flags & ~SupportedFlags)
04584     {
04585         FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
04586         SetLastError(ERROR_INVALID_FLAGS);
04587     }
04588     else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
04589     {
04590         FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
04591         SetLastError(ERROR_INVALID_FLAGS);
04592     }
04593     else if ((DeviceInstallParams->Flags & DI_NOVCP)
04594         && (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
04595         SetLastError(ERROR_INVALID_USER_BUFFER);
04596     else
04597     {
04598         /* FIXME: check Reserved field */
04599         ret = TRUE;
04600     }
04601 
04602     return ret;
04603 }
04604 
04605 /***********************************************************************
04606  *      SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
04607  */
04608 BOOL WINAPI
04609 SetupDiSetDeviceInstallParamsW(
04610         IN HDEVINFO DeviceInfoSet,
04611         IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
04612         IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
04613 {
04614     struct DeviceInfoSet *list;
04615     BOOL ret = FALSE;
04616 
04617     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
04618 
04619     if (!DeviceInfoSet)
04620         SetLastError(ERROR_INVALID_HANDLE);
04621     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04622         SetLastError(ERROR_INVALID_HANDLE);
04623     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04624         SetLastError(ERROR_INVALID_USER_BUFFER);
04625     else if (!DeviceInstallParams)
04626         SetLastError(ERROR_INVALID_PARAMETER);
04627     else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
04628         SetLastError(ERROR_INVALID_USER_BUFFER);
04629     else if (CheckDeviceInstallParameters(DeviceInstallParams))
04630     {
04631         PSP_DEVINSTALL_PARAMS_W Destination;
04632 
04633         if (DeviceInfoData)
04634             Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
04635         else
04636             Destination = &list->InstallParams;
04637         memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
04638         ret = TRUE;
04639     }
04640 
04641     TRACE("Returning %d\n", ret);
04642     return ret;
04643 }
04644 
04645 /***********************************************************************
04646  *      SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
04647  */
04648 BOOL WINAPI
04649 SetupDiSetDeviceInstallParamsA(
04650         HDEVINFO DeviceInfoSet,
04651         PSP_DEVINFO_DATA DeviceInfoData,
04652         PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
04653 {
04654     SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
04655     int len = 0;
04656     BOOL ret = FALSE;
04657 
04658     TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
04659 
04660     if (DeviceInstallParams == NULL)
04661         SetLastError(ERROR_INVALID_PARAMETER);
04662     else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
04663         SetLastError(ERROR_INVALID_USER_BUFFER);
04664     else
04665     {
04666         memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
04667         deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
04668         len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
04669         if (!len)
04670         {
04671             ERR("DrivePath is NULL\n");
04672             ret = FALSE;
04673         }
04674         else
04675         {
04676             MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
04677             ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
04678         }
04679     }
04680 
04681     TRACE("Returning %d\n", ret);
04682     return ret;
04683 }
04684 
04685 static HKEY
04686 OpenHardwareProfileKey(
04687         IN HKEY HKLM,
04688         IN DWORD HwProfile,
04689         IN DWORD samDesired)
04690 {
04691     HKEY hHWProfilesKey = NULL;
04692     HKEY hHWProfileKey = NULL;
04693     HKEY ret = INVALID_HANDLE_VALUE;
04694     LONG rc;
04695 
04696     rc = RegOpenKeyExW(HKLM,
04697                        REGSTR_PATH_HWPROFILES,
04698                        0,
04699                        0,
04700                        &hHWProfilesKey);
04701     if (rc != ERROR_SUCCESS)
04702     {
04703         SetLastError(rc);
04704         goto cleanup;
04705     }
04706     if (HwProfile == 0)
04707     {
04708         rc = RegOpenKeyExW(hHWProfilesKey,
04709                            REGSTR_KEY_CURRENT,
04710                            0,
04711                            KEY_CREATE_SUB_KEY,
04712                            &hHWProfileKey);
04713     }
04714     else
04715     {
04716         WCHAR subKey[5];
04717         snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
04718         subKey[4] = '\0';
04719         rc = RegOpenKeyExW(hHWProfilesKey,
04720                            subKey,
04721                            0,
04722                            KEY_CREATE_SUB_KEY,
04723                            &hHWProfileKey);
04724     }
04725     if (rc != ERROR_SUCCESS)
04726     {
04727         SetLastError(rc);
04728         goto cleanup;
04729     }
04730     ret = hHWProfileKey;
04731 
04732 cleanup:
04733     if (hHWProfilesKey != NULL)
04734         RegCloseKey(hHWProfilesKey);
04735     if (hHWProfileKey != NULL && hHWProfileKey != ret)
04736         RegCloseKey(hHWProfileKey);
04737     return ret;
04738 }
04739 
04740 static BOOL
04741 IsDeviceInfoInDeviceInfoSet(
04742         struct DeviceInfoSet *deviceInfoSet,
04743         struct DeviceInfo *deviceInfo)
04744 {
04745     PLIST_ENTRY ListEntry;
04746 
04747     ListEntry = deviceInfoSet->ListHead.Flink;
04748     while (ListEntry != &deviceInfoSet->ListHead)
04749     {
04750         if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
04751             return TRUE;
04752 
04753         ListEntry = ListEntry->Flink;
04754     }
04755 
04756     return FALSE;
04757 }
04758 
04759 /***********************************************************************
04760  *      SetupDiDeleteDeviceInfo (SETUPAPI.@)
04761  */
04762 BOOL WINAPI
04763 SetupDiDeleteDeviceInfo(
04764         IN HDEVINFO DeviceInfoSet,
04765         IN PSP_DEVINFO_DATA DeviceInfoData)
04766 {
04767     struct DeviceInfoSet *deviceInfoSet;
04768     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
04769     BOOL ret = FALSE;
04770 
04771     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
04772 
04773     if (!DeviceInfoSet)
04774         SetLastError(ERROR_INVALID_HANDLE);
04775     else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04776         SetLastError(ERROR_INVALID_HANDLE);
04777     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04778         SetLastError(ERROR_INVALID_USER_BUFFER);
04779     else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
04780         SetLastError(ERROR_INVALID_PARAMETER);
04781     else
04782     {
04783         RemoveEntryList(&deviceInfo->ListEntry);
04784         DestroyDeviceInfo(deviceInfo);
04785         ret = TRUE;
04786     }
04787 
04788     return ret;
04789 }
04790 
04791 
04792 /***********************************************************************
04793  *      SetupDiOpenDeviceInfoA (SETUPAPI.@)
04794  */
04795 BOOL WINAPI
04796 SetupDiOpenDeviceInfoA(
04797         IN HDEVINFO DeviceInfoSet,
04798         IN PCSTR DeviceInstanceId,
04799         IN HWND hwndParent OPTIONAL,
04800         IN DWORD OpenFlags,
04801         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
04802 {
04803     LPWSTR DeviceInstanceIdW = NULL;
04804     BOOL bResult;
04805 
04806     TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
04807 
04808     DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
04809     if (DeviceInstanceIdW == NULL)
04810         return FALSE;
04811 
04812     bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
04813         DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
04814 
04815     MyFree(DeviceInstanceIdW);
04816 
04817     return bResult;
04818 }
04819 
04820 
04821 /***********************************************************************
04822  *      SetupDiOpenDeviceInfoW (SETUPAPI.@)
04823  */
04824 BOOL WINAPI
04825 SetupDiOpenDeviceInfoW(
04826         IN HDEVINFO DeviceInfoSet,
04827         IN PCWSTR DeviceInstanceId,
04828         IN HWND hwndParent OPTIONAL,
04829         IN DWORD OpenFlags,
04830         OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
04831 {
04832     struct DeviceInfoSet *list;
04833     HKEY hEnumKey, hKey = NULL;
04834     DWORD rc, dwSize;
04835     BOOL ret = FALSE;
04836 
04837     TRACE("%p %s %p %lx %p\n",
04838         DeviceInfoSet, debugstr_w(DeviceInstanceId),
04839         hwndParent, OpenFlags, DeviceInfoData);
04840 
04841     if (OpenFlags & DIOD_CANCEL_REMOVE)
04842         FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
04843 
04844     if (!DeviceInfoSet)
04845         SetLastError(ERROR_INVALID_HANDLE);
04846     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04847         SetLastError(ERROR_INVALID_HANDLE);
04848     else if (!DeviceInstanceId)
04849         SetLastError(ERROR_INVALID_PARAMETER);
04850     else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
04851     {
04852         TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
04853         SetLastError(ERROR_INVALID_FLAGS);
04854     }
04855     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04856         SetLastError(ERROR_INVALID_USER_BUFFER);
04857     else
04858     {
04859         struct DeviceInfo *deviceInfo = NULL;
04860         /* Search if device already exists in DeviceInfoSet.
04861          *    If yes, return the existing element
04862          *    If no, create a new element using information in registry
04863          */
04864         PLIST_ENTRY ItemList = list->ListHead.Flink;
04865         while (ItemList != &list->ListHead)
04866         {
04867             deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
04868             if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
04869                 break;
04870             deviceInfo = NULL;
04871             ItemList = ItemList->Flink;
04872         }
04873 
04874         if (deviceInfo)
04875         {
04876             /* good one found */
04877             ret = TRUE;
04878         }
04879         else
04880         {
04881             GUID ClassGUID;
04882             WCHAR szClassGuid[MAX_GUID_STRING_LEN];
04883 
04884             /* Open supposed registry key */
04885             rc = RegOpenKeyExW(
04886                 list->HKLM,
04887                 REGSTR_PATH_SYSTEMENUM,
04888                 0, /* Options */
04889                 0,
04890                 &hEnumKey);
04891             if (rc != ERROR_SUCCESS)
04892             {
04893                 SetLastError(rc);
04894                 goto cleanup;
04895             }
04896             rc = RegOpenKeyExW(
04897                 hEnumKey,
04898                 DeviceInstanceId,
04899                 0, /* Options */
04900                 KEY_QUERY_VALUE,
04901                 &hKey);
04902             RegCloseKey(hEnumKey);
04903             if (rc != ERROR_SUCCESS)
04904             {
04905                 if (rc == ERROR_FILE_NOT_FOUND)
04906                     rc = ERROR_NO_SUCH_DEVINST;
04907                 SetLastError(rc);
04908                 goto cleanup;
04909             }
04910 
04911             ClassGUID = GUID_NULL;
04912             dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
04913 
04914             if (RegQueryValueExW(hKey,
04915                                  REGSTR_VAL_CLASSGUID,
04916                                  NULL,
04917                                  NULL,
04918                                  (LPBYTE)szClassGuid,
04919                                  &dwSize) == ERROR_SUCCESS)
04920             {
04921                 szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
04922 
04923                 /* Convert a string to a ClassGuid */
04924                 UuidFromStringW(&szClassGuid[1], &ClassGUID);
04925             }
04926 
04927             if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
04928                 goto cleanup;
04929 
04930             InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
04931 
04932             ret = TRUE;
04933         }
04934 
04935         if (ret && deviceInfo && DeviceInfoData)
04936         {
04937             memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
04938             DeviceInfoData->DevInst = deviceInfo->dnDevInst;
04939             DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
04940         }
04941     }
04942 
04943 cleanup:
04944     if (hKey != NULL)
04945         RegCloseKey(hKey);
04946     return ret;
04947 }
04948 
04949 
04950 /***********************************************************************
04951  *      SetupDiGetSelectedDevice (SETUPAPI.@)
04952  */
04953 BOOL WINAPI
04954 SetupDiGetSelectedDevice(
04955         IN HDEVINFO DeviceInfoSet,
04956         OUT PSP_DEVINFO_DATA DeviceInfoData)
04957 {
04958     struct DeviceInfoSet *list;
04959     BOOL ret = FALSE;
04960 
04961     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
04962 
04963     if (!DeviceInfoSet)
04964         SetLastError(ERROR_INVALID_HANDLE);
04965     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
04966         SetLastError(ERROR_INVALID_HANDLE);
04967     else if (list->SelectedDevice == NULL)
04968         SetLastError(ERROR_NO_DEVICE_SELECTED);
04969     else if (!DeviceInfoData)
04970         SetLastError(ERROR_INVALID_PARAMETER);
04971     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
04972         SetLastError(ERROR_INVALID_USER_BUFFER);
04973     else
04974     {
04975         memcpy(&DeviceInfoData->ClassGuid,
04976             &list->SelectedDevice->ClassGuid,
04977             sizeof(GUID));
04978         DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
04979         DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
04980         ret = TRUE;
04981     }
04982 
04983     TRACE("Returning %d\n", ret);
04984     return ret;
04985 }
04986 
04987 
04988 /***********************************************************************
04989  *      SetupDiSetSelectedDevice (SETUPAPI.@)
04990  */
04991 BOOL WINAPI
04992 SetupDiSetSelectedDevice(
04993         IN HDEVINFO DeviceInfoSet,
04994         IN PSP_DEVINFO_DATA DeviceInfoData)
04995 {
04996     struct DeviceInfoSet *list;
04997     BOOL ret = FALSE;
04998 
04999     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
05000 
05001     if (!DeviceInfoSet)
05002         SetLastError(ERROR_INVALID_HANDLE);
05003     else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
05004         SetLastError(ERROR_INVALID_HANDLE);
05005     else if (!DeviceInfoData)
05006         SetLastError(ERROR_INVALID_PARAMETER);
05007     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
05008         SetLastError(ERROR_INVALID_USER_BUFFER);
05009     else if (DeviceInfoData->Reserved == 0)
05010         SetLastError(ERROR_INVALID_USER_BUFFER);
05011     else
05012     {
05013         list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
05014         ret = TRUE;
05015     }
05016 
05017     TRACE("Returning %d\n", ret);
05018     return ret;
05019 }
05020 
05021 
05022 /* Return the current hardware profile id, or -1 if error */
05023 static DWORD
05024 SETUPAPI_GetCurrentHwProfile(
05025         IN HDEVINFO DeviceInfoSet)
05026 {
05027     HKEY hKey = NULL;
05028     DWORD dwRegType, dwLength;
05029     DWORD hwProfile;
05030     LONG rc;
05031     DWORD ret = (DWORD)-1;
05032 
05033     rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
05034                        REGSTR_PATH_IDCONFIGDB,
05035                        0, /* Options */
05036                        KEY_QUERY_VALUE,
05037                        &hKey);
05038     if (rc != ERROR_SUCCESS)
05039     {
05040         SetLastError(rc);
05041         goto cleanup;
05042     }
05043 
05044     dwLength = sizeof(DWORD);
05045     rc = RegQueryValueExW(hKey,
05046                           REGSTR_VAL_CURRENTCONFIG,
05047                           NULL,
05048                           &dwRegType,
05049                           (LPBYTE)&hwProfile, &dwLength);
05050     if (rc != ERROR_SUCCESS)
05051     {
05052         SetLastError(rc);
05053         goto cleanup;
05054     }
05055     else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
05056     {
05057         SetLastError(ERROR_GEN_FAILURE);
05058         goto cleanup;
05059     }
05060 
05061     ret = hwProfile;
05062 
05063 cleanup:
05064     if (hKey != NULL)
05065         RegCloseKey(hKey);
05066 
05067     return ret;
05068 }
05069 
05070 static BOOL
05071 ResetDevice(
05072         IN HDEVINFO DeviceInfoSet,
05073         IN PSP_DEVINFO_DATA DeviceInfoData)
05074 {
05075 #ifndef __WINESRC__
05076     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
05077     struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
05078     CONFIGRET cr;
05079 
05080     cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
05081     if (cr != CR_SUCCESS)
05082     {
05083         SetLastError(GetErrorCodeFromCrCode(cr));
05084         return FALSE;
05085     }
05086 
05087     return TRUE;
05088 #else
05089     FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
05090     return TRUE;
05091 #endif
05092 }
05093 
05094 static BOOL StopDevice(
05095         IN HDEVINFO DeviceInfoSet,
05096         IN PSP_DEVINFO_DATA DeviceInfoData)
05097 {
05098     FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
05099     return TRUE;
05100 }
05101 
05102 /***********************************************************************
05103  *      SetupDiChangeState (SETUPAPI.@)
05104  */
05105 BOOL WINAPI
05106 SetupDiChangeState(
05107         IN HDEVINFO DeviceInfoSet,
05108         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
05109 {
05110     PSP_PROPCHANGE_PARAMS PropChange;
05111     HKEY hKey = INVALID_HANDLE_VALUE;
05112     LPCWSTR RegistryValueName;
05113     DWORD dwConfigFlags, dwLength, dwRegType;
05114     LONG rc;
05115     BOOL ret = FALSE;
05116 
05117     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
05118 
05119     if (!DeviceInfoData)
05120         PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
05121     else
05122         PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
05123     if (!PropChange)
05124     {
05125         SetLastError(ERROR_INVALID_PARAMETER);
05126         goto cleanup;
05127     }
05128 
05129     if (PropChange->Scope == DICS_FLAG_GLOBAL)
05130         RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
05131     else
05132         RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
05133 
05134     switch (PropChange->StateChange)
05135     {
05136         case DICS_ENABLE:
05137         case DICS_DISABLE:
05138         {
05139             /* Enable/disable device in registry */
05140             hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
05141             if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
05142                 hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
05143             if (hKey == INVALID_HANDLE_VALUE)
05144                 break;
05145             dwLength = sizeof(DWORD);
05146             rc = RegQueryValueExW(
05147                 hKey,
05148                 RegistryValueName,
05149                 NULL,
05150                 &dwRegType,
05151                 (LPBYTE)&dwConfigFlags, &dwLength);
05152             if (rc == ERROR_FILE_NOT_FOUND)
05153                 dwConfigFlags = 0;
05154             else if (rc != ERROR_SUCCESS)
05155             {
05156                 SetLastError(rc);
05157                 goto cleanup;
05158             }
05159             else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
05160             {
05161                 SetLastError(ERROR_GEN_FAILURE);
05162                 goto cleanup;
05163             }
05164             if (PropChange->StateChange == DICS_ENABLE)
05165                 dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
05166             else
05167                 dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
05168             rc = RegSetValueExW(
05169                 hKey,
05170                 RegistryValueName,
05171                 0,
05172                 REG_DWORD,
05173                 (LPBYTE)&dwConfigFlags, sizeof(DWORD));
05174             if (rc != ERROR_SUCCESS)
05175             {
05176                 SetLastError(rc);
05177                 goto cleanup;
05178             }
05179 
05180             /* Enable/disable device if needed */
05181             if (PropChange->Scope == DICS_FLAG_GLOBAL
05182                 || PropChange->HwProfile == 0
05183                 || PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
05184             {
05185                 if (PropChange->StateChange == DICS_ENABLE)
05186                     ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
05187                 else
05188                     ret = StopDevice(DeviceInfoSet, DeviceInfoData);
05189             }
05190             else
05191                 ret = TRUE;
05192             break;
05193         }
05194         case DICS_PROPCHANGE:
05195         {
05196             ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
05197             break;
05198         }
05199         default:
05200         {
05201             ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
05202             SetLastError(ERROR_NOT_SUPPORTED);
05203         }
05204     }
05205 
05206 cleanup:
05207     if (hKey != INVALID_HANDLE_VALUE)
05208         RegCloseKey(hKey);
05209 
05210     TRACE("Returning %d\n", ret);
05211     return ret;
05212 }
05213 
05214 /***********************************************************************
05215  *      SetupDiSelectDevice (SETUPAPI.@)
05216  */
05217 BOOL WINAPI
05218 SetupDiSelectDevice(
05219         IN HDEVINFO DeviceInfoSet,
05220         IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
05221 {
05222     FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
05223     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
05224     return FALSE;
05225 }
05226 
05227 
05228 /***********************************************************************
05229  *      SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
05230  */
05231 BOOL WINAPI
05232 SetupDiRegisterCoDeviceInstallers(
05233         IN HDEVINFO DeviceInfoSet,
05234         IN PSP_DEVINFO_DATA DeviceInfoData)
05235 {
05236     BOOL ret = FALSE; /* Return value */
05237 
05238     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
05239 
05240     if (!DeviceInfoSet)
05241         SetLastError(ERROR_INVALID_PARAMETER);
05242     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
05243         SetLastError(ERROR_INVALID_HANDLE);
05244     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
05245         SetLastError(ERROR_INVALID_HANDLE);
05246     else if (!DeviceInfoData)
05247         SetLastError(ERROR_INVALID_PARAMETER);
05248     else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
05249         SetLastError(ERROR_INVALID_USER_BUFFER);
05250     else
05251     {
05252         SP_DEVINSTALL_PARAMS_W InstallParams;
05253         struct DriverInfoElement *SelectedDriver;
05254         BOOL Result;
05255         DWORD DoAction;
05256         WCHAR SectionName[MAX_PATH];
05257         DWORD SectionNameLength = 0;
05258         HKEY hKey = INVALID_HANDLE_VALUE;
05259         PVOID Context = NULL;
05260 
05261         InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
05262         Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
05263         if (!Result)
05264             goto cleanup;
05265 
05266         SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
05267         if (SelectedDriver == NULL)
05268         {
05269             SetLastError(ERROR_NO_DRIVER_SELECTED);
05270             goto cleanup;
05271         }
05272 
05273         /* Get .CoInstallers section name */
05274         Result = SetupDiGetActualSectionToInstallW(
05275             SelectedDriver->InfFileDetails->hInf,
05276             SelectedDriver->Details.SectionName,
05277             SectionName, MAX_PATH, &SectionNameLength, NULL);
05278         if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
05279             goto cleanup;
05280         lstrcatW(SectionName, DotCoInstallers);
05281 
05282         /* Open/Create driver key information */
05283 #if _WIN32_WINNT >= 0x502
05284         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
05285 #else
05286         hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
05287 #endif
05288         if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
05289             hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
05290         if (hKey == INVALID_HANDLE_VALUE)
05291             goto cleanup;
05292 
05293         /* Install .CoInstallers section */
05294         DoAction = SPINST_REGISTRY;
05295         if (!(InstallParams.Flags & DI_NOFILECOPY))
05296         {
05297             DoAction |= SPINST_FILES;
05298             Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
05299             if (!Context)
05300                 goto cleanup;
05301         }
05302         Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
05303             SelectedDriver->InfFileDetails->hInf, SectionName,
05304             DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
05305             SetupDefaultQueueCallbackW, Context,
05306             DeviceInfoSet, DeviceInfoData);
05307         if (!Result)
05308             goto cleanup;
05309 
05310         ret = TRUE;
05311 
05312 cleanup:
05313         if (Context)
05314             SetupTermDefaultQueueCallback(Context);
05315         if (hKey != INVALID_HANDLE_VALUE)
05316             RegCloseKey(hKey);
05317     }
05318 
05319     TRACE("Returning %d\n", ret);
05320     return ret;
05321 }
05322 
05323 static BOOL
05324 InfIsFromOEMLocation(
05325         IN PCWSTR FullName,
05326         OUT LPBOOL IsOEMLocation)
05327 {
05328     PWCHAR last;
05329 
05330     last = strrchrW(FullName, '\\');
05331     if (!last)
05332     {
05333         /* No directory specified */
05334         *IsOEMLocation = FALSE;
05335     }
05336     else
05337     {
05338         LPWSTR Windir;
05339         UINT ret;
05340 
05341         Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
05342         if (!Windir)
05343         {
05344             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
05345             return FALSE;
05346         }
05347 
05348         ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
05349         if (ret == 0 || ret > MAX_PATH)
05350         {
05351             MyFree(Windir);
05352             SetLastError(ERROR_GEN_FAILURE);
05353             return FALSE;
05354         }
05355         if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
05356             strcatW(Windir, BackSlash);
05357         strcatW(Windir, InfDirectory);
05358 
05359         if (strncmpiW(FullName, Windir, last - FullName) == 0)
05360         {
05361             /* The path is %SYSTEMROOT%\Inf */
05362             *IsOEMLocation = FALSE;
05363         }
05364         else
05365         {
05366             /* The file is in another place */
05367             *IsOEMLocation = TRUE;
05368         }
05369         MyFree(Windir);
05370     }
05371     return TRUE;
05372 }
05373 
05374 /***********************************************************************
05375  *      SetupDiInstallDevice (SETUPAPI.@)
05376  */
05377 BOOL WINAPI
05378 SetupDiInstallDevice(
05379         IN HDEVINFO DeviceInfoSet,
05380         IN OUT PSP_DEVINFO_DATA DeviceInfoData)
05381 {
05382     SP_DEVINSTALL_PARAMS_W InstallParams;
05383     struct DriverInfoElement *SelectedDriver;
05384     SYSTEMTIME DriverDate;
05385     WCHAR SectionName[MAX_PATH];
05386     WCHAR Buffer[32];
05387     DWORD SectionNameLength = 0;
05388     BOOL Result = FALSE;
05389     ULONG DoAction;
05390     DWORD RequiredSize;
05391     LPWSTR pSectionName = NULL;
05392     WCHAR ClassName[MAX_CLASS_NAME_LEN];
05393     GUID ClassGuid;
05394     LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
05395     BOOL RebootRequired = FALSE;
05396     HKEY hKey = INVALID_HANDLE_VALUE;
05397     BOOL NeedtoCopyFile;
05398     LARGE_INTEGER fullVersion;
05399     LONG rc;
05400     PVOID Context = NULL;
05401     BOOL ret = FALSE; /* Return value */
05402 
05403     TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
05404 
05405     if (!DeviceInfoSet)
05406         SetLastError(ERROR_INVALID_PARAMETER);
05407     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
05408         SetLastError(ERROR_INVALID_HANDLE);
05409     else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
05410         SetLastError(ERROR_INVALID_HANDLE);
05411     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
05412         SetLastError(ERROR_INVALID_USER_BUFFER);
05413     else
05414         Result = TRUE;
05415 
05416     if (!Result)
05417     {
05418         /* One parameter is bad */
05419         goto cleanup;
05420     }
05421 
05422     InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
05423     Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
05424     if (!Result)
05425         goto cleanup;
05426 
05427     if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
05428     {
05429         /* Set FAILEDINSTALL in ConfigFlags registry value */
05430         DWORD ConfigFlags, regType;
05431         Result = SetupDiGetDeviceRegistryPropertyW(
05432             DeviceInfoSet,
05433             DeviceInfoData,
05434             SPDRP_CONFIGFLAGS,
05435             &regType,
05436             (PBYTE)&ConfigFlags,
05437             sizeof(ConfigFlags),
05438             NULL);
05439         if (!Result || regType != REG_DWORD)
05440         {
05441             SetLastError(ERROR_GEN_FAILURE);
05442             goto cleanup;
05443         }
05444         ConfigFlags |= DNF_DISABLED;
05445         Result = SetupDiSetDeviceRegistryPropertyW(
05446             DeviceInfoSet,
05447             DeviceInfoData,
05448             SPDRP_CONFIGFLAGS,
05449             (PBYTE)&ConfigFlags,
05450             sizeof(ConfigFlags));
05451         if (!Result)
05452         {
05453             SetLastError(ERROR_GEN_FAILURE);
05454             goto cleanup;
05455         }
05456 
05457         ret = TRUE;
05458         goto cleanup;
05459     }
05460 
05461     SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
05462     if (SelectedDriver == NULL)
05463     {
05464         SetLastError(ERROR_NO_DRIVER_SELECTED);
05465         goto cleanup;
05466     }
05467 
05468     FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
05469 
05470     Result = SetupDiGetActualSectionToInstallW(
05471         SelectedDriver->InfFileDetails->hInf,
05472         SelectedDriver->Details.SectionName,
05473         SectionName, MAX_PATH, &SectionNameLength, NULL);
05474     if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
05475         goto cleanup;
05476     pSectionName = &SectionName[strlenW(SectionName)];
05477 
05478     /* Get information from [Version] section */
05479     if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
05480         goto cleanup;
05481     /* Format ClassGuid to a string */
05482     if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
05483         goto cleanup;
05484     RequiredSize = lstrlenW(lpGuidString);
05485     lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
05486     if (!lpFullGuidString)
05487     {
05488         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
05489         goto cleanup;
05490     }
05491     lpFullGuidString[0] = '{';
05492     memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
05493     lpFullGuidString[RequiredSize + 1] = '}';
05494     lpFullGuidString[RequiredSize + 2] = '\0';
05495 
05496     /* Copy .inf file to Inf\ directory (if needed) */
05497     Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
05498     if (!Result)
05499         goto cleanup;
05500     if (NeedtoCopyFile)
05501     {
05502         WCHAR NewFileName[MAX_PATH];
05503         struct InfFileDetails *newInfFileDetails;
05504         Result = SetupCopyOEMInfW(
05505             SelectedDriver->Details.InfFileName,
05506             NULL,
05507             SPOST_NONE,
05508             SP_COPY_NOOVERWRITE,
05509             NewFileName, MAX_PATH,
05510             NULL,
05511             NULL);
05512         if (!Result && GetLastError() != ERROR_FILE_EXISTS)
05513             goto cleanup;
05514         /* Create a new struct InfFileDetails, and set it to
05515          * SelectedDriver->InfFileDetails, to release use of
05516          * current InfFile */
05517         newInfFileDetails = CreateInfFileDetails(NewFileName);
05518         if (!newInfFileDetails)
05519             goto cleanup;
05520         DereferenceInfFile(SelectedDriver->InfFileDetails);
05521         SelectedDriver->InfFileDetails = newInfFileDetails;
05522         strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
05523     }
05524 
05525     /* Open/Create driver key information */
05526 #if _WIN32_WINNT >= 0x502
05527     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
05528 #else
05529     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
05530 #endif
05531     if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
05532         hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
05533     if (hKey == INVALID_HANDLE_VALUE)
05534         goto cleanup;
05535 
05536     /* Install main section */
05537     DoAction = 0;
05538     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
05539         DoAction |= SPINST_REGISTRY;
05540     if (!(InstallParams.Flags & DI_NOFILECOPY))
05541     {
05542         DoAction |= SPINST_FILES;
05543         Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
05544         if (!Context)
05545             goto cleanup;
05546     }
05547     *pSectionName = '\0';
05548     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
05549         SelectedDriver->InfFileDetails->hInf, SectionName,
05550         DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
05551         SetupDefaultQueueCallbackW, Context,
05552         DeviceInfoSet, DeviceInfoData);
05553     if (!Result)
05554         goto cleanup;
05555     InstallParams.Flags |= DI_NOFILECOPY;
05556     SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
05557 
05558     /* Write information to driver key */
05559     *pSectionName = UNICODE_NULL;
05560     memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
05561     TRACE("Write information to driver key\n");
05562     TRACE("DriverDate      : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
05563     TRACE("DriverDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
05564     TRACE("DriverVersion   : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
05565     TRACE("InfPath         : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
05566     TRACE("InfSection      : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
05567     TRACE("InfSectionExt   : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
05568     TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
05569     TRACE("ProviderName    : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
05570     sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
05571     rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
05572     if (rc == ERROR_SUCCESS)
05573         rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
05574     if (rc == ERROR_SUCCESS)
05575         rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
05576     if (rc == ERROR_SUCCESS)
05577     {
05578         sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
05579         rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
05580     }
05581     if (rc == ERROR_SUCCESS)
05582         rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
05583     if (rc == ERROR_SUCCESS)
05584         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
05585     if (rc == ERROR_SUCCESS)
05586         rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTIONEXT, 0, REG_SZ, (const BYTE *)&SectionName[strlenW(SelectedDriver->Details.SectionName)], (strlenW(SectionName) - strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
05587     if (rc == ERROR_SUCCESS)
05588         rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
05589     if (rc == ERROR_SUCCESS)
05590         rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
05591     if (rc != ERROR_SUCCESS)
05592     {
05593        SetLastError(rc);
05594        goto cleanup;
05595     }
05596     RegCloseKey(hKey);
05597     hKey = INVALID_HANDLE_VALUE;
05598 
05599     /* FIXME: Process .LogConfigOverride section */
05600 
05601     /* Install .Services section */
05602     strcpyW(pSectionName, DotServices);
05603     Result = SetupInstallServicesFromInfSectionExW(
05604         SelectedDriver->InfFileDetails->hInf,
05605         SectionName,
05606         0,
05607         DeviceInfoSet,
05608         DeviceInfoData,
05609         NULL,
05610         NULL);
05611     if (!Result)
05612         goto cleanup;
05613     if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
05614         RebootRequired = TRUE;
05615 
05616     /* Open device registry key */
05617     hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
05618     if (hKey == INVALID_HANDLE_VALUE)
05619         goto cleanup;
05620 
05621     /* Install .HW section */
05622     DoAction = 0;
05623     if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
05624         DoAction |= SPINST_REGISTRY;
05625     strcpyW(pSectionName, DotHW);
05626     Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
05627         SelectedDriver->InfFileDetails->hInf, SectionName,
05628         DoAction, hKey, NULL, 0,
05629         NULL, NULL,
05630         DeviceInfoSet, DeviceInfoData);
05631     if (!Result)
05632         goto cleanup;
05633 
05634     /* Write information to enum key */
05635     TRACE("Write information to enum key\n");
05636     TRACE("Class           : '%s'\n", debugstr_w(ClassName));
05637     TRACE("ClassGUID       : '%s'\n", debugstr_w(lpFullGuidString));
05638     TRACE("DeviceDesc      : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
05639     TRACE("Mfg             : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
05640     rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
05641     if (rc == ERROR_SUCCESS)
05642         rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
05643     if (rc == ERROR_SUCCESS)
05644         rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
05645     if (rc == ERROR_SUCCESS)
05646         rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
05647     if (rc != ERROR_SUCCESS)
05648     {
05649        SetLastError(rc);
05650        goto cleanup;
05651     }
05652 
05653     /* Start the device */
05654     if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
05655         ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
05656     else
05657         ret = TRUE;
05658 
05659 cleanup:
05660     /* End of installation */
05661     if (hKey != INVALID_HANDLE_VALUE)
05662         RegCloseKey(hKey);
05663     if (lpGuidString)
05664         RpcStringFreeW(&lpGuidString);
05665     HeapFree(GetProcessHeap(), 0, lpFullGuidString);
05666     if (Context)
05667         SetupTermDefaultQueueCallback(Context);
05668     TRACE("Returning %d\n", ret);
05669     return ret;
05670 }
05671 
05672 static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
05673 {
05674     HKEY enumKey, key = INVALID_HANDLE_VALUE;
05675     LONG l;
05676 
05677     l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, 0, &enumKey);
05678     if (!l)
05679     {
05680         l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
05681         RegCloseKey(enumKey);
05682     }
05683     if (l)
05684         SetLastError(l);
05685     return key;
05686 }
05687 
05688 static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
05689 {
05690     LPWSTR DriverKey = NULL;
05691     DWORD dwLength = 0;
05692     DWORD dwRegType;
05693     DWORD rc;
05694     HKEY hEnumKey = NULL;
05695     HKEY hKey = NULL;
05696     HKEY key = INVALID_HANDLE_VALUE;
05697 
05698     hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
05699     if (hKey == INVALID_HANDLE_VALUE)
05700         goto cleanup;
05701     /* Read the 'Driver' key */
05702     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
05703     if (rc != ERROR_SUCCESS)
05704     {
05705         SetLastError(rc);
05706         goto cleanup;
05707     }
05708     else if (dwRegType != REG_SZ)
05709     {
05710         SetLastError(ERROR_GEN_FAILURE);
05711         goto cleanup;
05712     }
05713     DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
05714     if (!DriverKey)
05715     {
05716         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
05717         goto cleanup;
05718     }
05719     rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
05720     if (rc != ERROR_SUCCESS)
05721     {
05722         SetLastError(rc);
05723         goto cleanup;
05724     }
05725     RegCloseKey(hKey);
05726     hKey = NULL;
05727     /* Need to open the driver key */
05728     rc = RegOpenKeyExW(
05729         RootKey,
05730         REGSTR_PATH_CLASS_NT,
05731         0, /* Options */
05732         0,
05733         &hEnumKey);
05734     if (rc != ERROR_SUCCESS)
05735     {
05736         SetLastError(rc);
05737         goto cleanup;
05738     }
05739     rc = RegOpenKeyExW(
05740         hEnumKey,
05741         DriverKey,
05742         0, /* Options */
05743         samDesired,
05744         &hKey);
05745     if (rc != ERROR_SUCCESS)
05746     {
05747         SetLastError(rc);
05748         goto cleanup;
05749     }
05750     key = hKey;
05751 
05752 cleanup:
05753     if (hEnumKey != NULL)
05754         RegCloseKey(hEnumKey);
05755     if (hKey != NULL && hKey != key)
05756         RegCloseKey(hKey);
05757     return key;
05758 }
05759 
05760 /***********************************************************************
05761  *      SetupDiOpenDevRegKey (SETUPAPI.@)
05762  */
05763 HKEY WINAPI SetupDiOpenDevRegKey(
05764         HDEVINFO DeviceInfoSet,
05765         PSP_DEVINFO_DATA DeviceInfoData,
05766         DWORD Scope,
05767         DWORD HwProfile,
05768         DWORD KeyType,
05769         REGSAM samDesired)
05770 {
05771     struct DeviceInfoSet *set = DeviceInfoSet;
05772     struct DeviceInfo *devInfo;
05773     HKEY key = INVALID_HANDLE_VALUE;
05774     HKEY RootKey;
05775 
05776     TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
05777           Scope, HwProfile, KeyType, samDesired);
05778 
05779     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
05780     {
05781         SetLastError(ERROR_INVALID_HANDLE);
05782         return INVALID_HANDLE_VALUE;
05783     }
05784     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
05785     {
05786         SetLastError(ERROR_INVALID_HANDLE);
05787         return INVALID_HANDLE_VALUE;
05788     }
05789     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
05790             || !DeviceInfoData->Reserved)
05791     {
05792         SetLastError(ERROR_INVALID_PARAMETER);
05793         return INVALID_HANDLE_VALUE;
05794     }
05795     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
05796     {
05797         SetLastError(ERROR_INVALID_FLAGS);
05798         return INVALID_HANDLE_VALUE;
05799     }
05800     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
05801     {
05802         SetLastError(ERROR_INVALID_FLAGS);
05803         return INVALID_HANDLE_VALUE;
05804     }
05805     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
05806     if (devInfo->set != set)
05807     {
05808         SetLastError(ERROR_INVALID_PARAMETER);
05809         return INVALID_HANDLE_VALUE;
05810     }
05811     if (Scope != DICS_FLAG_GLOBAL)
05812     {
05813         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
05814         if (RootKey == INVALID_HANDLE_VALUE)
05815             return INVALID_HANDLE_VALUE;
05816     }
05817     else
05818         RootKey = set->HKLM;
05819     switch (KeyType)
05820     {
05821         case DIREG_DEV:
05822             key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
05823             break;
05824         case DIREG_DRV:
05825             key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
05826             break;
05827         default:
05828             WARN("unknown KeyType %d\n", KeyType);
05829     }
05830     if (RootKey != set->HKLM)
05831         RegCloseKey(RootKey);
05832     return key;
05833 }
05834 
05835 static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
05836 {
05837     FIXME("\n");
05838     return FALSE;
05839 }
05840 
05841 static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
05842 {
05843     FIXME("\n");
05844     return FALSE;
05845 }
05846 
05847 /***********************************************************************
05848  *      SetupDiDeleteDevRegKey (SETUPAPI.@)
05849  */
05850 BOOL WINAPI SetupDiDeleteDevRegKey(
05851         HDEVINFO DeviceInfoSet,
05852         PSP_DEVINFO_DATA DeviceInfoData,
05853         DWORD Scope,
05854         DWORD HwProfile,
05855         DWORD KeyType)
05856 {
05857     struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
05858     struct DeviceInfo *devInfo;
05859     BOOL ret = FALSE;
05860     HKEY RootKey;
05861 
05862     TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
05863             KeyType);
05864 
05865     if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
05866     {
05867         SetLastError(ERROR_INVALID_HANDLE);
05868         return FALSE;
05869     }
05870     if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
05871     {
05872         SetLastError(ERROR_INVALID_HANDLE);
05873         return FALSE;
05874     }
05875     if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
05876             || !DeviceInfoData->Reserved)
05877     {
05878         SetLastError(ERROR_INVALID_PARAMETER);
05879         return FALSE;
05880     }
05881     if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
05882     {
05883         SetLastError(ERROR_INVALID_FLAGS);
05884         return FALSE;
05885     }
05886     if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
05887     {
05888         SetLastError(ERROR_INVALID_FLAGS);
05889         return FALSE;
05890     }
05891     devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
05892     if (devInfo->set != set)
05893     {
05894         SetLastError(ERROR_INVALID_PARAMETER);
05895         return FALSE;
05896     }
05897     if (Scope != DICS_FLAG_GLOBAL)
05898     {
05899         RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
05900         if (RootKey == INVALID_HANDLE_VALUE)
05901             return FALSE;
05902     }
05903     else
05904         RootKey = set->HKLM;
05905     switch (KeyType)
05906     {
05907         case DIREG_DEV:
05908             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
05909             break;
05910         case DIREG_DRV:
05911             ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
05912             break;
05913         case DIREG_BOTH:
05914             ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
05915             if (ret)
05916                 ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
05917             break;
05918         default:
05919             WARN("unknown KeyType %d\n", KeyType);
05920     }
05921     if (RootKey != set->HKLM)
05922         RegCloseKey(RootKey);
05923     return ret;
05924 }

Generated on Sat May 26 2012 04:16:55 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.