Implement SetupDiGetDriverInstallParamsW

Add support for DI_FLAGSEX_INSTALLEDDRIVER

svn path=/trunk/; revision=24322
This commit is contained in:
Hervé Poussineau 2006-09-30 20:42:47 +00:00
parent b0e0c40c5d
commit 3f47783c54
4 changed files with 382 additions and 47 deletions

View file

@ -1898,7 +1898,8 @@ CheckDeviceInstallParameters(
DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */ DI_FLAGSEX_DIDINFOLIST | /* 0x00000010 */
DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */ DI_FLAGSEX_DIDCOMPATINFO | /* 0x00000020 */
DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */ DI_FLAGSEX_ALLOWEXCLUDEDDRVS | /* 0x00000800 */
DI_FLAGSEX_NO_DRVREG_MODIFY; /* 0x00008000 */ DI_FLAGSEX_NO_DRVREG_MODIFY | /* 0x00008000 */
DI_FLAGSEX_INSTALLEDDRIVER; /* 0x04000000 */
BOOL ret = FALSE; BOOL ret = FALSE;
/* FIXME: add support for more flags */ /* FIXME: add support for more flags */

View file

@ -105,26 +105,26 @@ DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
* Helper functions for SetupDiBuildDriverInfoList * Helper functions for SetupDiBuildDriverInfoList
*/ */
static BOOL static BOOL
AddDriverToList( AddKnownDriverToList(
IN PLIST_ENTRY DriverListHead, IN PLIST_ENTRY DriverListHead,
IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */ IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
IN LPGUID ClassGuid, IN LPGUID ClassGuid,
IN INFCONTEXT ContextDevice,
IN struct InfFileDetails *InfFileDetails, IN struct InfFileDetails *InfFileDetails,
IN LPCWSTR InfFile, IN LPCWSTR InfFile,
IN LPCWSTR SectionName,
IN LPCWSTR DriverDescription,
IN LPCWSTR ProviderName, IN LPCWSTR ProviderName,
IN LPCWSTR ManufacturerName, IN LPCWSTR ManufacturerName,
IN LPCWSTR MatchingId, IN LPCWSTR MatchingId,
FILETIME DriverDate, IN FILETIME DriverDate,
DWORDLONG DriverVersion, IN DWORDLONG DriverVersion,
IN DWORD Rank) IN DWORD Rank)
{ {
struct DriverInfoElement *driverInfo = NULL; struct DriverInfoElement *driverInfo = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD RequiredSize = 128; /* Initial buffer size */
BOOL Result = FALSE; BOOL Result = FALSE;
PLIST_ENTRY PreviousEntry; PLIST_ENTRY PreviousEntry;
LPWSTR InfInstallSection = NULL; LPWSTR pDot;
BOOL ret = FALSE; BOOL ret = FALSE;
driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement)); driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
@ -135,6 +135,9 @@ AddDriverToList(
} }
memset(driverInfo, 0, sizeof(struct DriverInfoElement)); memset(driverInfo, 0, sizeof(struct DriverInfoElement));
driverInfo->Params.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
driverInfo->Params.Reserved = (ULONG_PTR)driverInfo;
driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); driverInfo->Details.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
driverInfo->Details.Reserved = (ULONG_PTR)driverInfo; driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
@ -154,20 +157,13 @@ AddDriverToList(
goto cleanup; goto cleanup;
/* Fill SectionName field */ /* Fill SectionName field */
Result = SetupGetStringFieldW( strncpyW(driverInfo->Details.SectionName, SectionName, LINE_LEN);
&ContextDevice, pDot = strchrW(driverInfo->Details.SectionName, '.');
1, if (pDot)
driverInfo->Details.SectionName, LINE_LEN, *pDot = UNICODE_NULL;
NULL);
if (!Result)
goto cleanup;
/* Fill DrvDescription field */ /* Fill DrvDescription field */
Result = SetupGetStringFieldW( strncpyW(driverInfo->Details.DrvDescription, DriverDescription, LINE_LEN);
&ContextDevice,
0, /* Field index */
driverInfo->Details.DrvDescription, LINE_LEN,
NULL);
/* Copy MatchingId information */ /* Copy MatchingId information */
if (MatchingId) if (MatchingId)
@ -183,30 +179,11 @@ AddDriverToList(
else else
driverInfo->MatchingId = NULL; driverInfo->MatchingId = NULL;
/* Get inf install section */
Result = FALSE;
RequiredSize = 128; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, InfInstallSection);
InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!InfInstallSection)
goto cleanup;
Result = SetupGetStringFieldW(
&ContextDevice,
1, /* Field index */
InfInstallSection, RequiredSize,
&RequiredSize);
}
if (!Result)
goto cleanup;
TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n", TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n",
debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile), debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile),
debugstr_w(InfInstallSection), Rank); debugstr_w(SectionName), Rank);
driverInfo->DriverRank = Rank; driverInfo->Params.Rank = Rank;
memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME)); memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME));
memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID)); memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
driverInfo->Info.DriverType = DriverType; driverInfo->Info.DriverType = DriverType;
@ -233,8 +210,8 @@ AddDriverToList(
{ {
struct DriverInfoElement *CurrentDriver; struct DriverInfoElement *CurrentDriver;
CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry); CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry);
if (CurrentDriver->DriverRank > Rank || if (CurrentDriver->Params.Rank > Rank ||
(CurrentDriver->DriverRank == Rank && CurrentDriver->DriverDate.QuadPart < driverInfo->DriverDate.QuadPart)) (CurrentDriver->Params.Rank == Rank && CurrentDriver->DriverDate.QuadPart < driverInfo->DriverDate.QuadPart))
{ {
/* Insert before the current item */ /* Insert before the current item */
InsertHeadList(PreviousEntry->Blink, &driverInfo->ListEntry); InsertHeadList(PreviousEntry->Blink, &driverInfo->ListEntry);
@ -259,7 +236,78 @@ cleanup:
} }
if (hFile != INVALID_HANDLE_VALUE) if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile); CloseHandle(hFile);
HeapFree(GetProcessHeap(), 0, InfInstallSection);
return ret;
}
static BOOL
AddDriverToList(
IN PLIST_ENTRY DriverListHead,
IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
IN LPGUID ClassGuid,
IN INFCONTEXT ContextDevice,
IN struct InfFileDetails *InfFileDetails,
IN LPCWSTR InfFile,
IN LPCWSTR ProviderName,
IN LPCWSTR ManufacturerName,
IN LPCWSTR MatchingId,
IN FILETIME DriverDate,
IN DWORDLONG DriverVersion,
IN DWORD Rank)
{
LPWSTR SectionName = NULL;
LPWSTR DriverDescription = NULL;
BOOL Result;
BOOL ret = FALSE;
/* Read SectionName */
SectionName = MyMalloc(LINE_LEN);
if (!SectionName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
ZeroMemory(SectionName, LINE_LEN);
Result = SetupGetStringFieldW(
&ContextDevice,
1,
SectionName, LINE_LEN,
NULL);
if (!Result)
goto cleanup;
/* Read DriverDescription */
DriverDescription = MyMalloc(LINE_LEN);
if (!DriverDescription)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
ZeroMemory(DriverDescription, LINE_LEN);
Result = SetupGetStringFieldW(
&ContextDevice,
0, /* Field index */
DriverDescription, LINE_LEN,
NULL);
ret = AddKnownDriverToList(
DriverListHead,
DriverType,
ClassGuid,
InfFileDetails,
InfFile,
SectionName,
DriverDescription,
ProviderName,
ManufacturerName,
MatchingId,
DriverDate,
DriverVersion,
Rank);
cleanup:
MyFree(SectionName);
MyFree(DriverDescription);
return ret; return ret;
} }
@ -517,6 +565,152 @@ done:
return Result; return Result;
} }
#if WIN32_WINNT < 0x0600
/* WARNING:
* This code has been copied from advapi32/reg/reg.c,
* so this dll can be tested as is on Windows XP
*/
#define RRF_RT_REG_NONE (1 << 0)
#define RRF_RT_REG_SZ (1 << 1)
#define RRF_RT_REG_EXPAND_SZ (1 << 2)
#define RRF_RT_REG_BINARY (1 << 3)
#define RRF_RT_REG_DWORD (1 << 4)
#define RRF_RT_REG_MULTI_SZ (1 << 5)
#define RRF_RT_REG_QWORD (1 << 6)
#define RRF_RT_DWORD (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD)
#define RRF_RT_QWORD (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD)
#define RRF_NOEXPAND (1 << 28)
#define RRF_ZEROONFAILURE (1 << 29)
static VOID
RegpApplyRestrictions( DWORD dwFlags, DWORD dwType, DWORD cbData,
PLONG ret )
{
/* Check if the type is restricted by the passed flags */
if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA)
{
DWORD dwMask = 0;
switch (dwType)
{
case REG_NONE: dwMask = RRF_RT_REG_NONE; break;
case REG_SZ: dwMask = RRF_RT_REG_SZ; break;
case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break;
case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break;
case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break;
case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break;
case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break;
}
if (dwFlags & dwMask)
{
/* Type is not restricted, check for size mismatch */
if (dwType == REG_BINARY)
{
DWORD cbExpect = 0;
if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD)
cbExpect = 4;
else if ((dwFlags & RRF_RT_DWORD) == RRF_RT_QWORD)
cbExpect = 8;
if (cbExpect && cbData != cbExpect)
*ret = ERROR_DATATYPE_MISMATCH;
}
}
else *ret = ERROR_UNSUPPORTED_TYPE;
}
}
static LONG WINAPI
RegGetValueW( HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue,
DWORD dwFlags, LPDWORD pdwType, PVOID pvData,
LPDWORD pcbData )
{
DWORD dwType, cbData = pcbData ? *pcbData : 0;
PVOID pvBuf = NULL;
LONG ret;
TRACE("(%p,%s,%s,%ld,%p,%p,%p=%ld)\n",
hKey, debugstr_w(pszSubKey), debugstr_w(pszValue), dwFlags, pdwType,
pvData, pcbData, cbData);
if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND))
return ERROR_INVALID_PARAMETER;
if (pszSubKey && pszSubKey[0])
{
ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey);
if (ret != ERROR_SUCCESS) return ret;
}
ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, pvData, &cbData);
/* If we are going to expand we need to read in the whole the value even
* if the passed buffer was too small as the expanded string might be
* smaller than the unexpanded one and could fit into cbData bytes. */
if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) &&
(dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)))
{
do {
if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData);
if (!pvBuf)
{
ret = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (ret == ERROR_MORE_DATA)
ret = RegQueryValueExW(hKey, pszValue, NULL,
&dwType, pvBuf, &cbData);
else
{
/* Even if cbData was large enough we have to copy the
* string since ExpandEnvironmentStrings can't handle
* overlapping buffers. */
CopyMemory(pvBuf, pvData, cbData);
}
/* Both the type or the value itself could have been modified in
* between so we have to keep retrying until the buffer is large
* enough or we no longer have to expand the value. */
} while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA);
if (ret == ERROR_SUCCESS)
{
if (dwType == REG_EXPAND_SZ)
{
cbData = ExpandEnvironmentStringsW(pvBuf, pvData,
pcbData ? *pcbData : 0);
dwType = REG_SZ;
if(pcbData && cbData > *pcbData)
ret = ERROR_MORE_DATA;
}
else if (pcbData)
CopyMemory(pvData, pvBuf, *pcbData);
}
if (pvBuf) HeapFree(GetProcessHeap(), 0, pvBuf);
}
if (pszSubKey && pszSubKey[0])
RegCloseKey(hKey);
RegpApplyRestrictions(dwFlags, dwType, cbData, &ret);
if (pcbData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE))
ZeroMemory(pvData, *pcbData);
if (pdwType) *pdwType = dwType;
if (pcbData) *pcbData = cbData;
return ret;
}
#endif /* End of code copied from advapi32/reg/reg.c */
/*********************************************************************** /***********************************************************************
* SetupDiBuildDriverInfoList (SETUPAPI.@) * SetupDiBuildDriverInfoList (SETUPAPI.@)
*/ */
@ -592,7 +786,95 @@ SetupDiBuildDriverInfoList(
} }
} }
if (InstallParams.Flags & DI_ENUMSINGLEINF) if (InstallParams.FlagsEx & DI_FLAGSEX_INSTALLEDDRIVER)
{
HKEY hDriverKey;
WCHAR InfFileName[MAX_PATH];
WCHAR InfFileSection[MAX_PATH];
ULONG RequiredSize;
struct DeviceInfoElement *devInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
struct InfFileDetails *infFileDetails = NULL;
FILETIME DriverDate;
LONG rc;
DWORD len;
/* Prepend inf directory name to file name */
len = sizeof(InfFileName) / sizeof(InfFileName[0]);
RequiredSize = GetSystemWindowsDirectoryW(InfFileName, len);
if (RequiredSize == 0 || RequiredSize >= len)
goto done;
if (*InfFileName && InfFileName[strlenW(InfFileName) - 1] != '\\')
strcatW(InfFileName, BackSlash);
strcatW(InfFileName, InfDirectory);
/* Read some information from registry, before creating the driver structure */
hDriverKey = SetupDiOpenDevRegKey(
DeviceInfoSet,
DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
KEY_QUERY_VALUE);
if (hDriverKey == INVALID_HANDLE_VALUE)
goto done;
RequiredSize = len - strlenW(InfFileName);
rc = RegGetValueW(
hDriverKey,
NULL,
REGSTR_VAL_INFPATH,
RRF_RT_REG_SZ,
NULL,
&InfFileName[strlenW(InfFileName)],
&RequiredSize);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
CloseHandle(hDriverKey);
goto done;
}
RequiredSize = sizeof(InfFileSection);
rc = RegGetValueW(
hDriverKey,
NULL,
REGSTR_VAL_INFSECTION,
RRF_RT_REG_SZ,
NULL,
InfFileSection,
&RequiredSize);
if (rc != ERROR_SUCCESS)
{
SetLastError(rc);
CloseHandle(hDriverKey);
goto done;
}
TRACE("Current driver in %s/%s\n", debugstr_w(InfFileName), debugstr_w(InfFileSection));
infFileDetails = CreateInfFileDetails(InfFileName);
if (!infFileDetails)
{
CloseHandle(hDriverKey);
goto done;
}
DriverDate.dwLowDateTime = DriverDate.dwHighDateTime = 0; /* FIXME */
CloseHandle(hDriverKey);
ret = AddKnownDriverToList(
pDriverListHead,
SPDIT_COMPATDRIVER,
&devInfo->ClassGuid,
infFileDetails,
InfFileName,
InfFileSection, /* Yes, we don't care of section extension */
L"DriverDescription", /* FIXME */
L"ProviderName", /* FIXME */
L"ManufacturerName", /* FIXME */
L"MatchingId", /* FIXME */
DriverDate,
0, /* FIXME: DriverVersion */
0);
if (!ret)
DereferenceInfFile(infFileDetails);
Result = FALSE;
}
else if (InstallParams.Flags & DI_ENUMSINGLEINF)
{ {
/* InstallParams.DriverPath contains the name of a .inf file */ /* InstallParams.DriverPath contains the name of a .inf file */
RequiredSize = strlenW(InstallParams.DriverPath) + 2; RequiredSize = strlenW(InstallParams.DriverPath) + 2;
@ -1380,7 +1662,7 @@ SetupDiSetSelectedDriverW(
DriverInfoData->Reserved = (ULONG_PTR)ItemList; DriverInfoData->Reserved = (ULONG_PTR)ItemList;
ret = TRUE; ret = TRUE;
TRACE("Choosing driver whose rank is 0x%lx\n", TRACE("Choosing driver whose rank is 0x%lx\n",
(*pDriverInfo)->DriverRank); (*pDriverInfo)->Params.Rank);
if (DeviceInfoData) if (DeviceInfoData)
memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID)); memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
} }
@ -1719,6 +2001,58 @@ done:
return ret; return ret;
} }
/***********************************************************************
* SetupDiGetDriverInstallParamsW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetDriverInstallParamsW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN PSP_DRVINFO_DATA_W DriverInfoData,
OUT PSP_DRVINSTALL_PARAMS DriverInstallParams)
{
BOOL ret = FALSE;
TRACE("%p %p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData, DriverInstallParams);
if (!DeviceInfoSet || !DriverInfoData || !DriverInstallParams)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
SetLastError(ERROR_INVALID_HANDLE);
else if (((struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (DriverInstallParams->cbSize != sizeof(SP_DRVINSTALL_PARAMS))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
SP_DEVINSTALL_PARAMS InstallParams;
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
if (SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
{
struct DriverInfoElement *driverInfo;
driverInfo = (struct DriverInfoElement *)InstallParams.Reserved;
if (driverInfo == NULL)
SetLastError(ERROR_NO_DRIVER_SELECTED);
else
{
memcpy(
DriverInstallParams,
&driverInfo->Params,
DriverInstallParams->cbSize);
ret = TRUE;
}
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/*********************************************************************** /***********************************************************************
* SetupDiSelectBestCompatDrv (SETUPAPI.@) * SetupDiSelectBestCompatDrv (SETUPAPI.@)
*/ */

