reactos/dll/win32/setupapi/devinst.c
Hermès Bélusca-Maïto 65ce146169 Create a branch for working on csrss and co.
svn path=/branches/ros-csrss/; revision=57561
2012-10-14 13:04:31 +00:00

5925 lines
191 KiB
C

/*
* SetupAPI device installer
*
* Copyright 2000 Andreas Mohr for CodeWeavers
* 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "setupapi_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
/* Unicode constants */
static const WCHAR BackSlash[] = {'\\',0};
static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
static const WCHAR Class[] = {'C','l','a','s','s',0};
static const WCHAR DateFormat[] = {'%','u','-','%','u','-','%','u',0};
static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
static const WCHAR DotHW[] = {'.','H','W',0};
static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
static const WCHAR InstanceKeyFormat[] = {'%','0','4','l','u',0};
static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
static const WCHAR VersionFormat[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
static const WCHAR REGSTR_DRIVER_DATE[] = {'D','r','i','v','e','r','D','a','t','e',0};
static const WCHAR REGSTR_DRIVER_DATE_DATA[] = {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
static const WCHAR REGSTR_DRIVER_VERSION[] = {'D','r','i','v','e','r','V','e','r','s','i','o','n',0};
static const WCHAR REGSTR_SECURITY[] = {'S','e','c','u','r','i','t','y',0};
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};
typedef DWORD
(CALLBACK* CLASS_INSTALL_PROC) (
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL);
typedef BOOL
(WINAPI* DEFAULT_CLASS_INSTALL_PROC) (
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData);
typedef DWORD
(CALLBACK* COINSTALLER_PROC) (
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN OUT PCOINSTALLER_CONTEXT_DATA Context);
struct CoInstallerElement
{
LIST_ENTRY ListEntry;
HMODULE Module;
COINSTALLER_PROC Function;
BOOL DoPostProcessing;
PVOID PrivateData;
};
struct GetSectionCallbackInfo
{
PSP_ALTPLATFORM_INFO PlatformInfo;
BYTE ProductType;
WORD SuiteMask;
DWORD PrefixLength;
WCHAR BestSection[LINE_LEN + 1];
DWORD BestScore1, BestScore2, BestScore3, BestScore4, BestScore5;
};
static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
{
static const WCHAR fmt[] = {'{','%','0','8','X','-','%','0','4','X','-',
'%','0','4','X','-','%','0','2','X','%','0','2','X','-','%','0','2',
'X','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X','%',
'0','2','X','}',0};
sprintfW(guidStr, fmt, guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
static DWORD
GetErrorCodeFromCrCode(const IN CONFIGRET cr)
{
switch (cr)
{
case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER;
case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED;
case CR_FAILURE: return ERROR_GEN_FAILURE;
case CR_INVALID_DATA: return ERROR_INVALID_USER_BUFFER;
case CR_INVALID_DEVICE_ID: return ERROR_INVALID_PARAMETER;
case CR_INVALID_MACHINENAME: return ERROR_INVALID_COMPUTERNAME;
case CR_INVALID_DEVNODE: return ERROR_INVALID_PARAMETER;
case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS;
case CR_INVALID_POINTER: return ERROR_INVALID_PARAMETER;
case CR_INVALID_PROPERTY: return ERROR_INVALID_PARAMETER;
case CR_NO_SUCH_DEVNODE: return ERROR_FILE_NOT_FOUND;
case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND;
case CR_NO_SUCH_VALUE: return ERROR_FILE_NOT_FOUND;
case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY;
case CR_REGISTRY_ERROR: return ERROR_GEN_FAILURE;
case CR_ALREADY_SUCH_DEVINST: return ERROR_DEVINST_ALREADY_EXISTS;
case CR_SUCCESS: return ERROR_SUCCESS;
default: return ERROR_GEN_FAILURE;
}
/* Does not happen */
}
/* Lower scores are best ones */
static BOOL
CheckSectionValid(
IN LPCWSTR SectionName,
IN PSP_ALTPLATFORM_INFO PlatformInfo,
IN BYTE ProductType,
IN WORD SuiteMask,
OUT PDWORD ScorePlatform,
OUT PDWORD ScoreMajorVersion,
OUT PDWORD ScoreMinorVersion,
OUT PDWORD ScoreProductType,
OUT PDWORD ScoreSuiteMask)
{
LPWSTR Section = NULL;
//LPCWSTR pExtensionPlatform;
LPCWSTR pExtensionArchitecture;
LPWSTR Fields[6];
DWORD i;
BOOL ret = FALSE;
//static const WCHAR ExtensionPlatformNone[] = {'.',0};
static const WCHAR ExtensionPlatformNT[] = {'.','N','T',0};
static const WCHAR ExtensionPlatformWindows[] = {'.','W','i','n',0};
static const WCHAR ExtensionArchitectureNone[] = {0};
static const WCHAR ExtensionArchitecturealpha[] = {'a','l','p','h','a',0};
static const WCHAR ExtensionArchitectureamd64[] = {'A','M','D','6','4',0};
static const WCHAR ExtensionArchitectureia64[] = {'I','A','6','4',0};
static const WCHAR ExtensionArchitecturemips[] = {'m','i','p','s',0};
static const WCHAR ExtensionArchitectureppc[] = {'p','p','c',0};
static const WCHAR ExtensionArchitecturex86[] = {'x','8','6',0};
TRACE("%s %p 0x%x 0x%x\n",
debugstr_w(SectionName), PlatformInfo, ProductType, SuiteMask);
*ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = 0;
Section = pSetupDuplicateString(SectionName);
if (!Section)
{
TRACE("pSetupDuplicateString() failed\n");
goto cleanup;
}
/* Set various extensions values */
switch (PlatformInfo->Platform)
{
case VER_PLATFORM_WIN32_WINDOWS:
//pExtensionPlatform = ExtensionPlatformWindows;
break;
case VER_PLATFORM_WIN32_NT:
//pExtensionPlatform = ExtensionPlatformNT;
break;
default:
ERR("Unknown platform 0x%lx\n", PlatformInfo->Platform);
//pExtensionPlatform = ExtensionPlatformNone;
break;
}
switch (PlatformInfo->ProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_ALPHA:
pExtensionArchitecture = ExtensionArchitecturealpha;
break;
case PROCESSOR_ARCHITECTURE_AMD64:
pExtensionArchitecture = ExtensionArchitectureamd64;
break;
case PROCESSOR_ARCHITECTURE_IA64:
pExtensionArchitecture = ExtensionArchitectureia64;
break;
case PROCESSOR_ARCHITECTURE_INTEL:
pExtensionArchitecture = ExtensionArchitecturex86;
break;
case PROCESSOR_ARCHITECTURE_MIPS:
pExtensionArchitecture = ExtensionArchitecturemips;
break;
case PROCESSOR_ARCHITECTURE_PPC:
pExtensionArchitecture = ExtensionArchitectureppc;
break;
default:
ERR("Unknown processor architecture 0x%x\n", PlatformInfo->ProcessorArchitecture);
case PROCESSOR_ARCHITECTURE_UNKNOWN:
pExtensionArchitecture = ExtensionArchitectureNone;
break;
}
/*
* Field[0] Platform
* Field[1] Architecture
* Field[2] Major version
* Field[3] Minor version
* Field[4] Product type
* Field[5] Suite mask
* Remark: lastests fields may be NULL if the information is not provided
*/
Fields[0] = Section;
if (Fields[0] == NULL)
{
TRACE("No extension found\n");
*ScorePlatform = *ScoreMajorVersion = *ScoreMinorVersion = *ScoreProductType = *ScoreSuiteMask = ULONG_MAX;
ret = TRUE;
goto cleanup;
}
Fields[1] = Fields[0] + 1;
Fields[2] = Fields[3] = Fields[4] = Fields[5] = NULL;
for (i = 2; Fields[i - 1] != NULL && i < 6; i++)
{
Fields[i] = wcschr(Fields[i - 1], '.');
if (Fields[i])
{
Fields[i]++;
*(Fields[i] - 1) = UNICODE_NULL;
}
}
/* Take care of first 2 fields */
if (strncmpiW(Fields[0], ExtensionPlatformWindows, strlenW(ExtensionPlatformWindows)) == 0)
{
if (PlatformInfo->Platform != VER_PLATFORM_WIN32_WINDOWS)
{
TRACE("Mismatch on platform field\n");
goto cleanup;
}
Fields[1] += wcslen(ExtensionPlatformWindows) - 1;
}
else if (strncmpiW(Fields[0], ExtensionPlatformNT, strlenW(ExtensionPlatformNT)) == 0)
{
if (PlatformInfo->Platform != VER_PLATFORM_WIN32_NT)
{
TRACE("Mismatch on platform field\n");
goto cleanup;
}
Fields[1] += wcslen(ExtensionPlatformNT) - 1;
}
else
{
/* No platform specified */
*ScorePlatform |= 0x02;
}
if (strcmpiW(Fields[1], ExtensionArchitectureNone) == 0)
{
/* No architecture specified */
*ScorePlatform |= 0x01;
}
else if (strcmpiW(Fields[1], pExtensionArchitecture) != 0)
{
TRACE("Mismatch on architecture field ('%s' and '%s')\n",
debugstr_w(Fields[1]), debugstr_w(pExtensionArchitecture));
goto cleanup;
}
/* Check if informations are matching */
if (Fields[2] && *Fields[2])
{
DWORD MajorVersion, MinorVersion = 0;
MajorVersion = strtoulW(Fields[2], NULL, 0);
if ((MajorVersion == 0 || MajorVersion == ULONG_MAX) &&
(errno == ERANGE || errno == EINVAL))
{
TRACE("Wrong MajorVersion ('%s')\n", debugstr_w(Fields[2]));
goto cleanup;
}
if (Fields[3] && *Fields[3])
{
MinorVersion = strtoulW(Fields[3], NULL, 0);
if ((MinorVersion == 0 || MinorVersion == ULONG_MAX) &&
(errno == ERANGE || errno == EINVAL))
{
TRACE("Wrong MinorVersion ('%s')\n", debugstr_w(Fields[3]));
goto cleanup;
}
}
if (PlatformInfo->MajorVersion < MajorVersion ||
(PlatformInfo->MajorVersion == MajorVersion && PlatformInfo->MinorVersion < MinorVersion))
{
TRACE("Mismatch on version field (%lu.%lu and %lu.%lu)\n",
MajorVersion, MinorVersion, PlatformInfo->MajorVersion, PlatformInfo->MinorVersion);
goto cleanup;
}
*ScoreMajorVersion = MajorVersion - PlatformInfo->MajorVersion;
if (MajorVersion == PlatformInfo->MajorVersion)
*ScoreMinorVersion = MinorVersion - PlatformInfo->MinorVersion;
else
*ScoreMinorVersion = MinorVersion;
}
else if (Fields[3] && *Fields[3])
{
TRACE("Minor version found without major version\n");
goto cleanup;
}
else
{
*ScoreMajorVersion = PlatformInfo->MajorVersion;
*ScoreMinorVersion = PlatformInfo->MinorVersion;
}
if (Fields[4] && *Fields[4])
{
DWORD CurrentProductType;
CurrentProductType = strtoulW(Fields[4], NULL, 0);
if ((CurrentProductType == 0 || CurrentProductType == ULONG_MAX) &&
(errno == ERANGE || errno == EINVAL))
{
TRACE("Wrong Product type ('%s')\n", debugstr_w(Fields[4]));
goto cleanup;
}
if (CurrentProductType != ProductType)
{
TRACE("Mismatch on product type (0x%08lx and 0x%08x)\n",
CurrentProductType, ProductType);
goto cleanup;
}
}
else
*ScoreProductType = 1;
if (Fields[5] && *Fields[5])
{
DWORD CurrentSuiteMask;
CurrentSuiteMask = strtoulW(Fields[5], NULL, 0);
if ((CurrentSuiteMask == 0 || CurrentSuiteMask == ULONG_MAX) &&
(errno == ERANGE || errno == EINVAL))
{
TRACE("Wrong Suite mask ('%s')\n", debugstr_w(Fields[5]));
goto cleanup;
}
if ((CurrentSuiteMask & ~SuiteMask) != 0)
{
TRACE("Mismatch on suite mask (0x%08lx and 0x%08x)\n",
CurrentSuiteMask, SuiteMask);
goto cleanup;
}
*ScoreSuiteMask = SuiteMask & ~CurrentSuiteMask;
}
else
*ScoreSuiteMask = SuiteMask;
ret = TRUE;
cleanup:
MyFree(Section);
return ret;
}
static BOOL
GetSectionCallback(
IN LPCWSTR SectionName,
IN PVOID Context)
{
struct GetSectionCallbackInfo *info = Context;
DWORD Score1, Score2, Score3, Score4, Score5;
BOOL ret;
if (SectionName[info->PrefixLength] != '.')
return TRUE;
ret = CheckSectionValid(
&SectionName[info->PrefixLength],
info->PlatformInfo,
info->ProductType,
info->SuiteMask,
&Score1, &Score2, &Score3, &Score4, &Score5);
if (!ret)
{
TRACE("Section %s not compatible\n", debugstr_w(SectionName));
return TRUE;
}
if (Score1 > info->BestScore1) goto done;
if (Score1 < info->BestScore1) goto bettersection;
if (Score2 > info->BestScore2) goto done;
if (Score2 < info->BestScore2) goto bettersection;
if (Score3 > info->BestScore3) goto done;
if (Score3 < info->BestScore3) goto bettersection;
if (Score4 > info->BestScore4) goto done;
if (Score4 < info->BestScore4) goto bettersection;
if (Score5 > info->BestScore5) goto done;
if (Score5 < info->BestScore5) goto bettersection;
goto done;
bettersection:
strcpyW(info->BestSection, SectionName);
info->BestScore1 = Score1;
info->BestScore2 = Score2;
info->BestScore3 = Score3;
info->BestScore4 = Score4;
info->BestScore5 = Score5;
done:
return TRUE;
}
/***********************************************************************
* SetupDiGetActualSectionToInstallExW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetActualSectionToInstallExW(
IN HINF InfHandle,
IN PCWSTR InfSectionName,
IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
OUT PWSTR InfSectionWithExt OPTIONAL,
IN DWORD InfSectionWithExtSize,
OUT PDWORD RequiredSize OPTIONAL,
OUT PWSTR* Extension OPTIONAL,
IN PVOID Reserved)
{
BOOL ret = FALSE;
TRACE("%p %s %p %p %lu %p %p %p\n", InfHandle, debugstr_w(InfSectionName),
AlternatePlatformInfo, InfSectionWithExt, InfSectionWithExtSize,
RequiredSize, Extension, Reserved);
if (!InfHandle || InfHandle == (HINF)INVALID_HANDLE_VALUE)
SetLastError(ERROR_INVALID_HANDLE);
else if (!InfSectionName)
SetLastError(ERROR_INVALID_PARAMETER);
else if (AlternatePlatformInfo && AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (Reserved != NULL)
SetLastError(ERROR_INVALID_PARAMETER);
else
{
static SP_ALTPLATFORM_INFO CurrentPlatform = { 0, };
static BYTE CurrentProductType = 0;
static WORD CurrentSuiteMask = 0;
PSP_ALTPLATFORM_INFO pPlatformInfo = &CurrentPlatform;
struct GetSectionCallbackInfo CallbackInfo;
DWORD dwFullLength;
BYTE ProductType;
WORD SuiteMask;
/* Fill platform info if needed */
if (AlternatePlatformInfo)
{
pPlatformInfo = AlternatePlatformInfo;
ProductType = 0;
SuiteMask = 0;
}
else
{
if (CurrentPlatform.cbSize != sizeof(SP_ALTPLATFORM_INFO))
{
/* That's the first time we go here. We need to fill in the structure */
OSVERSIONINFOEX VersionInfo;
SYSTEM_INFO SystemInfo;
VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
ret = GetVersionExW((OSVERSIONINFO*)&VersionInfo);
if (!ret)
goto done;
GetSystemInfo(&SystemInfo);
CurrentPlatform.cbSize = sizeof(SP_ALTPLATFORM_INFO);
CurrentPlatform.Platform = VersionInfo.dwPlatformId;
CurrentPlatform.MajorVersion = VersionInfo.dwMajorVersion;
CurrentPlatform.MinorVersion = VersionInfo.dwMinorVersion;
CurrentPlatform.ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
CurrentPlatform.Reserved = 0;
CurrentProductType = VersionInfo.wProductType;
CurrentSuiteMask = VersionInfo.wSuiteMask;
}
ProductType = CurrentProductType;
SuiteMask = CurrentSuiteMask;
}
CallbackInfo.PlatformInfo = pPlatformInfo;
CallbackInfo.ProductType = ProductType;
CallbackInfo.SuiteMask = SuiteMask;
CallbackInfo.PrefixLength = strlenW(InfSectionName);
CallbackInfo.BestScore1 = ULONG_MAX;
CallbackInfo.BestScore2 = ULONG_MAX;
CallbackInfo.BestScore3 = ULONG_MAX;
CallbackInfo.BestScore4 = ULONG_MAX;
CallbackInfo.BestScore5 = ULONG_MAX;
strcpyW(CallbackInfo.BestSection, InfSectionName);
if (!EnumerateSectionsStartingWith(
InfHandle,
InfSectionName,
GetSectionCallback,
&CallbackInfo))
{
SetLastError(ERROR_GEN_FAILURE);
goto done;
}
dwFullLength = lstrlenW(CallbackInfo.BestSection);
if (RequiredSize != NULL)
*RequiredSize = dwFullLength + 1;
if (InfSectionWithExtSize > 0)
{
if (InfSectionWithExtSize < dwFullLength + 1)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto done;
}
strcpyW(InfSectionWithExt, CallbackInfo.BestSection);
if (Extension)
{
DWORD dwLength = lstrlenW(InfSectionName);
*Extension = (dwLength == dwFullLength) ? NULL : &InfSectionWithExt[dwLength];
}
}
ret = TRUE;
}
done:
TRACE("Returning %d\n", ret);
return ret;
}
BOOL
CreateDeviceInfo(
IN struct DeviceInfoSet *list,
IN LPCWSTR InstancePath,
IN LPCGUID pClassGuid,
OUT struct DeviceInfo **pDeviceInfo)
{
DWORD size;
CONFIGRET cr;
struct DeviceInfo *deviceInfo;
*pDeviceInfo = NULL;
size = FIELD_OFFSET(struct DeviceInfo, Data) + (strlenW(InstancePath) + 1) * sizeof(WCHAR);
deviceInfo = HeapAlloc(GetProcessHeap(), 0, size);
if (!deviceInfo)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
ZeroMemory(deviceInfo, size);
cr = CM_Locate_DevNode_ExW(&deviceInfo->dnDevInst, (DEVINSTID_W)InstancePath, CM_LOCATE_DEVNODE_PHANTOM, list->hMachine);
if (cr != CR_SUCCESS)
{
SetLastError(GetErrorCodeFromCrCode(cr));
return FALSE;
}
deviceInfo->set = list;
deviceInfo->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
strcpyW(deviceInfo->Data, InstancePath);
deviceInfo->instanceId = deviceInfo->Data;
deviceInfo->UniqueId = strrchrW(deviceInfo->Data, '\\');
deviceInfo->DeviceDescription = NULL;
memcpy(&deviceInfo->ClassGuid, pClassGuid, sizeof(GUID));
deviceInfo->CreationFlags = 0;
InitializeListHead(&deviceInfo->DriverListHead);
InitializeListHead(&deviceInfo->InterfaceListHead);
*pDeviceInfo = deviceInfo;
return TRUE;
}
static BOOL
DestroyClassInstallParams(struct ClassInstallParams* installParams)
{
HeapFree(GetProcessHeap(), 0, installParams->PropChangeParams);
HeapFree(GetProcessHeap(), 0, installParams->AddPropertyPageData);
return TRUE;
}
static BOOL
DestroyDeviceInfo(struct DeviceInfo *deviceInfo)
{
PLIST_ENTRY ListEntry;
struct DriverInfoElement *driverInfo;
struct DeviceInterface *deviceInterface;
while (!IsListEmpty(&deviceInfo->DriverListHead))
{
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
if (!DestroyDriverInfoElement(driverInfo))
return FALSE;
}
while (!IsListEmpty(&deviceInfo->InterfaceListHead))
{
ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
deviceInterface = CONTAINING_RECORD(ListEntry, struct DeviceInterface, ListEntry);
if (!DestroyDeviceInterface(deviceInterface))
return FALSE;
}
DestroyClassInstallParams(&deviceInfo->ClassInstallParams);
return HeapFree(GetProcessHeap(), 0, deviceInfo);
}
static BOOL
DestroyDeviceInfoSet(struct DeviceInfoSet* list)
{
PLIST_ENTRY ListEntry;
struct DeviceInfo *deviceInfo;
while (!IsListEmpty(&list->ListHead))
{
ListEntry = RemoveHeadList(&list->ListHead);
deviceInfo = CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry);
if (!DestroyDeviceInfo(deviceInfo))
return FALSE;
}
if (list->HKLM != HKEY_LOCAL_MACHINE)
RegCloseKey(list->HKLM);
CM_Disconnect_Machine(list->hMachine);
DestroyClassInstallParams(&list->ClassInstallParams);
return HeapFree(GetProcessHeap(), 0, list);
}
/***********************************************************************
* SetupDiBuildClassInfoList (SETUPAPI.@)
*
* Returns a list of setup class GUIDs that identify the classes
* that are installed on a local machine.
*
* PARAMS
* Flags [I] control exclusion of classes from the list.
* ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
* ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
* RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*/
BOOL WINAPI SetupDiBuildClassInfoList(
DWORD Flags,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize)
{
TRACE("\n");
return SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
ClassGuidListSize, RequiredSize,
NULL, NULL);
}
/***********************************************************************
* SetupDiBuildClassInfoListExA (SETUPAPI.@)
*
* Returns a list of setup class GUIDs that identify the classes
* that are installed on a local or remote macine.
*
* PARAMS
* Flags [I] control exclusion of classes from the list.
* ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
* ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
* RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
* MachineName [I] name of a remote machine.
* Reserved [I] must be NULL.
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*/
BOOL WINAPI SetupDiBuildClassInfoListExA(
DWORD Flags,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize,
LPCSTR MachineName,
PVOID Reserved)
{
LPWSTR MachineNameW = NULL;
BOOL bResult;
TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
if (MachineName)
{
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
if (MachineNameW == NULL) return FALSE;
}
bResult = SetupDiBuildClassInfoListExW(Flags, ClassGuidList,
ClassGuidListSize, RequiredSize,
MachineNameW, Reserved);
MyFree(MachineNameW);
return bResult;
}
/***********************************************************************
* SetupDiBuildClassInfoListExW (SETUPAPI.@)
*
* Returns a list of setup class GUIDs that identify the classes
* that are installed on a local or remote macine.
*
* PARAMS
* Flags [I] control exclusion of classes from the list.
* ClassGuidList [O] pointer to a GUID-typed array that receives a list of setup class GUIDs.
* ClassGuidListSize [I] The number of GUIDs in the array (ClassGuidList).
* RequiredSize [O] pointer, which receives the number of GUIDs that are returned.
* MachineName [I] name of a remote machine.
* Reserved [I] must be NULL.
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*/
BOOL WINAPI SetupDiBuildClassInfoListExW(
DWORD Flags,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize,
LPCWSTR MachineName,
PVOID Reserved)
{
WCHAR szKeyName[40];
HKEY hClassesKey = INVALID_HANDLE_VALUE;
HKEY hClassKey;
DWORD dwLength;
DWORD dwIndex;
LONG lError;
DWORD dwGuidListIndex = 0;
TRACE("0x%lx %p %lu %p %s %p\n", Flags, ClassGuidList,
ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
if (!RequiredSize)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
else if (!ClassGuidList && ClassGuidListSize > 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
KEY_ENUMERATE_SUB_KEYS,
DIOCR_INSTALLER,
MachineName,
Reserved);
if (hClassesKey == INVALID_HANDLE_VALUE)
{
return FALSE;
}
for (dwIndex = 0; ; dwIndex++)
{
dwLength = 40;
lError = RegEnumKeyExW(hClassesKey,
dwIndex,
szKeyName,
&dwLength,
NULL,
NULL,
NULL,
NULL);
TRACE("RegEnumKeyExW() returns %d\n", lError);
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
{
TRACE("Key name: %s\n", debugstr_w(szKeyName));
if (RegOpenKeyExW(hClassesKey,
szKeyName,
0,
KEY_QUERY_VALUE,
&hClassKey))
{
RegCloseKey(hClassesKey);
return FALSE;
}
if (!RegQueryValueExW(hClassKey,
REGSTR_VAL_NOUSECLASS,
NULL,
NULL,
NULL,
NULL))
{
TRACE("'NoUseClass' value found!\n");
RegCloseKey(hClassKey);
continue;
}
if ((Flags & DIBCI_NOINSTALLCLASS) &&
(!RegQueryValueExW(hClassKey,
REGSTR_VAL_NOINSTALLCLASS,
NULL,
NULL,
NULL,
NULL)))
{
TRACE("'NoInstallClass' value found!\n");
RegCloseKey(hClassKey);
continue;
}
if ((Flags & DIBCI_NODISPLAYCLASS) &&
(!RegQueryValueExW(hClassKey,
REGSTR_VAL_NODISPLAYCLASS,
NULL,
NULL,
NULL,
NULL)))
{
TRACE("'NoDisplayClass' value found!\n");
RegCloseKey(hClassKey);
continue;
}
RegCloseKey(hClassKey);
TRACE("Guid: %s\n", debugstr_w(szKeyName));
if (dwGuidListIndex < ClassGuidListSize)
{
if (szKeyName[0] == '{' && szKeyName[37] == '}')
{
szKeyName[37] = 0;
}
TRACE("Guid: %p\n", &szKeyName[1]);
UuidFromStringW(&szKeyName[1],
&ClassGuidList[dwGuidListIndex]);
}
dwGuidListIndex++;
}
if (lError != ERROR_SUCCESS)
break;
}
RegCloseKey(hClassesKey);
if (RequiredSize != NULL)
*RequiredSize = dwGuidListIndex;
if (ClassGuidListSize < dwGuidListIndex)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return TRUE;
}
/***********************************************************************
* SetupDiClassGuidsFromNameA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassGuidsFromNameA(
LPCSTR ClassName,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize)
{
return SetupDiClassGuidsFromNameExA(ClassName, ClassGuidList,
ClassGuidListSize, RequiredSize,
NULL, NULL);
}
/***********************************************************************
* SetupDiClassGuidsFromNameW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassGuidsFromNameW(
LPCWSTR ClassName,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize)
{
return SetupDiClassGuidsFromNameExW(ClassName, ClassGuidList,
ClassGuidListSize, RequiredSize,
NULL, NULL);
}
/***********************************************************************
* SetupDiClassGuidsFromNameExA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassGuidsFromNameExA(
LPCSTR ClassName,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize,
LPCSTR MachineName,
PVOID Reserved)
{
LPWSTR ClassNameW = NULL;
LPWSTR MachineNameW = NULL;
BOOL bResult;
TRACE("%s %p %lu %p %s %p\n", debugstr_a(ClassName), ClassGuidList,
ClassGuidListSize, RequiredSize, debugstr_a(MachineName), Reserved);
if (!ClassName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
ClassNameW = pSetupMultiByteToUnicode(ClassName, CP_ACP);
if (ClassNameW == NULL)
return FALSE;
if (MachineName)
{
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
if (MachineNameW == NULL)
{
MyFree(ClassNameW);
return FALSE;
}
}
bResult = SetupDiClassGuidsFromNameExW(ClassNameW, ClassGuidList,
ClassGuidListSize, RequiredSize,
MachineNameW, Reserved);
MyFree(MachineNameW);
MyFree(ClassNameW);
return bResult;
}
/***********************************************************************
* SetupDiClassGuidsFromNameExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassGuidsFromNameExW(
LPCWSTR ClassName,
LPGUID ClassGuidList,
DWORD ClassGuidListSize,
PDWORD RequiredSize,
LPCWSTR MachineName,
PVOID Reserved)
{
WCHAR szKeyName[40];
WCHAR szClassName[MAX_CLASS_NAME_LEN];
HKEY hClassesKey;
HKEY hClassKey;
DWORD dwLength;
DWORD dwIndex;
LONG lError;
DWORD dwGuidListIndex = 0;
TRACE("%s %p %lu %p %s %p\n", debugstr_w(ClassName), ClassGuidList,
ClassGuidListSize, RequiredSize, debugstr_w(MachineName), Reserved);
if (!ClassName || !RequiredSize)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!ClassGuidList && ClassGuidListSize > 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*RequiredSize = 0;
hClassesKey = SetupDiOpenClassRegKeyExW(NULL,
KEY_ENUMERATE_SUB_KEYS,
DIOCR_INSTALLER,
MachineName,
Reserved);
if (hClassesKey == INVALID_HANDLE_VALUE)
{
return FALSE;
}
for (dwIndex = 0; ; dwIndex++)
{
dwLength = 40;
lError = RegEnumKeyExW(hClassesKey,
dwIndex,
szKeyName,
&dwLength,
NULL,
NULL,
NULL,
NULL);
TRACE("RegEnumKeyExW() returns %d\n", lError);
if (lError == ERROR_SUCCESS || lError == ERROR_MORE_DATA)
{
TRACE("Key name: %p\n", szKeyName);
if (RegOpenKeyExW(hClassesKey,
szKeyName,
0,
KEY_QUERY_VALUE,
&hClassKey))
{
RegCloseKey(hClassesKey);
return FALSE;
}
dwLength = MAX_CLASS_NAME_LEN * sizeof(WCHAR);
if (!RegQueryValueExW(hClassKey,
Class,
NULL,
NULL,
(LPBYTE)szClassName,
&dwLength))
{
TRACE("Class name: %p\n", szClassName);
if (strcmpiW(szClassName, ClassName) == 0)
{
TRACE("Found matching class name\n");
TRACE("Guid: %p\n", szKeyName);
if (dwGuidListIndex < ClassGuidListSize)
{
if (szKeyName[0] == '{' && szKeyName[37] == '}')
{
szKeyName[37] = 0;
}
TRACE("Guid: %p\n", &szKeyName[1]);
UuidFromStringW(&szKeyName[1],
&ClassGuidList[dwGuidListIndex]);
}
dwGuidListIndex++;
}
}
RegCloseKey(hClassKey);
}
if (lError != ERROR_SUCCESS)
break;
}
RegCloseKey(hClassesKey);
if (RequiredSize != NULL)
*RequiredSize = dwGuidListIndex;
if (ClassGuidListSize < dwGuidListIndex)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return TRUE;
}
/***********************************************************************
* SetupDiClassNameFromGuidA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassNameFromGuidA(
const GUID* ClassGuid,
PSTR ClassName,
DWORD ClassNameSize,
PDWORD RequiredSize)
{
return SetupDiClassNameFromGuidExA(ClassGuid, ClassName,
ClassNameSize, RequiredSize,
NULL, NULL);
}
/***********************************************************************
* SetupDiClassNameFromGuidW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassNameFromGuidW(
const GUID* ClassGuid,
PWSTR ClassName,
DWORD ClassNameSize,
PDWORD RequiredSize)
{
return SetupDiClassNameFromGuidExW(ClassGuid, ClassName,
ClassNameSize, RequiredSize,
NULL, NULL);
}
/***********************************************************************
* SetupDiClassNameFromGuidExA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassNameFromGuidExA(
const GUID* ClassGuid,
PSTR ClassName,
DWORD ClassNameSize,
PDWORD RequiredSize,
PCSTR MachineName,
PVOID Reserved)
{
WCHAR ClassNameW[MAX_CLASS_NAME_LEN];
LPWSTR MachineNameW = NULL;
BOOL ret;
if (MachineName)
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
ret = SetupDiClassNameFromGuidExW(ClassGuid, ClassNameW, MAX_CLASS_NAME_LEN,
RequiredSize, MachineNameW, Reserved);
if (ret)
{
int len = WideCharToMultiByte(CP_ACP, 0, ClassNameW, -1, ClassName,
ClassNameSize, NULL, NULL);
if (len == 0 || len > ClassNameSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
ret = FALSE;
}
}
MyFree(MachineNameW);
return ret;
}
/***********************************************************************
* SetupDiClassNameFromGuidExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiClassNameFromGuidExW(
const GUID* ClassGuid,
PWSTR ClassName,
DWORD ClassNameSize,
PDWORD RequiredSize,
PCWSTR MachineName,
PVOID Reserved)
{
HKEY hKey;
DWORD dwLength;
DWORD dwRegType;
LONG rc;
PWSTR Buffer;
TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassName,
ClassNameSize, RequiredSize, debugstr_w(MachineName), Reserved);
/* Make sure there's a GUID */
if (ClassGuid == NULL)
{
SetLastError(ERROR_INVALID_CLASS); /* On Vista: ERROR_INVALID_USER_BUFFER */
return FALSE;
}
/* Make sure there's a real buffer when there's a size */
if ((ClassNameSize > 0) && (ClassName == NULL))
{
SetLastError(ERROR_INVALID_PARAMETER); /* On Vista: ERROR_INVALID_USER_BUFFER */
return FALSE;
}
/* Open the key for the GUID */
hKey = SetupDiOpenClassRegKeyExW(ClassGuid, KEY_QUERY_VALUE, DIOCR_INSTALLER, MachineName, Reserved);
if (hKey == INVALID_HANDLE_VALUE)
return FALSE;
/* Retrieve the class name data and close the key */
rc = QueryRegistryValue(hKey, Class, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
RegCloseKey(hKey);
/* Make sure we got the data */
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
return FALSE;
}
/* Make sure the data is a string */
if (dwRegType != REG_SZ)
{
MyFree(Buffer);
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
/* Determine the length of the class name */
dwLength /= sizeof(WCHAR);
if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
/* Count the null-terminator */
dwLength++;
/* Inform the caller about the class name */
if ((ClassName != NULL) && (dwLength <= ClassNameSize))
{
memcpy(ClassName, Buffer, (dwLength - 1) * sizeof(WCHAR));
ClassName[dwLength - 1] = UNICODE_NULL;
}
/* Inform the caller about the required size */
if (RequiredSize != NULL)
*RequiredSize = dwLength;
/* Clean up the buffer */
MyFree(Buffer);
/* Make sure the buffer was large enough */
if ((ClassName == NULL) || (dwLength > ClassNameSize))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return TRUE;
}
/***********************************************************************
* SetupDiCreateDeviceInfoList (SETUPAPI.@)
*/
HDEVINFO WINAPI
SetupDiCreateDeviceInfoList(const GUID *ClassGuid,
HWND hwndParent)
{
return SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent, NULL, NULL);
}
/***********************************************************************
* SetupDiCreateDeviceInfoListExA (SETUPAPI.@)
*/
HDEVINFO WINAPI
SetupDiCreateDeviceInfoListExA(const GUID *ClassGuid,
HWND hwndParent,
PCSTR MachineName,
PVOID Reserved)
{
LPWSTR MachineNameW = NULL;
HDEVINFO hDevInfo;
TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
debugstr_a(MachineName), Reserved);
if (MachineName)
{
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
if (MachineNameW == NULL)
return INVALID_HANDLE_VALUE;
}
hDevInfo = SetupDiCreateDeviceInfoListExW(ClassGuid, hwndParent,
MachineNameW, Reserved);
MyFree(MachineNameW);
return hDevInfo;
}
/***********************************************************************
* SetupDiCreateDeviceInfoListExW (SETUPAPI.@)
*
* Create an empty DeviceInfoSet list.
*
* PARAMS
* ClassGuid [I] if not NULL only devices with GUID ClcassGuid are associated
* with this list.
* hwndParent [I] hwnd needed for interface related actions.
* MachineName [I] name of machine to create emtpy DeviceInfoSet list, if NULL
* local registry will be used.
* Reserved [I] must be NULL
*
* RETURNS
* Success: empty list.
* Failure: INVALID_HANDLE_VALUE.
*/
HDEVINFO WINAPI
SetupDiCreateDeviceInfoListExW(const GUID *ClassGuid,
HWND hwndParent,
PCWSTR MachineName,
PVOID Reserved)
{
struct DeviceInfoSet *list = NULL;
DWORD size = FIELD_OFFSET(struct DeviceInfoSet, szData);
DWORD rc;
CONFIGRET cr;
HDEVINFO ret = INVALID_HANDLE_VALUE;
TRACE("%s %p %s %p\n", debugstr_guid(ClassGuid), hwndParent,
debugstr_w(MachineName), Reserved);
if (MachineName != NULL)
{
SIZE_T len = strlenW(MachineName);
if (len >= SP_MAX_MACHINENAME_LENGTH - 4)
{
SetLastError(ERROR_INVALID_MACHINENAME);
goto cleanup;
}
if(len > 0)
size += (len + 3) * sizeof(WCHAR);
else
MachineName = NULL;
}
if (Reserved != NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
list = MyMalloc(size);
if (!list)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
ZeroMemory(list, FIELD_OFFSET(struct DeviceInfoSet, szData));
list->magic = SETUP_DEVICE_INFO_SET_MAGIC;
memcpy(&list->ClassGuid,
ClassGuid ? ClassGuid : &GUID_NULL,
sizeof(list->ClassGuid));
list->InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
list->InstallParams.Flags |= DI_CLASSINSTALLPARAMS;
list->InstallParams.hwndParent = hwndParent;
if (MachineName)
{
rc = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &list->HKLM);
if (rc != ERROR_SUCCESS)
{
SetLastError(ERROR_INVALID_MACHINENAME);
goto cleanup;
}
list->szData[0] = list->szData[1] = '\\';
strcpyW(list->szData + 2, MachineName);
list->MachineName = list->szData;
}
else
{
list->HKLM = HKEY_LOCAL_MACHINE;
list->MachineName = NULL;
}
cr = CM_Connect_MachineW(list->MachineName, &list->hMachine);
if (cr != CR_SUCCESS)
{
SetLastError(GetErrorCodeFromCrCode(cr));
goto cleanup;
}
InitializeListHead(&list->DriverListHead);
InitializeListHead(&list->ListHead);
return (HDEVINFO)list;
cleanup:
if (ret == INVALID_HANDLE_VALUE)
{
if (list)
{
if (list->HKLM != NULL && list->HKLM != HKEY_LOCAL_MACHINE)
RegCloseKey(list->HKLM);
MyFree(list);
}
}
return ret;
}
/***********************************************************************
* SetupDiCreateDevRegKeyA (SETUPAPI.@)
*/
HKEY WINAPI SetupDiCreateDevRegKeyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
HINF InfHandle,
PCSTR InfSectionName)
{
PWSTR InfSectionNameW = NULL;
HKEY key;
TRACE("%p %p %d %d %d %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
HwProfile, KeyType, InfHandle, debugstr_a(InfSectionName));
if (InfHandle)
{
if (!InfSectionName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
else
{
InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
if (InfSectionNameW == NULL) return INVALID_HANDLE_VALUE;
}
}
key = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, Scope,
HwProfile, KeyType, InfHandle, InfSectionNameW);
MyFree(InfSectionNameW);
return key;
}
static HKEY
OpenHardwareProfileKey(
IN HKEY HKLM,
IN DWORD HwProfile,
IN DWORD samDesired);
/***********************************************************************
* SetupDiCreateDevRegKeyW (SETUPAPI.@)
*/
HKEY WINAPI SetupDiCreateDevRegKeyW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
HINF InfHandle,
PCWSTR InfSectionName)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
HKEY key = INVALID_HANDLE_VALUE;
LPWSTR lpGuidString = NULL;
LPWSTR DriverKey = NULL; /* {GUID}\Index */
LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
DWORD Index; /* Index used in the DriverKey name */
DWORD dwSize;
DWORD Disposition;
DWORD rc;
HKEY hHWProfileKey = INVALID_HANDLE_VALUE;
HKEY hEnumKey = NULL;
HKEY hClassKey = NULL;
HKEY hDeviceKey = INVALID_HANDLE_VALUE;
HKEY hKey = NULL;
HKEY RootKey;
TRACE("%p %p %lu %lu %lu %p %s\n", DeviceInfoSet, DeviceInfoData, Scope,
HwProfile, KeyType, InfHandle, debugstr_w(InfSectionName));
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
{
SetLastError(ERROR_INVALID_FLAGS);
return INVALID_HANDLE_VALUE;
}
if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
{
SetLastError(ERROR_INVALID_FLAGS);
return INVALID_HANDLE_VALUE;
}
if (InfHandle && !InfSectionName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (!InfHandle && InfSectionName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (Scope == DICS_FLAG_GLOBAL)
RootKey = set->HKLM;
else /* Scope == DICS_FLAG_CONFIGSPECIFIC */
{
hHWProfileKey = OpenHardwareProfileKey(set->HKLM, HwProfile, KEY_CREATE_SUB_KEY);
if (hHWProfileKey == INVALID_HANDLE_VALUE)
goto cleanup;
RootKey = hHWProfileKey;
}
if (KeyType == DIREG_DEV)
{
struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
rc = RegCreateKeyExW(
RootKey,
REGSTR_PATH_SYSTEMENUM,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_CREATE_SUB_KEY,
NULL,
&hEnumKey,
NULL);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
rc = RegCreateKeyExW(
hEnumKey,
deviceInfo->instanceId,
0,
NULL,
REG_OPTION_NON_VOLATILE,
#if _WIN32_WINNT >= 0x502
KEY_READ | KEY_WRITE,
#else
KEY_ALL_ACCESS,
#endif
NULL,
&hKey,
NULL);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
}
else /* KeyType == DIREG_DRV */
{
/* Open device key, to read Driver value */
hDeviceKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, Scope, HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
if (hDeviceKey == INVALID_HANDLE_VALUE)
goto cleanup;
rc = RegOpenKeyExW(RootKey, REGSTR_PATH_CLASS_NT, 0, KEY_CREATE_SUB_KEY, &hClassKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, NULL, &dwSize);
if (rc != ERROR_SUCCESS)
{
/* Create a new driver key */
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) != RPC_S_OK)
goto cleanup;
/* The driver key is in \System\CurrentControlSet\Control\Class\{GUID}\Index */
DriverKey = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpGuidString) + 7) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
if (!DriverKey)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
DriverKey[0] = '{';
strcpyW(&DriverKey[1], lpGuidString);
pDeviceInstance = &DriverKey[strlenW(DriverKey)];
*pDeviceInstance++ = '}';
*pDeviceInstance++ = '\\';
/* Try all values for Index between 0 and 9999 */
Index = 0;
while (Index <= 9999)
{
sprintfW(pDeviceInstance, InstanceKeyFormat, Index);
rc = RegCreateKeyExW(hClassKey,
DriverKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
#if _WIN32_WINNT >= 0x502
KEY_READ | KEY_WRITE,
#else
KEY_ALL_ACCESS,
#endif
NULL,
&hKey,
&Disposition);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
if (Disposition == REG_CREATED_NEW_KEY)
break;
RegCloseKey(hKey);
hKey = NULL;
Index++;
}
if (Index > 9999)
{
/* Unable to create more than 9999 devices within the same class */
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
/* Write the new Driver value */
rc = RegSetValueExW(hDeviceKey, REGSTR_VAL_DRIVER, 0, REG_SZ, (const BYTE *)DriverKey, (strlenW(DriverKey) + 1) * sizeof(WCHAR));
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
}
else
{
/* Open the existing driver key */
DriverKey = HeapAlloc(GetProcessHeap(), 0, dwSize);
if (!DriverKey)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
rc = RegQueryValueExW(hDeviceKey, REGSTR_VAL_DRIVER, NULL, NULL, (LPBYTE)DriverKey, &dwSize);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
rc = RegCreateKeyExW(hClassKey,
DriverKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
#if _WIN32_WINNT >= 0x502
KEY_READ | KEY_WRITE,
#else
KEY_ALL_ACCESS,
#endif
NULL,
&hKey,
&Disposition);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
}
}
/* Do installation of the specified section */
if (InfHandle)
{
FIXME("Need to install section %s in file %p\n",
debugstr_w(InfSectionName), InfHandle);
}
key = hKey;
cleanup:
if (lpGuidString)
RpcStringFreeW(&lpGuidString);
HeapFree(GetProcessHeap(), 0, DriverKey);
if (hHWProfileKey != INVALID_HANDLE_VALUE)
RegCloseKey(hHWProfileKey);
if (hEnumKey != NULL)
RegCloseKey(hEnumKey);
if (hClassKey != NULL)
RegCloseKey(hClassKey);
if (hDeviceKey != INVALID_HANDLE_VALUE)
RegCloseKey(hDeviceKey);
if (hKey != NULL && hKey != key)
RegCloseKey(hKey);
TRACE("Returning 0x%p\n", key);
return key;
}
/***********************************************************************
* SetupDiCreateDeviceInfoA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCreateDeviceInfoA(
HDEVINFO DeviceInfoSet,
PCSTR DeviceName,
CONST GUID *ClassGuid,
PCSTR DeviceDescription,
HWND hwndParent,
DWORD CreationFlags,
PSP_DEVINFO_DATA DeviceInfoData)
{
BOOL ret;
LPWSTR DeviceNameW = NULL;
LPWSTR DeviceDescriptionW = NULL;
TRACE("\n");
if (DeviceName)
{
DeviceNameW = pSetupMultiByteToUnicode(DeviceName, CP_ACP);
if (DeviceNameW == NULL) return FALSE;
}
if (DeviceDescription)
{
DeviceDescriptionW = pSetupMultiByteToUnicode(DeviceDescription, CP_ACP);
if (DeviceDescriptionW == NULL)
{
MyFree(DeviceNameW);
return FALSE;
}
}
ret = SetupDiCreateDeviceInfoW(DeviceInfoSet, DeviceNameW, ClassGuid, DeviceDescriptionW,
hwndParent, CreationFlags, DeviceInfoData);
MyFree(DeviceNameW);
MyFree(DeviceDescriptionW);
return ret;
}
/***********************************************************************
* SetupDiCreateDeviceInfoW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCreateDeviceInfoW(
HDEVINFO DeviceInfoSet,
PCWSTR DeviceName,
CONST GUID *ClassGuid,
PCWSTR DeviceDescription,
HWND hwndParent,
DWORD CreationFlags,
PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
struct DeviceInfo *deviceInfo = NULL;
BOOL ret = FALSE;
CONFIGRET cr;
DEVINST RootDevInst;
DEVINST DevInst;
TRACE("%p %s %s %s %p %x %p\n", DeviceInfoSet, debugstr_w(DeviceName),
debugstr_guid(ClassGuid), debugstr_w(DeviceDescription),
hwndParent, CreationFlags, DeviceInfoData);
if (!DeviceName)
{
SetLastError(ERROR_INVALID_DEVINST_NAME);
return FALSE;
}
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!ClassGuid)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!IsEqualGUID(&set->ClassGuid, &GUID_NULL) &&
!IsEqualGUID(ClassGuid, &set->ClassGuid))
{
SetLastError(ERROR_CLASS_MISMATCH);
return FALSE;
}
if (CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS))
{
TRACE("Unknown flags: 0x%08lx\n", CreationFlags & ~(DICD_GENERATE_ID | DICD_INHERIT_CLASSDRVS));
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
/* Get the root device instance */
cr = CM_Locate_DevInst_ExW(&RootDevInst,
NULL,
CM_LOCATE_DEVINST_NORMAL,
set->hMachine);
if (cr != CR_SUCCESS)
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
/* Create the new device instance */
cr = CM_Create_DevInst_ExW(&DevInst,
(DEVINSTID)DeviceName,
RootDevInst,
0,
set->hMachine);
if (cr != CR_SUCCESS)
{
SetLastError(GetErrorCodeFromCrCode(cr));
return FALSE;
}
if (CreateDeviceInfo(set, DeviceName, ClassGuid, &deviceInfo))
{
InsertTailList(&set->ListHead, &deviceInfo->ListEntry);
if (!DeviceInfoData)
ret = TRUE;
else
{
if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
{
SetLastError(ERROR_INVALID_USER_BUFFER);
}
else
{
memcpy(&DeviceInfoData->ClassGuid, ClassGuid, sizeof(GUID));
DeviceInfoData->DevInst = deviceInfo->dnDevInst;
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
ret = TRUE;
}
}
}
if (ret == FALSE)
{
if (deviceInfo != NULL)
{
/* Remove deviceInfo from List */
RemoveEntryList(&deviceInfo->ListEntry);
/* Destroy deviceInfo */
DestroyDeviceInfo(deviceInfo);
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiRegisterDeviceInfo (SETUPAPI.@)
*/
BOOL WINAPI SetupDiRegisterDeviceInfo(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Flags,
PSP_DETSIG_CMPPROC CompareProc,
PVOID CompareContext,
PSP_DEVINFO_DATA DupDeviceInfoData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
WCHAR DevInstId[MAX_DEVICE_ID_LEN];
DEVINST ParentDevInst;
CONFIGRET cr;
DWORD dwError = ERROR_SUCCESS;
TRACE("%p %p %08x %p %p %p\n", DeviceInfoSet, DeviceInfoData, Flags,
CompareProc, CompareContext, DupDeviceInfoData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Flags & ~SPRDI_FIND_DUPS)
{
TRACE("Unknown flags: 0x%08lx\n", Flags & ~SPRDI_FIND_DUPS);
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
if (Flags & SPRDI_FIND_DUPS)
{
FIXME("Unimplemented codepath!\n");
}
CM_Get_Device_ID_Ex(DeviceInfoData->DevInst,
DevInstId,
MAX_DEVICE_ID_LEN,
0,
set->hMachine);
CM_Get_Parent_Ex(&ParentDevInst,
DeviceInfoData->DevInst,
0,
set->hMachine);
cr = CM_Create_DevInst_Ex(&DeviceInfoData->DevInst,
DevInstId,
ParentDevInst,
CM_CREATE_DEVINST_NORMAL | CM_CREATE_DEVINST_DO_NOT_INSTALL,
set->hMachine);
if (cr != CR_SUCCESS)
{
dwError = ERROR_NO_SUCH_DEVINST;
}
SetLastError(dwError);
return (dwError == ERROR_SUCCESS);
}
/***********************************************************************
* SetupDiEnumDeviceInfo (SETUPAPI.@)
*/
BOOL WINAPI SetupDiEnumDeviceInfo(
HDEVINFO devinfo,
DWORD index,
PSP_DEVINFO_DATA info)
{
BOOL ret = FALSE;
TRACE("%p %d %p\n", devinfo, index, info);
if(info==NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (devinfo && devinfo != INVALID_HANDLE_VALUE)
{
struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
{
if (info->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
PLIST_ENTRY ItemList = list->ListHead.Flink;
while (ItemList != &list->ListHead && index-- > 0)
ItemList = ItemList->Flink;
if (ItemList == &list->ListHead)
SetLastError(ERROR_NO_MORE_ITEMS);
else
{
struct DeviceInfo *DevInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
memcpy(&info->ClassGuid,
&DevInfo->ClassGuid,
sizeof(GUID));
info->DevInst = DevInfo->dnDevInst;
info->Reserved = (ULONG_PTR)DevInfo;
ret = TRUE;
}
}
}
else
SetLastError(ERROR_INVALID_HANDLE);
}
else
SetLastError(ERROR_INVALID_HANDLE);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInstanceIdA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInstanceIdA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PSTR DeviceInstanceId,
DWORD DeviceInstanceIdSize,
PDWORD RequiredSize)
{
BOOL ret = FALSE;
DWORD size;
PWSTR instanceId;
TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
DeviceInstanceIdSize, RequiredSize);
if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
DeviceInfoData,
NULL,
0,
&size);
if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
instanceId = MyMalloc(size * sizeof(WCHAR));
if (instanceId)
{
ret = SetupDiGetDeviceInstanceIdW(DeviceInfoSet,
DeviceInfoData,
instanceId,
size,
&size);
if (ret)
{
int len = WideCharToMultiByte(CP_ACP, 0, instanceId, -1,
DeviceInstanceId,
DeviceInstanceIdSize, NULL, NULL);
if (!len)
ret = FALSE;
else
{
if (len > DeviceInstanceIdSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
ret = FALSE;
}
if (RequiredSize)
*RequiredSize = len;
}
}
MyFree(instanceId);
}
else
{
if (RequiredSize)
*RequiredSize = size;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
ret = FALSE;
}
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInstanceIdW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInstanceIdW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PWSTR DeviceInstanceId,
DWORD DeviceInstanceIdSize,
PDWORD RequiredSize)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
struct DeviceInfo *devInfo;
TRACE("%p %p %p %d %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstanceId,
DeviceInstanceIdSize, RequiredSize);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (!DeviceInstanceId && DeviceInstanceIdSize > 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DeviceInstanceId && DeviceInstanceIdSize == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
TRACE("instance ID: %s\n", debugstr_w(devInfo->instanceId));
if (DeviceInstanceIdSize < lstrlenW(devInfo->instanceId) + 1)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
if (RequiredSize)
*RequiredSize = lstrlenW(devInfo->instanceId) + 1;
return FALSE;
}
lstrcpyW(DeviceInstanceId, devInfo->instanceId);
if (RequiredSize)
*RequiredSize = lstrlenW(devInfo->instanceId) + 1;
return TRUE;
}
/***********************************************************************
* SetupDiGetActualSectionToInstallA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetActualSectionToInstallA(
HINF InfHandle,
PCSTR InfSectionName,
PSTR InfSectionWithExt,
DWORD InfSectionWithExtSize,
PDWORD RequiredSize,
PSTR *Extension)
{
return SetupDiGetActualSectionToInstallExA(InfHandle, InfSectionName,
NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
Extension, NULL);
}
/***********************************************************************
* SetupDiGetActualSectionToInstallW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetActualSectionToInstallW(
HINF InfHandle,
PCWSTR InfSectionName,
PWSTR InfSectionWithExt,
DWORD InfSectionWithExtSize,
PDWORD RequiredSize,
PWSTR *Extension)
{
return SetupDiGetActualSectionToInstallExW(InfHandle, InfSectionName,
NULL, InfSectionWithExt, InfSectionWithExtSize, RequiredSize,
Extension, NULL);
}
/***********************************************************************
* SetupDiGetActualSectionToInstallExA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetActualSectionToInstallExA(
IN HINF InfHandle,
IN PCSTR InfSectionName,
IN PSP_ALTPLATFORM_INFO AlternatePlatformInfo OPTIONAL,
OUT PSTR InfSectionWithExt OPTIONAL,
IN DWORD InfSectionWithExtSize,
OUT PDWORD RequiredSize OPTIONAL,
OUT PSTR* Extension OPTIONAL,
IN PVOID Reserved)
{
LPWSTR InfSectionNameW = NULL;
LPWSTR InfSectionWithExtW = NULL;
PWSTR ExtensionW;
BOOL bResult = FALSE;
TRACE("\n");
if (InfSectionName)
{
InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
if (InfSectionNameW == NULL)
goto cleanup;
}
if (InfSectionWithExt)
{
InfSectionWithExtW = MyMalloc(InfSectionWithExtSize * sizeof(WCHAR));
if (InfSectionWithExtW == NULL)
goto cleanup;
}
bResult = SetupDiGetActualSectionToInstallExW(
InfHandle, InfSectionNameW, AlternatePlatformInfo,
InfSectionWithExt ? InfSectionWithExtW : NULL,
InfSectionWithExtSize,
RequiredSize,
Extension ? &ExtensionW : NULL,
Reserved);
if (bResult && InfSectionWithExt)
{
bResult = WideCharToMultiByte(CP_ACP, 0, InfSectionWithExtW, -1, InfSectionWithExt,
InfSectionWithExtSize, NULL, NULL) != 0;
}
if (bResult && Extension)
{
if (ExtensionW == NULL)
*Extension = NULL;
else
*Extension = &InfSectionWithExt[ExtensionW - InfSectionWithExtW];
}
cleanup:
MyFree(InfSectionNameW);
MyFree(InfSectionWithExtW);
return bResult;
}
/***********************************************************************
* SetupDiGetClassDescriptionA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetClassDescriptionA(
const GUID* ClassGuid,
PSTR ClassDescription,
DWORD ClassDescriptionSize,
PDWORD RequiredSize)
{
return SetupDiGetClassDescriptionExA(ClassGuid, ClassDescription,
ClassDescriptionSize,
RequiredSize, NULL, NULL);
}
/***********************************************************************
* SetupDiGetClassDescriptionW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetClassDescriptionW(
const GUID* ClassGuid,
PWSTR ClassDescription,
DWORD ClassDescriptionSize,
PDWORD RequiredSize)
{
return SetupDiGetClassDescriptionExW(ClassGuid, ClassDescription,
ClassDescriptionSize,
RequiredSize, NULL, NULL);
}
/***********************************************************************
* SetupDiGetClassDescriptionExA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetClassDescriptionExA(
const GUID* ClassGuid,
PSTR ClassDescription,
DWORD ClassDescriptionSize,
PDWORD RequiredSize,
PCSTR MachineName,
PVOID Reserved)
{
PWCHAR ClassDescriptionW = NULL;
LPWSTR MachineNameW = NULL;
BOOL ret = FALSE;
TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
ClassDescriptionSize, RequiredSize, debugstr_a(MachineName), Reserved);
if (ClassDescriptionSize > 0)
{
ClassDescriptionW = MyMalloc(ClassDescriptionSize * sizeof(WCHAR));
if (!ClassDescriptionW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
}
if (MachineName)
{
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
if (!MachineNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
}
ret = SetupDiGetClassDescriptionExW(ClassGuid, ClassDescriptionW,
ClassDescriptionSize * sizeof(WCHAR), RequiredSize, MachineNameW, Reserved);
if (ret)
{
DWORD len = (DWORD)WideCharToMultiByte(CP_ACP, 0, ClassDescriptionW, -1, ClassDescription,
ClassDescriptionSize, NULL, NULL);
if (len == 0 || len > ClassDescriptionSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
ret = FALSE;
}
}
cleanup:
MyFree(ClassDescriptionW);
MyFree(MachineNameW);
return ret;
}
/***********************************************************************
* SetupDiGetClassDescriptionExW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetClassDescriptionExW(
const GUID* ClassGuid,
PWSTR ClassDescription,
DWORD ClassDescriptionSize,
PDWORD RequiredSize,
PCWSTR MachineName,
PVOID Reserved)
{
HKEY hKey;
DWORD dwLength;
DWORD dwRegType;
LONG rc;
PWSTR Buffer;
TRACE("%s %p %lu %p %s %p\n", debugstr_guid(ClassGuid), ClassDescription,
ClassDescriptionSize, RequiredSize, debugstr_w(MachineName), Reserved);
/* Make sure there's a GUID */
if (!ClassGuid)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Make sure there's a real buffer when there's a size */
if (!ClassDescription && ClassDescriptionSize > 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Open the key for the GUID */
hKey = SetupDiOpenClassRegKeyExW(ClassGuid,
KEY_QUERY_VALUE,
DIOCR_INSTALLER,
MachineName,
Reserved);
if (hKey == INVALID_HANDLE_VALUE)
return FALSE;
/* Retrieve the class description data and close the key */
rc = QueryRegistryValue(hKey, NULL, (LPBYTE *) &Buffer, &dwRegType, &dwLength);
RegCloseKey(hKey);
/* Make sure we got the data */
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
return FALSE;
}
/* Make sure the data is a string */
if (dwRegType != REG_SZ)
{
MyFree(Buffer);
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
/* Determine the length of the class description */
dwLength /= sizeof(WCHAR);
/* Count the null-terminator if none is present */
if ((dwLength == 0) || (Buffer[dwLength - 1] != UNICODE_NULL))
dwLength++;
/* Inform the caller about the class description */
if ((ClassDescription != NULL) && (dwLength <= ClassDescriptionSize))
{
memcpy(ClassDescription, Buffer, (dwLength - 1) * sizeof(WCHAR));
ClassDescription[dwLength - 1] = UNICODE_NULL;
}
/* Inform the caller about the required size */
if (RequiredSize != NULL)
*RequiredSize = dwLength;
/* Clean up the buffer */
MyFree(Buffer);
/* Make sure the buffer was large enough */
if ((ClassDescription == NULL) || (dwLength > ClassDescriptionSize))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return TRUE;
}
/***********************************************************************
* SetupDiGetClassDevsA (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsA(
CONST GUID *class,
LPCSTR enumstr,
HWND parent,
DWORD flags)
{
return SetupDiGetClassDevsExA(class, enumstr, parent,
flags, NULL, NULL, NULL);
}
/***********************************************************************
* SetupDiGetClassDevsExA (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsExA(
const GUID *class,
PCSTR enumstr,
HWND parent,
DWORD flags,
HDEVINFO deviceset,
PCSTR machine,
PVOID reserved)
{
HDEVINFO ret;
LPWSTR enumstrW = NULL, machineW = NULL;
if (enumstr)
{
enumstrW = pSetupMultiByteToUnicode(enumstr, CP_ACP);
if (!enumstrW)
{
ret = INVALID_HANDLE_VALUE;
goto end;
}
}
if (machine)
{
machineW = pSetupMultiByteToUnicode(machine, CP_ACP);
if (!machineW)
{
MyFree(enumstrW);
ret = INVALID_HANDLE_VALUE;
goto end;
}
}
ret = SetupDiGetClassDevsExW(class, enumstrW, parent, flags, deviceset,
machineW, reserved);
MyFree(enumstrW);
MyFree(machineW);
end:
return ret;
}
/***********************************************************************
* SetupDiGetClassDevsW (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsW(
CONST GUID *class,
LPCWSTR enumstr,
HWND parent,
DWORD flags)
{
return SetupDiGetClassDevsExW(class, enumstr, parent, flags, NULL, NULL,
NULL);
}
/***********************************************************************
* SetupDiGetClassDevsExW (SETUPAPI.@)
*/
HDEVINFO WINAPI SetupDiGetClassDevsExW(
CONST GUID *class,
PCWSTR enumstr,
HWND parent,
DWORD flags,
HDEVINFO deviceset,
PCWSTR machine,
PVOID reserved)
{
HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
struct DeviceInfoSet *list;
CONST GUID *pClassGuid;
LONG rc;
HDEVINFO set = INVALID_HANDLE_VALUE;
TRACE("%s %s %p 0x%08x %p %s %p\n", debugstr_guid(class),
debugstr_w(enumstr), parent, flags, deviceset, debugstr_w(machine),
reserved);
if (!(flags & DIGCF_ALLCLASSES) && !class)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
/* Create the deviceset if not set */
if (deviceset)
{
list = (struct DeviceInfoSet *)deviceset;
if (list->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
goto cleanup;
}
hDeviceInfo = deviceset;
}
else
{
hDeviceInfo = SetupDiCreateDeviceInfoListExW(
flags & (DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES) ? NULL : class,
NULL, machine, NULL);
if (hDeviceInfo == INVALID_HANDLE_VALUE)
goto cleanup;
list = (struct DeviceInfoSet *)hDeviceInfo;
}
if (flags & DIGCF_PROFILE)
FIXME(": flag DIGCF_PROFILE ignored\n");
if (flags & DIGCF_DEVICEINTERFACE)
{
if (!class)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
rc = SETUP_CreateInterfaceList(list, machine, class, enumstr, flags & DIGCF_PRESENT);
}
else
{
/* Determine which class(es) should be included in the deviceset */
if (flags & DIGCF_ALLCLASSES)
{
/* The caller wants all classes. Check if
* the deviceset limits us to one class */
if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
pClassGuid = NULL;
else
pClassGuid = &list->ClassGuid;
}
else if (class)
{
/* The caller wants one class. Check if it matches deviceset class */
if (IsEqualIID(&list->ClassGuid, class)
|| IsEqualIID(&list->ClassGuid, &GUID_NULL))
{
pClassGuid = class;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
}
else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL))
{
/* No class specified. Try to use the one of the deviceset */
if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
pClassGuid = &list->ClassGuid;
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
rc = SETUP_CreateDevicesList(list, machine, pClassGuid, enumstr);
}
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
set = hDeviceInfo;
cleanup:
if (!deviceset && hDeviceInfo != INVALID_HANDLE_VALUE && hDeviceInfo != set)
SetupDiDestroyDeviceInfoList(hDeviceInfo);
return set;
}
/***********************************************************************
* SetupDiGetDeviceInfoListDetailA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInfoListDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_A DevInfoData )
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DevInfoData ||
DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_A))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
DevInfoData->RemoteMachineHandle = set->hMachine;
if (set->MachineName)
{
FIXME("Stub\n");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
else
DevInfoData->RemoteMachineName[0] = 0;
return TRUE;
}
/***********************************************************************
* SetupDiGetDeviceInfoListDetailW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInfoListDetailW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_LIST_DETAIL_DATA_W DevInfoData )
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p\n", DeviceInfoSet, DevInfoData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DevInfoData ||
DevInfoData->cbSize != sizeof(SP_DEVINFO_LIST_DETAIL_DATA_W))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy(&DevInfoData->ClassGuid, &set->ClassGuid, sizeof(GUID));
DevInfoData->RemoteMachineHandle = set->hMachine;
if (set->MachineName)
strcpyW(DevInfoData->RemoteMachineName, set->MachineName + 2);
else
DevInfoData->RemoteMachineName[0] = 0;
return TRUE;
}
/***********************************************************************
* SetupDiCreateDeviceInterfaceA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCreateDeviceInterfaceA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
const GUID *InterfaceClassGuid,
PCSTR ReferenceString,
DWORD CreationFlags,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
BOOL ret;
LPWSTR ReferenceStringW = NULL;
TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
debugstr_guid(InterfaceClassGuid), debugstr_a(ReferenceString),
CreationFlags, DeviceInterfaceData);
if (ReferenceString)
{
ReferenceStringW = pSetupMultiByteToUnicode(ReferenceString, CP_ACP);
if (ReferenceStringW == NULL) return FALSE;
}
ret = SetupDiCreateDeviceInterfaceW(DeviceInfoSet, DeviceInfoData,
InterfaceClassGuid, ReferenceStringW, CreationFlags,
DeviceInterfaceData);
MyFree(ReferenceStringW);
return ret;
}
/***********************************************************************
* SetupDiCreateDeviceInterfaceW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCreateDeviceInterfaceW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
const GUID *InterfaceClassGuid,
PCWSTR ReferenceString,
DWORD CreationFlags,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
CreationFlags, DeviceInterfaceData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!InterfaceClassGuid)
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
FIXME("%p %p %s %s %08x %p\n", DeviceInfoSet, DeviceInfoData,
debugstr_guid(InterfaceClassGuid), debugstr_w(ReferenceString),
CreationFlags, DeviceInterfaceData);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* SetupDiCreateDeviceInterfaceRegKeyA (SETUPAPI.@)
*/
HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyA(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
DWORD Reserved,
REGSAM samDesired,
HINF InfHandle,
PCSTR InfSectionName)
{
HKEY key;
PWSTR InfSectionNameW = NULL;
TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
samDesired, InfHandle, InfSectionName);
if (InfHandle)
{
if (!InfSectionName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
InfSectionNameW = pSetupMultiByteToUnicode(InfSectionName, CP_ACP);
if (!InfSectionNameW)
return INVALID_HANDLE_VALUE;
}
key = SetupDiCreateDeviceInterfaceRegKeyW(DeviceInfoSet,
DeviceInterfaceData, Reserved, samDesired, InfHandle,
InfSectionNameW);
MyFree(InfSectionNameW);
return key;
}
/***********************************************************************
* SetupDiCreateDeviceInterfaceRegKeyW (SETUPAPI.@)
*/
HKEY WINAPI SetupDiCreateDeviceInterfaceRegKeyW(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
DWORD Reserved,
REGSAM samDesired,
HINF InfHandle,
PCWSTR InfSectionName)
{
HKEY hKey, hDevKey;
LPWSTR SymbolicLink;
DWORD Length, Index;
LONG rc;
WCHAR bracedGuidString[39];
struct DeviceInterface *DevItf;
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p %d %08x %p %p\n", DeviceInfoSet, DeviceInterfaceData, Reserved,
samDesired, InfHandle, InfSectionName);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
if (!DeviceInterfaceData ||
DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
!DeviceInterfaceData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (InfHandle && !InfSectionName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
hKey = SetupDiOpenClassRegKeyExW(&DeviceInterfaceData->InterfaceClassGuid, samDesired, DIOCR_INTERFACE, NULL, NULL);
if (hKey == INVALID_HANDLE_VALUE)
{
hKey = SetupDiOpenClassRegKeyExW(NULL, samDesired, DIOCR_INTERFACE, NULL, NULL);
if (hKey == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
SETUPDI_GuidToString(&DeviceInterfaceData->InterfaceClassGuid, bracedGuidString);
if (RegCreateKeyExW(hKey, bracedGuidString, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL) != ERROR_SUCCESS)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
RegCloseKey(hKey);
hKey = hDevKey;
}
DevItf = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
Length = (wcslen(DevItf->SymbolicLink)+1) * sizeof(WCHAR);
SymbolicLink = HeapAlloc(GetProcessHeap(), 0, Length);
if (!SymbolicLink)
{
RegCloseKey(hKey);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
wcscpy(SymbolicLink, DevItf->SymbolicLink);
Index = 0;
while(SymbolicLink[Index])
{
if (SymbolicLink[Index] == L'\\')
{
SymbolicLink[Index] = L'#';
}
Index++;
}
rc = RegCreateKeyExW(hKey, SymbolicLink, 0, NULL, 0, samDesired, NULL, &hDevKey, NULL);
RegCloseKey(hKey);
HeapFree(GetProcessHeap(), 0, SymbolicLink);
if (rc == ERROR_SUCCESS)
{
if (InfHandle && InfSectionName)
{
if (!SetupInstallFromInfSection(NULL /*FIXME */,
InfHandle,
InfSectionName,
SPINST_INIFILES | SPINST_REGISTRY | SPINST_INI2REG | SPINST_FILES | SPINST_BITREG | SPINST_REGSVR | SPINST_UNREGSVR | SPINST_PROFILEITEMS | SPINST_COPYINF,
hDevKey,
NULL,
0,
set->SelectedDevice->InstallParams.InstallMsgHandler,
set->SelectedDevice->InstallParams.InstallMsgHandlerContext,
INVALID_HANDLE_VALUE,
NULL))
{
RegCloseKey(hDevKey);
return INVALID_HANDLE_VALUE;
}
}
}
SetLastError(rc);
return hDevKey;
}
/***********************************************************************
* SetupDiDeleteDeviceInterfaceRegKey (SETUPAPI.@)
*/
BOOL WINAPI SetupDiDeleteDeviceInterfaceRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
DWORD Reserved)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
BOOL ret = FALSE;
TRACE("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInterfaceData ||
DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
!DeviceInterfaceData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FIXME("%p %p %d\n", DeviceInfoSet, DeviceInterfaceData, Reserved);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return ret;
}
/***********************************************************************
* SetupDiEnumDeviceInterfaces (SETUPAPI.@)
*
* PARAMS
* DeviceInfoSet [I] Set of devices from which to enumerate
* interfaces
* DeviceInfoData [I] (Optional) If specified, a specific device
* instance from which to enumerate interfaces.
* If it isn't specified, all interfaces for all
* devices in the set are enumerated.
* InterfaceClassGuid [I] The interface class to enumerate.
* MemberIndex [I] An index of the interface instance to enumerate.
* A caller should start with MemberIndex set to 0,
* and continue until the function fails with
* ERROR_NO_MORE_ITEMS.
* DeviceInterfaceData [I/O] Returns an enumerated interface. Its cbSize
* member must be set to
* sizeof(SP_DEVICE_INTERFACE_DATA).
*
* RETURNS
* Success: non-zero value.
* Failure: FALSE. Call GetLastError() for more info.
*/
BOOL WINAPI SetupDiEnumDeviceInterfaces(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
CONST GUID * InterfaceClassGuid,
DWORD MemberIndex,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
BOOL ret = FALSE;
TRACE("%p, %p, %s, %d, %p\n", DeviceInfoSet, DeviceInfoData,
debugstr_guid(InterfaceClassGuid), MemberIndex, DeviceInterfaceData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (DeviceInfoData && (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) ||
!DeviceInfoData->Reserved))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!DeviceInterfaceData ||
DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DeviceInfoData)
{
struct DeviceInfo *devInfo =
(struct DeviceInfo *)DeviceInfoData->Reserved;
BOOL found = FALSE;
PLIST_ENTRY InterfaceListEntry = devInfo->InterfaceListHead.Flink;
while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
{
struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
{
InterfaceListEntry = InterfaceListEntry->Flink;
continue;
}
if (MemberIndex-- == 0)
{
/* return this item */
memcpy(&DeviceInterfaceData->InterfaceClassGuid,
&DevItf->InterfaceClassGuid,
sizeof(GUID));
DeviceInterfaceData->Flags = DevItf->Flags;
DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
found = TRUE;
ret = TRUE;
}
InterfaceListEntry = InterfaceListEntry->Flink;
}
if (!found)
SetLastError(ERROR_NO_MORE_ITEMS);
}
else
{
BOOL found = FALSE;
PLIST_ENTRY ItemList = set->ListHead.Flink;
while (ItemList != &set->ListHead && !found)
{
PLIST_ENTRY InterfaceListEntry;
struct DeviceInfo *devInfo =
CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
InterfaceListEntry = devInfo->InterfaceListHead.Flink;
while (InterfaceListEntry != &devInfo->InterfaceListHead && !found)
{
struct DeviceInterface *DevItf = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
if (!IsEqualIID(&DevItf->InterfaceClassGuid, InterfaceClassGuid))
{
InterfaceListEntry = InterfaceListEntry->Flink;
continue;
}
if (MemberIndex-- == 0)
{
/* return this item */
memcpy(&DeviceInterfaceData->InterfaceClassGuid,
&DevItf->InterfaceClassGuid,
sizeof(GUID));
DeviceInterfaceData->Flags = DevItf->Flags;
DeviceInterfaceData->Reserved = (ULONG_PTR)DevItf;
found = TRUE;
ret = TRUE;
}
InterfaceListEntry = InterfaceListEntry->Flink;
}
ItemList = ItemList->Flink;
}
if (!found)
SetLastError(ERROR_NO_MORE_ITEMS);
}
return ret;
}
/***********************************************************************
* SetupDiDestroyDeviceInfoList (SETUPAPI.@)
*
* Destroy a DeviceInfoList and free all used memory of the list.
*
* PARAMS
* devinfo [I] DeviceInfoList pointer to list to destroy
*
* RETURNS
* Success: non zero value.
* Failure: zero value.
*/
BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
{
BOOL ret = FALSE;
TRACE("%p\n", devinfo);
if (devinfo && devinfo != INVALID_HANDLE_VALUE)
{
struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
if (list->magic == SETUP_DEVICE_INFO_SET_MAGIC)
{
ret = DestroyDeviceInfoSet(list);
}
}
if (ret == FALSE)
SetLastError(ERROR_INVALID_HANDLE);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInterfaceDetailA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInterfaceDetailA(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
PDWORD RequiredSize,
PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailDataW = NULL;
DWORD sizeW = 0, bytesNeeded;
BOOL ret = FALSE;
TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
DeviceInterfaceData, DeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInterfaceData ||
DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
!DeviceInterfaceData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DeviceInterfaceDetailData && (DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A)))
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if((DeviceInterfaceDetailDataSize != 0) &&
(DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath) + sizeof(CHAR))))
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (DeviceInterfaceDetailData != NULL)
{
sizeW = FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)
+ (DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath)) * sizeof(WCHAR);
DeviceInterfaceDetailDataW = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)MyMalloc(sizeW);
if (!DeviceInterfaceDetailDataW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
DeviceInterfaceDetailDataW->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
}
if (!DeviceInterfaceDetailData || (DeviceInterfaceDetailData && DeviceInterfaceDetailDataW))
{
ret = SetupDiGetDeviceInterfaceDetailW(
DeviceInfoSet,
DeviceInterfaceData,
DeviceInterfaceDetailDataW,
sizeW,
&sizeW,
DeviceInfoData);
bytesNeeded = (sizeW - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) / sizeof(WCHAR)
+ FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath);
if (RequiredSize)
*RequiredSize = bytesNeeded;
if (ret && DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize >= bytesNeeded)
{
if (!WideCharToMultiByte(
CP_ACP, 0,
DeviceInterfaceDetailDataW->DevicePath, -1,
DeviceInterfaceDetailData->DevicePath, DeviceInterfaceDetailDataSize - FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_A, DevicePath),
NULL, NULL))
{
ret = FALSE;
}
}
}
MyFree(DeviceInterfaceDetailDataW);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInterfaceDetailW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInterfaceDetailW(
HDEVINFO DeviceInfoSet,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
DWORD DeviceInterfaceDetailDataSize,
PDWORD RequiredSize,
PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
BOOL ret = FALSE;
TRACE("(%p, %p, %p, %d, %p, %p)\n", DeviceInfoSet,
DeviceInterfaceData, DeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE ||
set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInterfaceData ||
DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA) ||
!DeviceInterfaceData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (DeviceInterfaceDetailData && DeviceInterfaceDetailData->cbSize != sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W))
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize)
{
SetLastError(ERROR_INVALID_USER_BUFFER);
return FALSE;
}
if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((DeviceInterfaceDetailData != NULL)
&& (DeviceInterfaceDetailDataSize < (FIELD_OFFSET(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath)) + sizeof(WCHAR)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
else
{
struct DeviceInterface *deviceInterface = (struct DeviceInterface *)DeviceInterfaceData->Reserved;
LPCWSTR devName = deviceInterface->SymbolicLink;
DWORD sizeRequired = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) +
(lstrlenW(devName) + 1) * sizeof(WCHAR);
if (sizeRequired > DeviceInterfaceDetailDataSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
if (RequiredSize)
*RequiredSize = sizeRequired;
}
else
{
strcpyW(DeviceInterfaceDetailData->DevicePath, devName);
TRACE("DevicePath is %s\n", debugstr_w(DeviceInterfaceDetailData->DevicePath));
if (DeviceInfoData)
{
memcpy(&DeviceInfoData->ClassGuid,
&deviceInterface->DeviceInfo->ClassGuid,
sizeof(GUID));
DeviceInfoData->DevInst = deviceInterface->DeviceInfo->dnDevInst;
DeviceInfoData->Reserved = (ULONG_PTR)deviceInterface->DeviceInfo;
}
ret = TRUE;
}
}
return ret;
}
struct PropertyMapEntry
{
DWORD regType;
LPCSTR nameA;
LPCWSTR nameW;
};
static struct PropertyMapEntry PropertyMap[] = {
{ REG_SZ, "DeviceDesc", REGSTR_VAL_DEVDESC },
{ REG_MULTI_SZ, "HardwareId", REGSTR_VAL_HARDWAREID },
{ REG_MULTI_SZ, "CompatibleIDs", REGSTR_VAL_COMPATIBLEIDS },
{ 0, NULL, NULL }, /* SPDRP_UNUSED0 */
{ REG_SZ, "Service", REGSTR_VAL_SERVICE },
{ 0, NULL, NULL }, /* SPDRP_UNUSED1 */
{ 0, NULL, NULL }, /* SPDRP_UNUSED2 */
{ REG_SZ, "Class", REGSTR_VAL_CLASS },
{ REG_SZ, "ClassGUID", REGSTR_VAL_CLASSGUID },
{ REG_SZ, "Driver", REGSTR_VAL_DRIVER },
{ REG_DWORD, "ConfigFlags", REGSTR_VAL_CONFIGFLAGS },
{ REG_SZ, "Mfg", REGSTR_VAL_MFG },
{ REG_SZ, "FriendlyName", REGSTR_VAL_FRIENDLYNAME },
{ REG_SZ, "LocationInformation", REGSTR_VAL_LOCATION_INFORMATION },
{ 0, NULL, NULL }, /* SPDRP_PHYSICAL_DEVICE_OBJECT_NAME */
{ REG_DWORD, "Capabilities", REGSTR_VAL_CAPABILITIES },
{ REG_DWORD, "UINumber", REGSTR_VAL_UI_NUMBER },
{ REG_MULTI_SZ, "UpperFilters", REGSTR_VAL_UPPERFILTERS },
{ REG_MULTI_SZ, "LowerFilters", REGSTR_VAL_LOWERFILTERS },
{ 0, NULL, NULL }, /* SPDRP_BUSTYPEGUID */
{ 0, NULL, NULL }, /* SPDRP_LEGACYBUSTYPE */
{ 0, NULL, NULL }, /* SPDRP_BUSNUMBER */
{ 0, NULL, NULL }, /* SPDRP_ENUMERATOR_NAME */
{ REG_BINARY, "Security", REGSTR_SECURITY },
{ 0, NULL, NULL }, /* SPDRP_SECURITY_SDS */
{ 0, NULL, NULL }, /* SPDRP_DEVTYPE */
{ 0, NULL, NULL }, /* SPDRP_EXCLUSIVE */
{ 0, NULL, NULL }, /* SPDRP_CHARACTERISTICS */
{ 0, NULL, NULL }, /* SPDRP_ADDRESS */
{ REG_SZ, "UINumberDescFormat", REGSTR_UI_NUMBER_DESC_FORMAT },
{ 0, NULL, NULL }, /* SPDRP_DEVICE_POWER_DATA */
{ 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY */
{ 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_HW_DEFAULT */
{ 0, NULL, NULL }, /* SPDRP_REMOVAL_POLICY_OVERRIDE */
{ 0, NULL, NULL }, /* SPDRP_INSTALL_STATE */
};
/***********************************************************************
* SetupDiGetDeviceRegistryPropertyA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize)
{
BOOL ret;
BOOL bIsStringProperty;
DWORD RegType;
DWORD RequiredSizeA, RequiredSizeW;
DWORD PropertyBufferSizeW = 0;
PBYTE PropertyBufferW = NULL;
TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
RequiredSize);
if (PropertyBufferSize != 0)
{
PropertyBufferSizeW = PropertyBufferSize * 2;
PropertyBufferW = HeapAlloc(GetProcessHeap(), 0, PropertyBufferSizeW);
if (!PropertyBufferW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
ret = SetupDiGetDeviceRegistryPropertyW(DeviceInfoSet,
DeviceInfoData,
Property,
&RegType,
PropertyBufferW,
PropertyBufferSizeW,
&RequiredSizeW);
if (ret || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
bIsStringProperty = (RegType == REG_SZ || RegType == REG_MULTI_SZ || RegType == REG_EXPAND_SZ);
if (bIsStringProperty)
RequiredSizeA = RequiredSizeW / sizeof(WCHAR);
else
RequiredSizeA = RequiredSizeW;
if (RequiredSize)
*RequiredSize = RequiredSizeA;
if (PropertyRegDataType)
*PropertyRegDataType = RegType;
}
if (!ret)
{
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
return ret;
}
if (RequiredSizeA <= PropertyBufferSize)
{
if (bIsStringProperty && PropertyBufferSize > 0)
{
if (WideCharToMultiByte(CP_ACP, 0, (LPWSTR)PropertyBufferW, RequiredSizeW / sizeof(WCHAR), (LPSTR)PropertyBuffer, PropertyBufferSize, NULL, NULL) == 0)
{
/* Last error is already set by WideCharToMultiByte */
ret = FALSE;
}
}
else
memcpy(PropertyBuffer, PropertyBufferW, RequiredSizeA);
}
else
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
ret = FALSE;
}
HeapFree(GetProcessHeap(), 0, PropertyBufferW);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceRegistryPropertyW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
PDWORD PropertyRegDataType,
PBYTE PropertyBuffer,
DWORD PropertyBufferSize,
PDWORD RequiredSize)
{
BOOL ret = FALSE;
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
struct DeviceInfo *devInfo;
TRACE("%p %p %d %p %p %d %p\n", DeviceInfoSet, DeviceInfoData,
Property, PropertyRegDataType, PropertyBuffer, PropertyBufferSize,
RequiredSize);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
&& PropertyMap[Property].nameW)
{
DWORD size = PropertyBufferSize;
HKEY hKey;
LONG l;
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hKey == INVALID_HANDLE_VALUE)
return FALSE;
l = RegQueryValueExW(hKey, PropertyMap[Property].nameW,
NULL, PropertyRegDataType, PropertyBuffer, &size);
RegCloseKey(hKey);
if (RequiredSize)
*RequiredSize = size;
switch(l) {
case ERROR_SUCCESS:
if (PropertyBuffer != NULL || size == 0)
ret = TRUE;
else
SetLastError(ERROR_INSUFFICIENT_BUFFER);
break;
case ERROR_MORE_DATA:
SetLastError(ERROR_INSUFFICIENT_BUFFER);
break;
default:
SetLastError(l);
}
}
else if (Property == SPDRP_PHYSICAL_DEVICE_OBJECT_NAME)
{
DWORD required = (strlenW(devInfo->Data) + 1) * sizeof(WCHAR);
if (PropertyRegDataType)
*PropertyRegDataType = REG_SZ;
if (RequiredSize)
*RequiredSize = required;
if (PropertyBufferSize >= required)
{
strcpyW((LPWSTR)PropertyBuffer, devInfo->Data);
ret = TRUE;
}
else
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
{
ERR("Property 0x%lx not implemented\n", Property);
SetLastError(ERROR_NOT_SUPPORTED);
}
return ret;
}
/***********************************************************************
* SetupDiSetDeviceRegistryPropertyA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiSetDeviceRegistryPropertyA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
const BYTE *PropertyBuffer,
DWORD PropertyBufferSize)
{
BOOL ret = FALSE;
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
PropertyBuffer, PropertyBufferSize);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FIXME("%p %p 0x%lx %p 0x%lx\n", DeviceInfoSet, DeviceInfoData,
Property, PropertyBuffer, PropertyBufferSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return ret;
}
/***********************************************************************
* SetupDiSetDeviceRegistryPropertyW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiSetDeviceRegistryPropertyW(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property,
const BYTE *PropertyBuffer,
DWORD PropertyBufferSize)
{
BOOL ret = FALSE;
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
TRACE("%p %p %d %p %d\n", DeviceInfoSet, DeviceInfoData, Property,
PropertyBuffer, PropertyBufferSize);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Property < sizeof(PropertyMap) / sizeof(PropertyMap[0])
&& PropertyMap[Property].nameW)
{
HKEY hKey;
LONG l;
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
if (hKey == INVALID_HANDLE_VALUE)
return FALSE;
/* Write new data */
l = RegSetValueExW(
hKey, PropertyMap[Property].nameW, 0,
PropertyMap[Property].regType, PropertyBuffer,
PropertyBufferSize);
if (!l)
ret = TRUE;
else
SetLastError(l);
RegCloseKey(hKey);
}
else
{
ERR("Property 0x%lx not implemented\n", Property);
SetLastError(ERROR_NOT_SUPPORTED);
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiInstallClassA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiInstallClassA(
HWND hwndParent,
PCSTR InfFileName,
DWORD Flags,
HSPFILEQ FileQueue)
{
return SetupDiInstallClassExA(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
}
/***********************************************************************
* SetupDiInstallClassExA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiInstallClassExA(
IN HWND hwndParent OPTIONAL,
IN PCSTR InfFileName OPTIONAL,
IN DWORD Flags,
IN HSPFILEQ FileQueue OPTIONAL,
IN CONST GUID *InterfaceClassGuid OPTIONAL,
IN PVOID Reserved1,
IN PVOID Reserved2)
{
PWSTR InfFileNameW = NULL;
BOOL Result;
if (!InfFileName)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
else
{
InfFileNameW = pSetupMultiByteToUnicode(InfFileName, CP_ACP);
if (InfFileNameW == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
Result = SetupDiInstallClassExW(hwndParent, InfFileNameW, Flags,
FileQueue, InterfaceClassGuid, Reserved1, Reserved2);
MyFree(InfFileNameW);
return Result;
}
HKEY SETUP_CreateClassKey(HINF hInf)
{
static const WCHAR slash[] = { '\\',0 };
WCHAR FullBuffer[MAX_PATH];
WCHAR Buffer[MAX_PATH];
DWORD RequiredSize;
HKEY hClassKey;
if (!SetupGetLineTextW(NULL,
hInf,
Version,
ClassGUID,
Buffer,
MAX_PATH,
&RequiredSize))
{
return INVALID_HANDLE_VALUE;
}
lstrcpyW(FullBuffer, REGSTR_PATH_CLASS_NT);
lstrcatW(FullBuffer, slash);
lstrcatW(FullBuffer, Buffer);
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
FullBuffer,
0,
KEY_SET_VALUE,
&hClassKey))
{
if (!SetupGetLineTextW(NULL,
hInf,
Version,
Class,
Buffer,
MAX_PATH,
&RequiredSize))
{
return INVALID_HANDLE_VALUE;
}
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
FullBuffer,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
&hClassKey,
NULL))
{
return INVALID_HANDLE_VALUE;
}
}
if (RegSetValueExW(hClassKey,
Class,
0,
REG_SZ,
(LPBYTE)Buffer,
RequiredSize * sizeof(WCHAR)))
{
RegCloseKey(hClassKey);
RegDeleteKeyW(HKEY_LOCAL_MACHINE,
FullBuffer);
return INVALID_HANDLE_VALUE;
}
return hClassKey;
}
/***********************************************************************
* SetupDiInstallClassW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiInstallClassW(
HWND hwndParent,
PCWSTR InfFileName,
DWORD Flags,
HSPFILEQ FileQueue)
{
return SetupDiInstallClassExW(hwndParent, InfFileName, Flags, FileQueue, NULL, NULL, NULL);
}
/***********************************************************************
* SetupDiOpenClassRegKey (SETUPAPI.@)
*/
HKEY WINAPI SetupDiOpenClassRegKey(
const GUID* ClassGuid,
REGSAM samDesired)
{
return SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
DIOCR_INSTALLER, NULL, NULL);
}
/***********************************************************************
* SetupDiOpenClassRegKeyExA (SETUPAPI.@)
*/
HKEY WINAPI SetupDiOpenClassRegKeyExA(
const GUID* ClassGuid,
REGSAM samDesired,
DWORD Flags,
PCSTR MachineName,
PVOID Reserved)
{
PWSTR MachineNameW = NULL;
HKEY hKey;
TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
Flags, debugstr_a(MachineName), Reserved);
if (MachineName)
{
MachineNameW = pSetupMultiByteToUnicode(MachineName, CP_ACP);
if (MachineNameW == NULL)
return INVALID_HANDLE_VALUE;
}
hKey = SetupDiOpenClassRegKeyExW(ClassGuid, samDesired,
Flags, MachineNameW, Reserved);
MyFree(MachineNameW);
return hKey;
}
/***********************************************************************
* SetupDiOpenClassRegKeyExW (SETUPAPI.@)
*/
HKEY WINAPI SetupDiOpenClassRegKeyExW(
const GUID* ClassGuid,
REGSAM samDesired,
DWORD Flags,
PCWSTR MachineName,
PVOID Reserved)
{
HKEY HKLM;
HKEY hClassesKey;
HKEY key;
LPCWSTR lpKeyName;
LONG l;
TRACE("%s 0x%lx 0x%lx %s %p\n", debugstr_guid(ClassGuid), samDesired,
Flags, debugstr_w(MachineName), Reserved);
if (MachineName != NULL)
{
l = RegConnectRegistryW(MachineName, HKEY_LOCAL_MACHINE, &HKLM);
if (l != ERROR_SUCCESS)
{
SetLastError(l);
return INVALID_HANDLE_VALUE;
}
}
else
HKLM = HKEY_LOCAL_MACHINE;
if (Flags == DIOCR_INSTALLER)
{
lpKeyName = REGSTR_PATH_CLASS_NT;
}
else if (Flags == DIOCR_INTERFACE)
{
lpKeyName = REGSTR_PATH_DEVICE_CLASSES;
}
else
{
ERR("Invalid Flags parameter!\n");
SetLastError(ERROR_INVALID_FLAGS);
if (MachineName != NULL) RegCloseKey(HKLM);
return INVALID_HANDLE_VALUE;
}
if (!ClassGuid)
{
if ((l = RegOpenKeyExW(HKLM,
lpKeyName,
0,
samDesired,
&hClassesKey)))
{
SetLastError(ERROR_INVALID_CLASS);
hClassesKey = INVALID_HANDLE_VALUE;
}
if (MachineName != NULL)
RegCloseKey(HKLM);
key = hClassesKey;
}
else
{
WCHAR bracedGuidString[39];
SETUPDI_GuidToString(ClassGuid, bracedGuidString);
if (!(l = RegOpenKeyExW(HKLM,
lpKeyName,
0,
samDesired,
&hClassesKey)))
{
if (MachineName != NULL)
RegCloseKey(HKLM);
if ((l = RegOpenKeyExW(hClassesKey,
bracedGuidString,
0,
samDesired,
&key)))
{
SetLastError(l);
key = INVALID_HANDLE_VALUE;
}
RegCloseKey(hClassesKey);
}
else
{
if (MachineName != NULL) RegCloseKey(HKLM);
SetLastError(l);
key = INVALID_HANDLE_VALUE;
}
}
return key;
}
/***********************************************************************
* SetupDiOpenDeviceInterfaceW (SETUPAPI.@)
*/
BOOL WINAPI SetupDiOpenDeviceInterfaceW(
HDEVINFO DeviceInfoSet,
PCWSTR DevicePath,
DWORD OpenFlags,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
struct DeviceInfoSet * list;
PCWSTR pEnd;
DWORD dwLength, dwError, dwIndex, dwKeyName, dwSubIndex;
CLSID ClassId;
WCHAR Buffer[MAX_PATH + 1];
WCHAR SymBuffer[MAX_PATH + 1];
WCHAR InstancePath[MAX_PATH + 1];
HKEY hKey, hDevKey, hSymKey;
struct DeviceInfo * deviceInfo;
struct DeviceInterface *deviceInterface;
BOOL Ret;
PLIST_ENTRY ItemList;
PLIST_ENTRY InterfaceListEntry;
TRACE("%p %s %08x %p\n",
DeviceInfoSet, debugstr_w(DevicePath), OpenFlags, DeviceInterfaceData);
if (DeviceInterfaceData && DeviceInterfaceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
list = (struct DeviceInfoSet * )DeviceInfoSet;
dwLength = wcslen(DevicePath);
if (dwLength < 39)
{
/* path must be at least a guid length + L'\0' */
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
if (DevicePath[0] != L'\\' ||
DevicePath[1] != L'\\' ||
(DevicePath[2] != L'?' && DevicePath[2] != L'.') ||
DevicePath[3] != L'\\')
{
/* invalid formatted path */
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
/* check for reference strings */
pEnd = wcschr(&DevicePath[4], L'\\');
if (!pEnd)
{
/* no reference string */
pEnd = DevicePath + dwLength;
}
/* copy guid */
wcscpy(Buffer, pEnd - 37);
Buffer[36] = L'\0';
dwError = UuidFromStringW(Buffer, &ClassId);
if (dwError != NOERROR)
{
/* invalid formatted path */
SetLastError(ERROR_BAD_PATHNAME);
return FALSE;
}
hKey = SetupDiOpenClassRegKeyExW(&ClassId, KEY_READ, DIOCR_INTERFACE, list->MachineName, NULL);
if (hKey == INVALID_HANDLE_VALUE)
{
/* invalid device class */
return FALSE;
}
ItemList = list->ListHead.Flink;
while (ItemList != &list->ListHead)
{
deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
InterfaceListEntry = deviceInfo->InterfaceListHead.Flink;
while (InterfaceListEntry != &deviceInfo->InterfaceListHead)
{
deviceInterface = CONTAINING_RECORD(InterfaceListEntry, struct DeviceInterface, ListEntry);
if (!IsEqualIID(&deviceInterface->InterfaceClassGuid, &ClassId))
{
InterfaceListEntry = InterfaceListEntry->Flink;
continue;
}
if (!wcsicmp(deviceInterface->SymbolicLink, DevicePath))
{
if (DeviceInterfaceData)
{
DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
DeviceInterfaceData->Flags = deviceInterface->Flags;
CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
}
return TRUE;
}
}
}
dwIndex = 0;
do
{
Buffer[0] = 0;
dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
dwError = RegEnumKeyExW(hKey, dwIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
if (dwError != ERROR_SUCCESS)
break;
if (RegOpenKeyExW(hKey, Buffer, 0, KEY_READ, &hDevKey) != ERROR_SUCCESS)
break;
dwSubIndex = 0;
InstancePath[0] = 0;
dwKeyName = sizeof(InstancePath);
dwError = RegQueryValueExW(hDevKey, L"DeviceInstance", NULL, NULL, (LPBYTE)InstancePath, &dwKeyName);
while(TRUE)
{
Buffer[0] = 0;
dwKeyName = sizeof(Buffer) / sizeof(WCHAR);
dwError = RegEnumKeyExW(hDevKey, dwSubIndex, Buffer, &dwKeyName, NULL, NULL, NULL, NULL);
if (dwError != ERROR_SUCCESS)
break;
dwError = RegOpenKeyExW(hDevKey, Buffer, 0, KEY_READ, &hSymKey);
if (dwError != ERROR_SUCCESS)
break;
/* query for symbolic link */
dwKeyName = sizeof(SymBuffer);
SymBuffer[0] = L'\0';
dwError = RegQueryValueExW(hSymKey, L"SymbolicLink", NULL, NULL, (LPBYTE)SymBuffer, &dwKeyName);
if (dwError != ERROR_SUCCESS)
{
RegCloseKey(hSymKey);
break;
}
if (!wcsicmp(SymBuffer, DevicePath))
{
Ret = CreateDeviceInfo(list, InstancePath, &ClassId, &deviceInfo);
RegCloseKey(hSymKey);
RegCloseKey(hDevKey);
RegCloseKey(hKey);
if (Ret)
{
deviceInterface = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DeviceInterface) + (wcslen(SymBuffer) + 1) * sizeof(WCHAR));
if (deviceInterface)
{
CopyMemory(&deviceInterface->InterfaceClassGuid, &ClassId, sizeof(GUID));
deviceInterface->DeviceInfo = deviceInfo;
deviceInterface->Flags = SPINT_ACTIVE; //FIXME
wcscpy(deviceInterface->SymbolicLink, SymBuffer);
InsertTailList(&deviceInfo->InterfaceListHead, &deviceInterface->ListEntry);
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
if (DeviceInterfaceData)
{
DeviceInterfaceData->Reserved = (ULONG_PTR)deviceInterface;
DeviceInterfaceData->Flags = deviceInterface->Flags;
CopyMemory(&DeviceInterfaceData->InterfaceClassGuid, &ClassId, sizeof(GUID));
}
else
{
Ret = FALSE;
SetLastError(ERROR_INVALID_USER_BUFFER);
}
}
}
else
{
HeapFree(GetProcessHeap(), 0, deviceInfo);
Ret = FALSE;
}
return Ret;
}
RegCloseKey(hSymKey);
dwSubIndex++;
}
RegCloseKey(hDevKey);
dwIndex++;
} while(TRUE);
RegCloseKey(hKey);
return FALSE;
}
/***********************************************************************
* SetupDiOpenDeviceInterfaceA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiOpenDeviceInterfaceA(
HDEVINFO DeviceInfoSet,
PCSTR DevicePath,
DWORD OpenFlags,
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData)
{
LPWSTR DevicePathW = NULL;
BOOL bResult;
TRACE("%p %s %08lx %p\n", DeviceInfoSet, debugstr_a(DevicePath), OpenFlags, DeviceInterfaceData);
DevicePathW = pSetupMultiByteToUnicode(DevicePath, CP_ACP);
if (DevicePathW == NULL)
return FALSE;
bResult = SetupDiOpenDeviceInterfaceW(DeviceInfoSet,
DevicePathW, OpenFlags, DeviceInterfaceData);
MyFree(DevicePathW);
return bResult;
}
/***********************************************************************
* SetupDiSetClassInstallParamsA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiSetClassInstallParamsA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PSP_CLASSINSTALL_HEADER ClassInstallParams,
DWORD ClassInstallParamsSize)
{
FIXME("%p %p %x %u\n",DeviceInfoSet, DeviceInfoData,
ClassInstallParams->InstallFunction, ClassInstallParamsSize);
return FALSE;
}
static BOOL WINAPI
IntSetupDiRegisterDeviceInfo(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
{
return SetupDiRegisterDeviceInfo(DeviceInfoSet, DeviceInfoData, 0, NULL, NULL, NULL);
}
/***********************************************************************
* SetupDiCallClassInstaller (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCallClassInstaller(
DI_FUNCTION InstallFunction,
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData)
{
BOOL ret = FALSE;
TRACE("%u %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
SetLastError(ERROR_INVALID_HANDLE);
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (((struct DeviceInfoSet *)DeviceInfoSet)->HKLM != HKEY_LOCAL_MACHINE)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
SP_DEVINSTALL_PARAMS_W InstallParams;
#define CLASS_COINSTALLER 0x1
#define DEVICE_COINSTALLER 0x2
#define CLASS_INSTALLER 0x4
UCHAR CanHandle = 0;
DEFAULT_CLASS_INSTALL_PROC DefaultHandler = NULL;
switch (InstallFunction)
{
case DIF_ADDPROPERTYPAGE_ADVANCED:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_ALLOW_INSTALL:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_DETECT:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_DESTROYPRIVATEDATA:
CanHandle = CLASS_INSTALLER;
break;
case DIF_INSTALLDEVICE:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiInstallDevice;
break;
case DIF_INSTALLDEVICEFILES:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiInstallDriverFiles;
break;
case DIF_INSTALLINTERFACES:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiInstallDeviceInterfaces;
break;
case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_NEWDEVICEWIZARD_POSTANALYZE:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_NEWDEVICEWIZARD_PREANALYZE:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_NEWDEVICEWIZARD_PRESELECT:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_NEWDEVICEWIZARD_SELECT:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_POWERMESSAGEWAKE:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_PROPERTYCHANGE:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiChangeState;
break;
case DIF_REGISTER_COINSTALLERS:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiRegisterCoDeviceInstallers;
break;
case DIF_REGISTERDEVICE:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = IntSetupDiRegisterDeviceInfo;
break;
case DIF_REMOVE:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiRemoveDevice;
break;
case DIF_SELECTBESTCOMPATDRV:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiSelectBestCompatDrv;
break;
case DIF_SELECTDEVICE:
CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiSelectDevice;
break;
case DIF_TROUBLESHOOTER:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
break;
case DIF_UNREMOVE:
CanHandle = CLASS_COINSTALLER | DEVICE_COINSTALLER | CLASS_INSTALLER;
DefaultHandler = SetupDiUnremoveDevice;
break;
default:
ERR("Install function %u not supported\n", InstallFunction);
SetLastError(ERROR_NOT_SUPPORTED);
}
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
/* Don't process this call, as a parameter is invalid */
CanHandle = 0;
if (CanHandle != 0)
{
LIST_ENTRY ClassCoInstallersListHead;
LIST_ENTRY DeviceCoInstallersListHead;
HMODULE ClassInstallerLibrary = NULL;
CLASS_INSTALL_PROC ClassInstaller = NULL;
COINSTALLER_CONTEXT_DATA Context;
PLIST_ENTRY ListEntry;
HKEY hKey;
DWORD dwRegType, dwLength;
DWORD rc = NO_ERROR;
InitializeListHead(&ClassCoInstallersListHead);
InitializeListHead(&DeviceCoInstallersListHead);
if (CanHandle & DEVICE_COINSTALLER)
{
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
if (hKey != INVALID_HANDLE_VALUE)
{
rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, &dwRegType, NULL, &dwLength);
if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
{
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
if (KeyBuffer != NULL)
{
rc = RegQueryValueExW(hKey, REGSTR_VAL_COINSTALLERS_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
if (rc == ERROR_SUCCESS)
{
LPWSTR ptr;
for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
{
/* Add coinstaller to DeviceCoInstallersListHead list */
struct CoInstallerElement *coinstaller;
TRACE("Got device coinstaller '%s'\n", debugstr_w(ptr));
coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
if (!coinstaller)
continue;
ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
InsertTailList(&DeviceCoInstallersListHead, &coinstaller->ListEntry);
else
HeapFree(GetProcessHeap(), 0, coinstaller);
}
}
HeapFree(GetProcessHeap(), 0, KeyBuffer);
}
}
RegCloseKey(hKey);
}
}
if (CanHandle & CLASS_COINSTALLER)
{
rc = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
REGSTR_PATH_CODEVICEINSTALLERS,
0, /* Options */
KEY_QUERY_VALUE,
&hKey);
if (rc == ERROR_SUCCESS)
{
LPWSTR lpGuidString;
if (UuidToStringW((UUID*)&DeviceInfoData->ClassGuid, &lpGuidString) == RPC_S_OK)
{
rc = RegQueryValueExW(hKey, lpGuidString, NULL, &dwRegType, NULL, &dwLength);
if (rc == ERROR_SUCCESS && dwRegType == REG_MULTI_SZ)
{
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
if (KeyBuffer != NULL)
{
rc = RegQueryValueExW(hKey, lpGuidString, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
if (rc == ERROR_SUCCESS)
{
LPWSTR ptr;
for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
{
/* Add coinstaller to ClassCoInstallersListHead list */
struct CoInstallerElement *coinstaller;
TRACE("Got class coinstaller '%s'\n", debugstr_w(ptr));
coinstaller = HeapAlloc(GetProcessHeap(), 0, sizeof(struct CoInstallerElement));
if (!coinstaller)
continue;
ZeroMemory(coinstaller, sizeof(struct CoInstallerElement));
if (GetFunctionPointer(ptr, &coinstaller->Module, (PVOID*)&coinstaller->Function) == ERROR_SUCCESS)
InsertTailList(&ClassCoInstallersListHead, &coinstaller->ListEntry);
else
HeapFree(GetProcessHeap(), 0, coinstaller);
}
}
HeapFree(GetProcessHeap(), 0, KeyBuffer);
}
}
RpcStringFreeW(&lpGuidString);
}
RegCloseKey(hKey);
}
}
if ((CanHandle & CLASS_INSTALLER) && !(InstallParams.FlagsEx & DI_FLAGSEX_CI_FAILED))
{
hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
if (hKey != INVALID_HANDLE_VALUE)
{
rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, &dwRegType, NULL, &dwLength);
if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
{
LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
if (KeyBuffer != NULL)
{
rc = RegQueryValueExW(hKey, REGSTR_VAL_INSTALLER_32, NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
if (rc == ERROR_SUCCESS)
{
/* Get ClassInstaller function pointer */
TRACE("Got class installer '%s'\n", debugstr_w(KeyBuffer));
if (GetFunctionPointer(KeyBuffer, &ClassInstallerLibrary, (PVOID*)&ClassInstaller) != ERROR_SUCCESS)
{
InstallParams.FlagsEx |= DI_FLAGSEX_CI_FAILED;
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
}
}
HeapFree(GetProcessHeap(), 0, KeyBuffer);
}
}
RegCloseKey(hKey);
}
}
/* Call Class co-installers */
Context.PostProcessing = FALSE;
rc = NO_ERROR;
ListEntry = ClassCoInstallersListHead.Flink;
while (rc == NO_ERROR && ListEntry != &ClassCoInstallersListHead)
{
struct CoInstallerElement *coinstaller;
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
coinstaller->PrivateData = Context.PrivateData;
if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
{
coinstaller->DoPostProcessing = TRUE;
rc = NO_ERROR;
}
ListEntry = ListEntry->Flink;
}
/* Call Device co-installers */
ListEntry = DeviceCoInstallersListHead.Flink;
while (rc == NO_ERROR && ListEntry != &DeviceCoInstallersListHead)
{
struct CoInstallerElement *coinstaller;
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
coinstaller->PrivateData = Context.PrivateData;
if (rc == ERROR_DI_POSTPROCESSING_REQUIRED)
{
coinstaller->DoPostProcessing = TRUE;
rc = NO_ERROR;
}
ListEntry = ListEntry->Flink;
}
/* Call Class installer */
if (ClassInstaller)
{
rc = (*ClassInstaller)(InstallFunction, DeviceInfoSet, DeviceInfoData);
FreeFunctionPointer(ClassInstallerLibrary, ClassInstaller);
}
else
rc = ERROR_DI_DO_DEFAULT;
/* Call default handler */
if (rc == ERROR_DI_DO_DEFAULT)
{
if (DefaultHandler && !(InstallParams.Flags & DI_NODI_DEFAULTACTION))
{
if ((*DefaultHandler)(DeviceInfoSet, DeviceInfoData))
rc = NO_ERROR;
else
rc = GetLastError();
}
else
rc = NO_ERROR;
}
/* Call Class co-installers that required postprocessing */
Context.PostProcessing = TRUE;
ListEntry = ClassCoInstallersListHead.Flink;
while (ListEntry != &ClassCoInstallersListHead)
{
struct CoInstallerElement *coinstaller;
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
if (coinstaller->DoPostProcessing)
{
Context.InstallResult = rc;
Context.PrivateData = coinstaller->PrivateData;
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
}
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
ListEntry = ListEntry->Flink;
}
/* Call Device co-installers that required postprocessing */
ListEntry = DeviceCoInstallersListHead.Flink;
while (ListEntry != &DeviceCoInstallersListHead)
{
struct CoInstallerElement *coinstaller;
coinstaller = CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry);
if (coinstaller->DoPostProcessing)
{
Context.InstallResult = rc;
Context.PrivateData = coinstaller->PrivateData;
rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
}
FreeFunctionPointer(coinstaller->Module, coinstaller->Function);
ListEntry = ListEntry->Flink;
}
/* Free allocated memory */
while (!IsListEmpty(&ClassCoInstallersListHead))
{
ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
}
while (!IsListEmpty(&DeviceCoInstallersListHead))
{
ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(ListEntry, struct CoInstallerElement, ListEntry));
}
ret = (rc == NO_ERROR);
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInstallParamsA (SETUPAPI.@)
*/
BOOL WINAPI SetupDiGetDeviceInstallParamsA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
{
SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
if (DeviceInstallParams == NULL)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_A))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
if (ret)
{
/* Do W->A conversion */
memcpy(
DeviceInstallParams,
&deviceInstallParamsW,
FIELD_OFFSET(SP_DEVINSTALL_PARAMS_W, DriverPath));
if (WideCharToMultiByte(CP_ACP, 0, deviceInstallParamsW.DriverPath, -1,
DeviceInstallParams->DriverPath, MAX_PATH, NULL, NULL) == 0)
{
DeviceInstallParams->DriverPath[0] = '\0';
ret = FALSE;
}
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInfoListClass (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetDeviceInfoListClass(
IN HDEVINFO DeviceInfoSet,
OUT LPGUID ClassGuid)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p\n", DeviceInfoSet, ClassGuid);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (IsEqualIID(&list->ClassGuid, &GUID_NULL))
SetLastError(ERROR_NO_ASSOCIATED_CLASS);
else
{
memcpy(&ClassGuid, &list->ClassGuid, sizeof(GUID));
ret = TRUE;
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetDeviceInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (!DeviceInstallParams)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
PSP_DEVINSTALL_PARAMS_W Source;
if (DeviceInfoData)
Source = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
else
Source = &list->InstallParams;
ret = TRUE;
_SEH2_TRY
{
memcpy(DeviceInstallParams, Source, Source->cbSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
ret = FALSE;
}
_SEH2_END;
}
TRACE("Returning %d\n", ret);
return ret;
}
static BOOL
CheckDeviceInstallParameters(
IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
{
DWORD SupportedFlags =
DI_NOVCP | /* 0x00000008 */
DI_DIDCOMPAT | /* 0x00000010 */
DI_DIDCLASS | /* 0x00000020 */
DI_NEEDRESTART | /* 0x00000080 */
DI_NEEDREBOOT | /* 0x00000100 */
DI_RESOURCEPAGE_ADDED | /* 0x00002000 */
DI_PROPERTIES_CHANGE | /* 0x00004000 */
DI_ENUMSINGLEINF | /* 0x00010000 */
DI_DONOTCALLCONFIGMG | /* 0x00020000 */
DI_CLASSINSTALLPARAMS | /* 0x00100000 */
DI_NODI_DEFAULTACTION | /* 0x00200000 */
DI_QUIETINSTALL | /* 0x00800000 */
DI_NOFILECOPY | /* 0x01000000 */
DI_DRIVERPAGE_ADDED; /* 0x04000000 */
DWORD SupportedFlagsEx =
DI_FLAGSEX_CI_FAILED | /* 0x00000004 */
DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
DI_FLAGSEX_NO_DRVREG_MODIFY | /* 0x00008000 */
DI_FLAGSEX_INSTALLEDDRIVER; /* 0x04000000 */
BOOL ret = FALSE;
/* FIXME: add support for more flags */
/* FIXME: DI_CLASSINSTALLPARAMS flag is not correctly used.
* It should be checked before accessing to other values
* of the SP_DEVINSTALL_PARAMS structure */
if (DeviceInstallParams->Flags & ~SupportedFlags)
{
FIXME("Unknown Flags: 0x%08lx\n", DeviceInstallParams->Flags & ~SupportedFlags);
SetLastError(ERROR_INVALID_FLAGS);
}
else if (DeviceInstallParams->FlagsEx & ~SupportedFlagsEx)
{
FIXME("Unknown FlagsEx: 0x%08lx\n", DeviceInstallParams->FlagsEx & ~SupportedFlagsEx);
SetLastError(ERROR_INVALID_FLAGS);
}
else if ((DeviceInstallParams->Flags & DI_NOVCP)
&& (DeviceInstallParams->FileQueue == NULL || DeviceInstallParams->FileQueue == (HSPFILEQ)INVALID_HANDLE_VALUE))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
/* FIXME: check Reserved field */
ret = TRUE;
}
return ret;
}
/***********************************************************************
* SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSetDeviceInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (!DeviceInstallParams)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (CheckDeviceInstallParameters(DeviceInstallParams))
{
PSP_DEVINSTALL_PARAMS_W Destination;
if (DeviceInfoData)
Destination = &((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams;
else
Destination = &list->InstallParams;
memcpy(Destination, DeviceInstallParams, DeviceInstallParams->cbSize);
ret = TRUE;
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiSetDeviceInstallParamsW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSetDeviceInstallParamsA(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
PSP_DEVINSTALL_PARAMS_A DeviceInstallParams)
{
SP_DEVINSTALL_PARAMS_W deviceInstallParamsW;
int len = 0;
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
if (DeviceInstallParams == NULL)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInstallParams->cbSize < sizeof(SP_DEVINSTALL_PARAMS_A))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
memcpy(&deviceInstallParamsW, DeviceInstallParams, FIELD_OFFSET(SP_DEVINSTALL_PARAMS_A, DriverPath));
deviceInstallParamsW.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
len = MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, NULL, 0);
if (!len)
{
ERR("DrivePath is NULL\n");
ret = FALSE;
}
else
{
MultiByteToWideChar(CP_ACP, 0, DeviceInstallParams->DriverPath, -1, deviceInstallParamsW.DriverPath, len);
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &deviceInstallParamsW);
}
}
TRACE("Returning %d\n", ret);
return ret;
}
static HKEY
OpenHardwareProfileKey(
IN HKEY HKLM,
IN DWORD HwProfile,
IN DWORD samDesired)
{
HKEY hHWProfilesKey = NULL;
HKEY hHWProfileKey = NULL;
HKEY ret = INVALID_HANDLE_VALUE;
LONG rc;
rc = RegOpenKeyExW(HKLM,
REGSTR_PATH_HWPROFILES,
0,
0,
&hHWProfilesKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
if (HwProfile == 0)
{
rc = RegOpenKeyExW(hHWProfilesKey,
REGSTR_KEY_CURRENT,
0,
KEY_CREATE_SUB_KEY,
&hHWProfileKey);
}
else
{
WCHAR subKey[5];
snprintfW(subKey, 4, InstanceKeyFormat, HwProfile);
subKey[4] = '\0';
rc = RegOpenKeyExW(hHWProfilesKey,
subKey,
0,
KEY_CREATE_SUB_KEY,
&hHWProfileKey);
}
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
ret = hHWProfileKey;
cleanup:
if (hHWProfilesKey != NULL)
RegCloseKey(hHWProfilesKey);
if (hHWProfileKey != NULL && hHWProfileKey != ret)
RegCloseKey(hHWProfileKey);
return ret;
}
static BOOL
IsDeviceInfoInDeviceInfoSet(
struct DeviceInfoSet *deviceInfoSet,
struct DeviceInfo *deviceInfo)
{
PLIST_ENTRY ListEntry;
ListEntry = deviceInfoSet->ListHead.Flink;
while (ListEntry != &deviceInfoSet->ListHead)
{
if (deviceInfo == CONTAINING_RECORD(ListEntry, struct DeviceInfo, ListEntry))
return TRUE;
ListEntry = ListEntry->Flink;
}
return FALSE;
}
/***********************************************************************
* SetupDiDeleteDeviceInfo (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiDeleteDeviceInfo(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *deviceInfoSet;
struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData;
BOOL ret = FALSE;
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((deviceInfoSet = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (!IsDeviceInfoInDeviceInfoSet(deviceInfoSet, deviceInfo))
SetLastError(ERROR_INVALID_PARAMETER);
else
{
RemoveEntryList(&deviceInfo->ListEntry);
DestroyDeviceInfo(deviceInfo);
ret = TRUE;
}
return ret;
}
/***********************************************************************
* SetupDiOpenDeviceInfoA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiOpenDeviceInfoA(
IN HDEVINFO DeviceInfoSet,
IN PCSTR DeviceInstanceId,
IN HWND hwndParent OPTIONAL,
IN DWORD OpenFlags,
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
{
LPWSTR DeviceInstanceIdW = NULL;
BOOL bResult;
TRACE("%p %s %p %lx %p\n", DeviceInfoSet, DeviceInstanceId, hwndParent, OpenFlags, DeviceInfoData);
DeviceInstanceIdW = pSetupMultiByteToUnicode(DeviceInstanceId, CP_ACP);
if (DeviceInstanceIdW == NULL)
return FALSE;
bResult = SetupDiOpenDeviceInfoW(DeviceInfoSet,
DeviceInstanceIdW, hwndParent, OpenFlags, DeviceInfoData);
MyFree(DeviceInstanceIdW);
return bResult;
}
/***********************************************************************
* SetupDiOpenDeviceInfoW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiOpenDeviceInfoW(
IN HDEVINFO DeviceInfoSet,
IN PCWSTR DeviceInstanceId,
IN HWND hwndParent OPTIONAL,
IN DWORD OpenFlags,
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
{
struct DeviceInfoSet *list;
HKEY hEnumKey, hKey = NULL;
DWORD rc, dwSize;
BOOL ret = FALSE;
TRACE("%p %s %p %lx %p\n",
DeviceInfoSet, debugstr_w(DeviceInstanceId),
hwndParent, OpenFlags, DeviceInfoData);
if (OpenFlags & DIOD_CANCEL_REMOVE)
FIXME("DIOD_CANCEL_REMOVE flag not implemented\n");
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (!DeviceInstanceId)
SetLastError(ERROR_INVALID_PARAMETER);
else if (OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS))
{
TRACE("Unknown flags: 0x%08lx\n", OpenFlags & ~(DIOD_CANCEL_REMOVE | DIOD_INHERIT_CLASSDRVS));
SetLastError(ERROR_INVALID_FLAGS);
}
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
struct DeviceInfo *deviceInfo = NULL;
/* Search if device already exists in DeviceInfoSet.
* If yes, return the existing element
* If no, create a new element using information in registry
*/
PLIST_ENTRY ItemList = list->ListHead.Flink;
while (ItemList != &list->ListHead)
{
deviceInfo = CONTAINING_RECORD(ItemList, struct DeviceInfo, ListEntry);
if (!wcscmp(deviceInfo->instanceId, DeviceInstanceId))
break;
deviceInfo = NULL;
ItemList = ItemList->Flink;
}
if (deviceInfo)
{
/* good one found */
ret = TRUE;
}
else
{
GUID ClassGUID;
WCHAR szClassGuid[MAX_GUID_STRING_LEN];
/* Open supposed registry key */
rc = RegOpenKeyExW(
list->HKLM,
REGSTR_PATH_SYSTEMENUM,
0, /* Options */
0,
&hEnumKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
rc = RegOpenKeyExW(
hEnumKey,
DeviceInstanceId,
0, /* Options */
KEY_QUERY_VALUE,
&hKey);
RegCloseKey(hEnumKey);
if (rc != ERROR_SUCCESS)
{
if (rc == ERROR_FILE_NOT_FOUND)
rc = ERROR_NO_SUCH_DEVINST;
SetLastError(rc);
goto cleanup;
}
ClassGUID = GUID_NULL;
dwSize = MAX_GUID_STRING_LEN * sizeof(WCHAR);
if (RegQueryValueExW(hKey,
REGSTR_VAL_CLASSGUID,
NULL,
NULL,
(LPBYTE)szClassGuid,
&dwSize) == ERROR_SUCCESS)
{
szClassGuid[MAX_GUID_STRING_LEN - 2] = UNICODE_NULL;
/* Convert a string to a ClassGuid */
UuidFromStringW(&szClassGuid[1], &ClassGUID);
}
if (!CreateDeviceInfo(list, DeviceInstanceId, &ClassGUID, &deviceInfo))
goto cleanup;
InsertTailList(&list->ListHead, &deviceInfo->ListEntry);
ret = TRUE;
}
if (ret && deviceInfo && DeviceInfoData)
{
memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
DeviceInfoData->DevInst = deviceInfo->dnDevInst;
DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
}
}
cleanup:
if (hKey != NULL)
RegCloseKey(hKey);
return ret;
}
/***********************************************************************
* SetupDiGetSelectedDevice (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetSelectedDevice(
IN HDEVINFO DeviceInfoSet,
OUT PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (list->SelectedDevice == NULL)
SetLastError(ERROR_NO_DEVICE_SELECTED);
else if (!DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
memcpy(&DeviceInfoData->ClassGuid,
&list->SelectedDevice->ClassGuid,
sizeof(GUID));
DeviceInfoData->DevInst = list->SelectedDevice->dnDevInst;
DeviceInfoData->Reserved = (ULONG_PTR)list->SelectedDevice;
ret = TRUE;
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiSetSelectedDevice (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSetSelectedDevice(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (!DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (DeviceInfoData->Reserved == 0)
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
list->SelectedDevice = (struct DeviceInfo *)DeviceInfoData->Reserved;
ret = TRUE;
}
TRACE("Returning %d\n", ret);
return ret;
}
/* Return the current hardware profile id, or -1 if error */
static DWORD
SETUPAPI_GetCurrentHwProfile(
IN HDEVINFO DeviceInfoSet)
{
HKEY hKey = NULL;
DWORD dwRegType, dwLength;
DWORD hwProfile;
LONG rc;
DWORD ret = (DWORD)-1;
rc = RegOpenKeyExW(((struct DeviceInfoSet *)DeviceInfoSet)->HKLM,
REGSTR_PATH_IDCONFIGDB,
0, /* Options */
KEY_QUERY_VALUE,
&hKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
dwLength = sizeof(DWORD);
rc = RegQueryValueExW(hKey,
REGSTR_VAL_CURRENTCONFIG,
NULL,
&dwRegType,
(LPBYTE)&hwProfile, &dwLength);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
ret = hwProfile;
cleanup:
if (hKey != NULL)
RegCloseKey(hKey);
return ret;
}
static BOOL
ResetDevice(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
#ifndef __WINESRC__
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
struct DeviceInfo *deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
CONFIGRET cr;
cr = CM_Enable_DevNode_Ex(deviceInfo->dnDevInst, 0, set->hMachine);
if (cr != CR_SUCCESS)
{
SetLastError(GetErrorCodeFromCrCode(cr));
return FALSE;
}
return TRUE;
#else
FIXME("Stub: ResetDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
return TRUE;
#endif
}
static BOOL StopDevice(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
FIXME("Stub: StopDevice(%p %p)\n", DeviceInfoSet, DeviceInfoData);
return TRUE;
}
/***********************************************************************
* SetupDiChangeState (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiChangeState(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
{
PSP_PROPCHANGE_PARAMS PropChange;
HKEY hKey = INVALID_HANDLE_VALUE;
LPCWSTR RegistryValueName;
DWORD dwConfigFlags, dwLength, dwRegType;
LONG rc;
BOOL ret = FALSE;
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoData)
PropChange = ((struct DeviceInfoSet *)DeviceInfoSet)->ClassInstallParams.PropChangeParams;
else
PropChange = ((struct DeviceInfo *)DeviceInfoData->Reserved)->ClassInstallParams.PropChangeParams;
if (!PropChange)
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
if (PropChange->Scope == DICS_FLAG_GLOBAL)
RegistryValueName = REGSTR_VAL_CONFIGFLAGS;
else
RegistryValueName = REGSTR_VAL_CSCONFIGFLAGS;
switch (PropChange->StateChange)
{
case DICS_ENABLE:
case DICS_DISABLE:
{
/* Enable/disable device in registry */
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, KEY_QUERY_VALUE | KEY_SET_VALUE);
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, PropChange->Scope, PropChange->HwProfile, DIREG_DEV, NULL, NULL);
if (hKey == INVALID_HANDLE_VALUE)
break;
dwLength = sizeof(DWORD);
rc = RegQueryValueExW(
hKey,
RegistryValueName,
NULL,
&dwRegType,
(LPBYTE)&dwConfigFlags, &dwLength);
if (rc == ERROR_FILE_NOT_FOUND)
dwConfigFlags = 0;
else if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
else if (dwRegType != REG_DWORD || dwLength != sizeof(DWORD))
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
if (PropChange->StateChange == DICS_ENABLE)
dwConfigFlags &= ~(PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
else
dwConfigFlags |= (PropChange->Scope == DICS_FLAG_GLOBAL ? CONFIGFLAG_DISABLED : CSCONFIGFLAG_DISABLED);
rc = RegSetValueExW(
hKey,
RegistryValueName,
0,
REG_DWORD,
(LPBYTE)&dwConfigFlags, sizeof(DWORD));
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
/* Enable/disable device if needed */
if (PropChange->Scope == DICS_FLAG_GLOBAL
|| PropChange->HwProfile == 0
|| PropChange->HwProfile == SETUPAPI_GetCurrentHwProfile(DeviceInfoSet))
{
if (PropChange->StateChange == DICS_ENABLE)
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
else
ret = StopDevice(DeviceInfoSet, DeviceInfoData);
}
else
ret = TRUE;
break;
}
case DICS_PROPCHANGE:
{
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
break;
}
default:
{
ERR("Unknown StateChange 0x%lx\n", PropChange->StateChange);
SetLastError(ERROR_NOT_SUPPORTED);
}
}
cleanup:
if (hKey != INVALID_HANDLE_VALUE)
RegCloseKey(hKey);
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiSelectDevice (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSelectDevice(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
{
FIXME("%p %p\n", DeviceInfoSet, DeviceInfoData);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiRegisterCoDeviceInstallers(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
BOOL ret = FALSE; /* Return value */
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
SetLastError(ERROR_INVALID_HANDLE);
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (!DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
SP_DEVINSTALL_PARAMS_W InstallParams;
struct DriverInfoElement *SelectedDriver;
BOOL Result;
DWORD DoAction;
WCHAR SectionName[MAX_PATH];
DWORD SectionNameLength = 0;
HKEY hKey = INVALID_HANDLE_VALUE;
PVOID Context = NULL;
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
if (!Result)
goto cleanup;
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
if (SelectedDriver == NULL)
{
SetLastError(ERROR_NO_DRIVER_SELECTED);
goto cleanup;
}
/* Get .CoInstallers section name */
Result = SetupDiGetActualSectionToInstallW(
SelectedDriver->InfFileDetails->hInf,
SelectedDriver->Details.SectionName,
SectionName, MAX_PATH, &SectionNameLength, NULL);
if (!Result || SectionNameLength > MAX_PATH - strlenW(DotCoInstallers) - 1)
goto cleanup;
lstrcatW(SectionName, DotCoInstallers);
/* Open/Create driver key information */
#if _WIN32_WINNT >= 0x502
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
#else
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
#endif
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
if (hKey == INVALID_HANDLE_VALUE)
goto cleanup;
/* Install .CoInstallers section */
DoAction = SPINST_REGISTRY;
if (!(InstallParams.Flags & DI_NOFILECOPY))
{
DoAction |= SPINST_FILES;
Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
if (!Context)
goto cleanup;
}
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
SetupDefaultQueueCallbackW, Context,
DeviceInfoSet, DeviceInfoData);
if (!Result)
goto cleanup;
ret = TRUE;
cleanup:
if (Context)
SetupTermDefaultQueueCallback(Context);
if (hKey != INVALID_HANDLE_VALUE)
RegCloseKey(hKey);
}
TRACE("Returning %d\n", ret);
return ret;
}
static BOOL
InfIsFromOEMLocation(
IN PCWSTR FullName,
OUT LPBOOL IsOEMLocation)
{
PWCHAR last;
last = strrchrW(FullName, '\\');
if (!last)
{
/* No directory specified */
*IsOEMLocation = FALSE;
}
else
{
LPWSTR Windir;
UINT ret;
Windir = MyMalloc((MAX_PATH + 1 + strlenW(InfDirectory)) * sizeof(WCHAR));
if (!Windir)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
ret = GetSystemWindowsDirectoryW(Windir, MAX_PATH);
if (ret == 0 || ret > MAX_PATH)
{
MyFree(Windir);
SetLastError(ERROR_GEN_FAILURE);
return FALSE;
}
if (*Windir && Windir[strlenW(Windir) - 1] != '\\')
strcatW(Windir, BackSlash);
strcatW(Windir, InfDirectory);
if (strncmpiW(FullName, Windir, last - FullName) == 0)
{
/* The path is %SYSTEMROOT%\Inf */
*IsOEMLocation = FALSE;
}
else
{
/* The file is in another place */
*IsOEMLocation = TRUE;
}
MyFree(Windir);
}
return TRUE;
}
/***********************************************************************
* SetupDiInstallDevice (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiInstallDevice(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData)
{
SP_DEVINSTALL_PARAMS_W InstallParams;
struct DriverInfoElement *SelectedDriver;
SYSTEMTIME DriverDate;
WCHAR SectionName[MAX_PATH];
WCHAR Buffer[32];
DWORD SectionNameLength = 0;
BOOL Result = FALSE;
ULONG DoAction;
DWORD RequiredSize;
LPWSTR pSectionName = NULL;
WCHAR ClassName[MAX_CLASS_NAME_LEN];
GUID ClassGuid;
LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
BOOL RebootRequired = FALSE;
HKEY hKey = INVALID_HANDLE_VALUE;
BOOL NeedtoCopyFile;
LARGE_INTEGER fullVersion;
LONG rc;
PVOID Context = NULL;
BOOL ret = FALSE; /* Return value */
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
SetLastError(ERROR_INVALID_HANDLE);
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
Result = TRUE;
if (!Result)
{
/* One parameter is bad */
goto cleanup;
}
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
if (!Result)
goto cleanup;
if (InstallParams.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)
{
/* Set FAILEDINSTALL in ConfigFlags registry value */
DWORD ConfigFlags, regType;
Result = SetupDiGetDeviceRegistryPropertyW(
DeviceInfoSet,
DeviceInfoData,
SPDRP_CONFIGFLAGS,
&regType,
(PBYTE)&ConfigFlags,
sizeof(ConfigFlags),
NULL);
if (!Result || regType != REG_DWORD)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
ConfigFlags |= DNF_DISABLED;
Result = SetupDiSetDeviceRegistryPropertyW(
DeviceInfoSet,
DeviceInfoData,
SPDRP_CONFIGFLAGS,
(PBYTE)&ConfigFlags,
sizeof(ConfigFlags));
if (!Result)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
ret = TRUE;
goto cleanup;
}
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
if (SelectedDriver == NULL)
{
SetLastError(ERROR_NO_DRIVER_SELECTED);
goto cleanup;
}
FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
Result = SetupDiGetActualSectionToInstallW(
SelectedDriver->InfFileDetails->hInf,
SelectedDriver->Details.SectionName,
SectionName, MAX_PATH, &SectionNameLength, NULL);
if (!Result || SectionNameLength > MAX_PATH - strlenW(DotServices))
goto cleanup;
pSectionName = &SectionName[strlenW(SectionName)];
/* Get information from [Version] section */
if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
goto cleanup;
/* Format ClassGuid to a string */
if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
goto cleanup;
RequiredSize = lstrlenW(lpGuidString);
lpFullGuidString = HeapAlloc(GetProcessHeap(), 0, (RequiredSize + 3) * sizeof(WCHAR));
if (!lpFullGuidString)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
lpFullGuidString[0] = '{';
memcpy(&lpFullGuidString[1], lpGuidString, RequiredSize * sizeof(WCHAR));
lpFullGuidString[RequiredSize + 1] = '}';
lpFullGuidString[RequiredSize + 2] = '\0';
/* Copy .inf file to Inf\ directory (if needed) */
Result = InfIsFromOEMLocation(SelectedDriver->Details.InfFileName, &NeedtoCopyFile);
if (!Result)
goto cleanup;
if (NeedtoCopyFile)
{
WCHAR NewFileName[MAX_PATH];
struct InfFileDetails *newInfFileDetails;
Result = SetupCopyOEMInfW(
SelectedDriver->Details.InfFileName,
NULL,
SPOST_NONE,
SP_COPY_NOOVERWRITE,
NewFileName, MAX_PATH,
NULL,
NULL);
if (!Result && GetLastError() != ERROR_FILE_EXISTS)
goto cleanup;
/* Create a new struct InfFileDetails, and set it to
* SelectedDriver->InfFileDetails, to release use of
* current InfFile */
newInfFileDetails = CreateInfFileDetails(NewFileName);
if (!newInfFileDetails)
goto cleanup;
DereferenceInfFile(SelectedDriver->InfFileDetails);
SelectedDriver->InfFileDetails = newInfFileDetails;
strcpyW(SelectedDriver->Details.InfFileName, NewFileName);
}
/* Open/Create driver key information */
#if _WIN32_WINNT >= 0x502
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ | KEY_WRITE);
#else
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
#endif
if (hKey == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND)
hKey = SetupDiCreateDevRegKeyW(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
if (hKey == INVALID_HANDLE_VALUE)
goto cleanup;
/* Install main section */
DoAction = 0;
if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
DoAction |= SPINST_REGISTRY;
if (!(InstallParams.Flags & DI_NOFILECOPY))
{
DoAction |= SPINST_FILES;
Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
if (!Context)
goto cleanup;
}
*pSectionName = '\0';
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
DoAction, hKey, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
SetupDefaultQueueCallbackW, Context,
DeviceInfoSet, DeviceInfoData);
if (!Result)
goto cleanup;
InstallParams.Flags |= DI_NOFILECOPY;
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
/* Write information to driver key */
*pSectionName = UNICODE_NULL;
memcpy(&fullVersion, &SelectedDriver->Info.DriverVersion, sizeof(LARGE_INTEGER));
TRACE("Write information to driver key\n");
TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
TRACE("DriverDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
TRACE("DriverVersion : '%ld.%ld.%lu.%ld'\n", fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
TRACE("InfPath : '%s'\n", debugstr_w(SelectedDriver->InfFileDetails->FileName));
TRACE("InfSection : '%s'\n", debugstr_w(SelectedDriver->Details.SectionName));
TRACE("InfSectionExt : '%s'\n", debugstr_w(&SectionName[strlenW(SelectedDriver->Details.SectionName)]));
TRACE("MatchingDeviceId: '%s'\n", debugstr_w(SelectedDriver->MatchingId));
TRACE("ProviderName : '%s'\n", debugstr_w(SelectedDriver->Info.ProviderName));
sprintfW(Buffer, DateFormat, DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_DRIVER_DATE_DATA, 0, REG_BINARY, (const BYTE *)&SelectedDriver->Info.DriverDate, sizeof(FILETIME));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_DRVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
{
sprintfW(Buffer, VersionFormat, fullVersion.HighPart >> 16, fullVersion.HighPart & 0xffff, fullVersion.LowPart >> 16, fullVersion.LowPart & 0xffff);
rc = RegSetValueExW(hKey, REGSTR_DRIVER_VERSION, 0, REG_SZ, (const BYTE *)Buffer, (strlenW(Buffer) + 1) * sizeof(WCHAR));
}
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_INFPATH, 0, REG_SZ, (const BYTE *)SelectedDriver->InfFileDetails->FileName, (strlenW(SelectedDriver->InfFileDetails->FileName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_INFSECTION, 0, REG_SZ, (const BYTE *)SelectedDriver->Details.SectionName, (strlenW(SelectedDriver->Details.SectionName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
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));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_MATCHINGDEVID, 0, REG_SZ, (const BYTE *)SelectedDriver->MatchingId, (strlenW(SelectedDriver->MatchingId) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_PROVIDER_NAME, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.ProviderName, (strlenW(SelectedDriver->Info.ProviderName) + 1) * sizeof(WCHAR));
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
RegCloseKey(hKey);
hKey = INVALID_HANDLE_VALUE;
/* FIXME: Process .LogConfigOverride section */
/* Install .Services section */
strcpyW(pSectionName, DotServices);
Result = SetupInstallServicesFromInfSectionExW(
SelectedDriver->InfFileDetails->hInf,
SectionName,
0,
DeviceInfoSet,
DeviceInfoData,
NULL,
NULL);
if (!Result)
goto cleanup;
if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
RebootRequired = TRUE;
/* Open device registry key */
hKey = SetupDiOpenDevRegKey(DeviceInfoSet, DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_SET_VALUE);
if (hKey == INVALID_HANDLE_VALUE)
goto cleanup;
/* Install .HW section */
DoAction = 0;
if (!(InstallParams.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY))
DoAction |= SPINST_REGISTRY;
strcpyW(pSectionName, DotHW);
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
DoAction, hKey, NULL, 0,
NULL, NULL,
DeviceInfoSet, DeviceInfoData);
if (!Result)
goto cleanup;
/* Write information to enum key */
TRACE("Write information to enum key\n");
TRACE("Class : '%s'\n", debugstr_w(ClassName));
TRACE("ClassGUID : '%s'\n", debugstr_w(lpFullGuidString));
TRACE("DeviceDesc : '%s'\n", debugstr_w(SelectedDriver->Info.Description));
TRACE("Mfg : '%s'\n", debugstr_w(SelectedDriver->Info.MfgName));
rc = RegSetValueExW(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (strlenW(ClassName) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (strlenW(lpFullGuidString) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (strlenW(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR));
if (rc == ERROR_SUCCESS)
rc = RegSetValueExW(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (strlenW(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR));
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
/* Start the device */
if (!RebootRequired && !(InstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
ret = ResetDevice(DeviceInfoSet, DeviceInfoData);
else
ret = TRUE;
cleanup:
/* End of installation */
if (hKey != INVALID_HANDLE_VALUE)
RegCloseKey(hKey);
if (lpGuidString)
RpcStringFreeW(&lpGuidString);
HeapFree(GetProcessHeap(), 0, lpFullGuidString);
if (Context)
SetupTermDefaultQueueCallback(Context);
TRACE("Returning %d\n", ret);
return ret;
}
static HKEY SETUPDI_OpenDevKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
{
HKEY enumKey, key = INVALID_HANDLE_VALUE;
LONG l;
l = RegOpenKeyExW(RootKey, REGSTR_PATH_SYSTEMENUM, 0, 0, &enumKey);
if (!l)
{
l = RegOpenKeyExW(enumKey, devInfo->instanceId, 0, samDesired, &key);
RegCloseKey(enumKey);
}
if (l)
SetLastError(l);
return key;
}
static HKEY SETUPDI_OpenDrvKey(HKEY RootKey, struct DeviceInfo *devInfo, REGSAM samDesired)
{
LPWSTR DriverKey = NULL;
DWORD dwLength = 0;
DWORD dwRegType;
DWORD rc;
HKEY hEnumKey = NULL;
HKEY hKey = NULL;
HKEY key = INVALID_HANDLE_VALUE;
hKey = SETUPDI_OpenDevKey(RootKey, devInfo, KEY_QUERY_VALUE);
if (hKey == INVALID_HANDLE_VALUE)
goto cleanup;
/* Read the 'Driver' key */
rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, NULL, &dwLength);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
else if (dwRegType != REG_SZ)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
DriverKey = HeapAlloc(GetProcessHeap(), 0, dwLength);
if (!DriverKey)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
rc = RegQueryValueExW(hKey, REGSTR_VAL_DRIVER, NULL, &dwRegType, (LPBYTE)DriverKey, &dwLength);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
RegCloseKey(hKey);
hKey = NULL;
/* Need to open the driver key */
rc = RegOpenKeyExW(
RootKey,
REGSTR_PATH_CLASS_NT,
0, /* Options */
0,
&hEnumKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
rc = RegOpenKeyExW(
hEnumKey,
DriverKey,
0, /* Options */
samDesired,
&hKey);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
goto cleanup;
}
key = hKey;
cleanup:
if (hEnumKey != NULL)
RegCloseKey(hEnumKey);
if (hKey != NULL && hKey != key)
RegCloseKey(hKey);
return key;
}
/***********************************************************************
* SetupDiOpenDevRegKey (SETUPAPI.@)
*/
HKEY WINAPI SetupDiOpenDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType,
REGSAM samDesired)
{
struct DeviceInfoSet *set = DeviceInfoSet;
struct DeviceInfo *devInfo;
HKEY key = INVALID_HANDLE_VALUE;
HKEY RootKey;
TRACE("%p %p %d %d %d %x\n", DeviceInfoSet, DeviceInfoData,
Scope, HwProfile, KeyType, samDesired);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_HANDLE_VALUE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
{
SetLastError(ERROR_INVALID_FLAGS);
return INVALID_HANDLE_VALUE;
}
if (KeyType != DIREG_DEV && KeyType != DIREG_DRV)
{
SetLastError(ERROR_INVALID_FLAGS);
return INVALID_HANDLE_VALUE;
}
devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (devInfo->set != set)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
if (Scope != DICS_FLAG_GLOBAL)
{
RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
if (RootKey == INVALID_HANDLE_VALUE)
return INVALID_HANDLE_VALUE;
}
else
RootKey = set->HKLM;
switch (KeyType)
{
case DIREG_DEV:
key = SETUPDI_OpenDevKey(RootKey, devInfo, samDesired);
break;
case DIREG_DRV:
key = SETUPDI_OpenDrvKey(RootKey, devInfo, samDesired);
break;
default:
WARN("unknown KeyType %d\n", KeyType);
}
if (RootKey != set->HKLM)
RegCloseKey(RootKey);
return key;
}
static BOOL SETUPDI_DeleteDevKey(HKEY RootKey, struct DeviceInfo *devInfo)
{
FIXME("\n");
return FALSE;
}
static BOOL SETUPDI_DeleteDrvKey(HKEY RootKey, struct DeviceInfo *devInfo)
{
FIXME("\n");
return FALSE;
}
/***********************************************************************
* SetupDiDeleteDevRegKey (SETUPAPI.@)
*/
BOOL WINAPI SetupDiDeleteDevRegKey(
HDEVINFO DeviceInfoSet,
PSP_DEVINFO_DATA DeviceInfoData,
DWORD Scope,
DWORD HwProfile,
DWORD KeyType)
{
struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet;
struct DeviceInfo *devInfo;
BOOL ret = FALSE;
HKEY RootKey;
TRACE("%p %p %d %d %d\n", DeviceInfoSet, DeviceInfoData, Scope, HwProfile,
KeyType);
if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)
|| !DeviceInfoData->Reserved)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Scope != DICS_FLAG_GLOBAL && Scope != DICS_FLAG_CONFIGSPECIFIC)
{
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
if (KeyType != DIREG_DEV && KeyType != DIREG_DRV && KeyType != DIREG_BOTH)
{
SetLastError(ERROR_INVALID_FLAGS);
return FALSE;
}
devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (devInfo->set != set)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Scope != DICS_FLAG_GLOBAL)
{
RootKey = OpenHardwareProfileKey(set->HKLM, HwProfile, 0);
if (RootKey == INVALID_HANDLE_VALUE)
return FALSE;
}
else
RootKey = set->HKLM;
switch (KeyType)
{
case DIREG_DEV:
ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
break;
case DIREG_DRV:
ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
break;
case DIREG_BOTH:
ret = SETUPDI_DeleteDevKey(RootKey, devInfo);
if (ret)
ret = SETUPDI_DeleteDrvKey(RootKey, devInfo);
break;
default:
WARN("unknown KeyType %d\n", KeyType);
}
if (RootKey != set->HKLM)
RegCloseKey(RootKey);
return ret;
}