View file

@ -332,7 +332,7 @@
@ stdcall SetupDiGetDriverInfoDetailA(ptr ptr ptr ptr long ptr) @ stdcall SetupDiGetDriverInfoDetailA(ptr ptr ptr ptr long ptr)
@ stdcall SetupDiGetDriverInfoDetailW(ptr ptr ptr ptr long ptr) @ stdcall SetupDiGetDriverInfoDetailW(ptr ptr ptr ptr long ptr)
@ stub SetupDiGetDriverInstallParamsA @ stub SetupDiGetDriverInstallParamsA
@ stub SetupDiGetDriverInstallParamsW @ stdcall SetupDiGetDriverInstallParamsW(ptr ptr ptr ptr)
@ stub SetupDiGetDeviceInterfaceAlias @ stub SetupDiGetDeviceInterfaceAlias
@ stdcall SetupDiGetDeviceInterfaceDetailA(long ptr ptr long ptr ptr) @ stdcall SetupDiGetDeviceInterfaceDetailA(long ptr ptr long ptr ptr)
@ stdcall SetupDiGetDeviceInterfaceDetailW(long ptr ptr long ptr ptr) @ stdcall SetupDiGetDeviceInterfaceDetailW(long ptr ptr long ptr ptr)

View file

@ -95,7 +95,7 @@ struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceIn
{ {
LIST_ENTRY ListEntry; LIST_ENTRY ListEntry;
DWORD DriverRank; SP_DRVINSTALL_PARAMS Params;
ULARGE_INTEGER DriverDate; ULARGE_INTEGER DriverDate;
SP_DRVINFO_DATA_V2_W Info; SP_DRVINFO_DATA_V2_W Info;
SP_DRVINFO_DETAIL_DATA_W Details; SP_DRVINFO_DETAIL_DATA_W Details;