reactos/dll/win32/setupapi/driver.c

2192 lines
78 KiB
C

/*
* SetupAPI driver-related functions
*
* Copyright 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"
/* Unicode constants */
static const WCHAR BackSlash[] = {'\\',0};
static const WCHAR ClassGUID[] = {'C','l','a','s','s','G','U','I','D',0};
static const WCHAR DotCoInstallers[] = {'.','C','o','I','n','s','t','a','l','l','e','r','s',0};
static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
static const WCHAR Version[] = {'V','e','r','s','i','o','n',0};
static const WCHAR INF_MANUFACTURER[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
static const WCHAR INF_PROVIDER[] = {'P','r','o','v','i','d','e','r',0};
static const WCHAR INF_DRIVER_VER[] = {'D','r','i','v','e','r','V','e','r',0};
/***********************************************************************
* struct InfFileDetails management
*/
static VOID
ReferenceInfFile(struct InfFileDetails* infFile)
{
InterlockedIncrement(&infFile->References);
}
VOID
DereferenceInfFile(struct InfFileDetails* infFile)
{
if (InterlockedDecrement(&infFile->References) == 0)
{
SetupCloseInfFile(infFile->hInf);
HeapFree(GetProcessHeap(), 0, infFile);
}
}
struct InfFileDetails *
CreateInfFileDetails(
IN LPCWSTR FullInfFileName)
{
struct InfFileDetails *details;
PWCHAR last;
DWORD Needed;
Needed = FIELD_OFFSET(struct InfFileDetails, szData)
+ strlenW(FullInfFileName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
details = HeapAlloc(GetProcessHeap(), 0, Needed);
if (!details)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
memset(details, 0, Needed);
strcpyW(details->szData, FullInfFileName);
last = strrchrW(details->szData, '\\');
if (last)
{
details->DirectoryName = details->szData;
details->FileName = last + 1;
*last = '\0';
}
else
details->FileName = details->szData;
ReferenceInfFile(details);
details->hInf = SetupOpenInfFileW(FullInfFileName, NULL, INF_STYLE_WIN4, NULL);
if (details->hInf == INVALID_HANDLE_VALUE)
{
HeapFree(GetProcessHeap(), 0, details);
return NULL;
}
return details;
}
BOOL
DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
{
DereferenceInfFile(driverInfo->InfFileDetails);
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
HeapFree(GetProcessHeap(), 0, driverInfo);
return TRUE;
}
/***********************************************************************
* Helper functions for SetupDiBuildDriverInfoList
*/
static BOOL
AddKnownDriverToList(
IN PLIST_ENTRY DriverListHead,
IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
IN LPGUID ClassGuid,
IN struct InfFileDetails *InfFileDetails,
IN LPCWSTR InfFile,
IN LPCWSTR SectionName,
IN LPCWSTR DriverDescription,
IN LPCWSTR ProviderName,
IN LPCWSTR ManufacturerName,
IN LPCWSTR MatchingId,
IN FILETIME DriverDate,
IN DWORDLONG DriverVersion,
IN DWORD Rank)
{
struct DriverInfoElement *driverInfo = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL Result = FALSE;
PLIST_ENTRY PreviousEntry;
BOOL ret = FALSE;
driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
if (!driverInfo)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
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_W);
driverInfo->Details.Reserved = (ULONG_PTR)driverInfo;
/* Copy InfFileName field */
lstrcpynW(driverInfo->Details.InfFileName, InfFile, MAX_PATH - 1);
driverInfo->Details.InfFileName[MAX_PATH - 1] = '\0';
/* Fill InfDate field */
hFile = CreateFileW(
InfFile,
GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto cleanup;
Result = GetFileTime(hFile, NULL, NULL, &driverInfo->Details.InfDate);
if (!Result)
goto cleanup;
/* Fill SectionName field */
lstrcpynW(driverInfo->Details.SectionName, SectionName, LINE_LEN);
/* Fill DrvDescription field */
lstrcpynW(driverInfo->Details.DrvDescription, DriverDescription, LINE_LEN);
/* Copy MatchingId information */
if (MatchingId)
{
driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
if (!driverInfo->MatchingId)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
RtlCopyMemory(driverInfo->MatchingId, MatchingId, (strlenW(MatchingId) + 1) * sizeof(WCHAR));
}
else
driverInfo->MatchingId = NULL;
TRACE("Adding driver '%s' [%s/%s] (Rank 0x%lx)\n",
debugstr_w(driverInfo->Details.DrvDescription), debugstr_w(InfFile),
debugstr_w(SectionName), Rank);
driverInfo->Params.Rank = Rank;
memcpy(&driverInfo->DriverDate, &DriverDate, sizeof(FILETIME));
memcpy(&driverInfo->ClassGuid, ClassGuid, sizeof(GUID));
driverInfo->Info.DriverType = DriverType;
driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
lstrcpynW(driverInfo->Info.Description, driverInfo->Details.DrvDescription, LINE_LEN - 1);
driverInfo->Info.Description[LINE_LEN - 1] = '\0';
lstrcpynW(driverInfo->Info.MfgName, ManufacturerName, LINE_LEN - 1);
driverInfo->Info.MfgName[LINE_LEN - 1] = '\0';
if (ProviderName)
{
lstrcpynW(driverInfo->Info.ProviderName, ProviderName, LINE_LEN - 1);
driverInfo->Info.ProviderName[LINE_LEN - 1] = '\0';
}
else
driverInfo->Info.ProviderName[0] = '\0';
driverInfo->Info.DriverDate = DriverDate;
driverInfo->Info.DriverVersion = DriverVersion;
ReferenceInfFile(InfFileDetails);
driverInfo->InfFileDetails = InfFileDetails;
/* Insert current driver in driver list, according to its rank */
PreviousEntry = DriverListHead->Flink;
while (PreviousEntry != DriverListHead)
{
struct DriverInfoElement *CurrentDriver;
CurrentDriver = CONTAINING_RECORD(PreviousEntry, struct DriverInfoElement, ListEntry);
if (CurrentDriver->Params.Rank > Rank ||
(CurrentDriver->Params.Rank == Rank && CurrentDriver->DriverDate.QuadPart < driverInfo->DriverDate.QuadPart))
{
/* Insert before the current item */
InsertHeadList(PreviousEntry->Blink, &driverInfo->ListEntry);
break;
}
PreviousEntry = PreviousEntry->Flink;
}
if (PreviousEntry == DriverListHead)
{
/* Insert at the end of the list */
InsertTailList(DriverListHead, &driverInfo->ListEntry);
}
ret = TRUE;
cleanup:
if (!ret)
{
if (driverInfo)
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
HeapFree(GetProcessHeap(), 0, driverInfo);
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
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;
}
static BOOL
GetVersionInformationFromInfFile(
IN HINF hInf,
OUT LPGUID ClassGuid,
OUT LPWSTR* pProviderName,
OUT FILETIME* DriverDate,
OUT DWORDLONG* DriverVersion)
{
DWORD RequiredSize;
WCHAR guidW[MAX_GUID_STRING_LEN + 1];
LPWSTR DriverVer = NULL;
LPWSTR ProviderName = NULL;
LPWSTR pComma; /* Points into DriverVer */
LPWSTR pVersion = NULL; /* Points into DriverVer */
SYSTEMTIME SystemTime;
BOOL Result;
BOOL ret = FALSE; /* Final result */
/* Get class Guid */
if (!SetupGetLineTextW(
NULL, /* Context */
hInf,
Version, ClassGUID,
guidW, sizeof(guidW),
NULL /* Required size */))
{
goto cleanup;
}
guidW[37] = '\0'; /* Replace the } by a NULL character */
if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
{
SetLastError(ERROR_GEN_FAILURE);
goto cleanup;
}
/* Get provider name */
Result = SetupGetLineTextW(
NULL, /* Context */
hInf, Version, INF_PROVIDER,
NULL, 0,
&RequiredSize);
if (Result)
{
/* We know the needed buffer size */
ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!ProviderName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
Result = SetupGetLineTextW(
NULL, /* Context */
hInf, Version, INF_PROVIDER,
ProviderName, RequiredSize,
&RequiredSize);
}
if (!Result)
goto cleanup;
*pProviderName = ProviderName;
/* Read the "DriverVer" value */
Result = SetupGetLineTextW(
NULL, /* Context */
hInf, Version, INF_DRIVER_VER,
NULL, 0,
&RequiredSize);
if (Result)
{
/* We know know the needed buffer size */
DriverVer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!DriverVer)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
Result = SetupGetLineTextW(
NULL, /* Context */
hInf, Version, INF_DRIVER_VER,
DriverVer, RequiredSize,
&RequiredSize);
}
else
{
/* windows sets default date of 00/00/0000 when this directive is missing*/
memset(DriverDate, 0, sizeof(FILETIME));
*DriverVersion = 0;
return TRUE;
}
/* Get driver date and driver version, by analyzing the "DriverVer" value */
pComma = strchrW(DriverVer, ',');
if (pComma != NULL)
{
*pComma = UNICODE_NULL;
pVersion = pComma + 1;
}
/* Get driver date version. Invalid date = 00/00/00 */
memset(DriverDate, 0, sizeof(FILETIME));
if (strlenW(DriverVer) == 10
&& (DriverVer[2] == '-' || DriverVer[2] == '/')
&& (DriverVer[5] == '-' || DriverVer[5] == '/'))
{
memset(&SystemTime, 0, sizeof(SYSTEMTIME));
DriverVer[2] = DriverVer[5] = UNICODE_NULL;
SystemTime.wMonth = ((DriverVer[0] - '0') * 10) + DriverVer[1] - '0';
SystemTime.wDay = ((DriverVer[3] - '0') * 10) + DriverVer[4] - '0';
SystemTime.wYear = ((DriverVer[6] - '0') * 1000) + ((DriverVer[7] - '0') * 100) + ((DriverVer[8] - '0') * 10) + DriverVer[9] - '0';
SystemTimeToFileTime(&SystemTime, DriverDate);
}
/* Get driver version. Invalid version = 0.0.0.0 */
*DriverVersion = 0;
if (pVersion)
{
WORD Major, Minor = 0, Revision = 0, Build = 0;
LPWSTR pMinor = NULL, pRevision = NULL, pBuild = NULL;
LARGE_INTEGER fullVersion;
pMinor = strchrW(pVersion, '.');
if (pMinor)
{
*pMinor = 0;
pRevision = strchrW(++pMinor, '.');
Minor = atoiW(pMinor);
}
if (pRevision)
{
*pRevision = 0;
pBuild = strchrW(++pRevision, '.');
Revision = atoiW(pRevision);
}
if (pBuild)
{
*pBuild = 0;
pBuild++;
Build = atoiW(pBuild);
}
Major = atoiW(pVersion);
fullVersion.u.HighPart = Major << 16 | Minor;
fullVersion.u.LowPart = Revision << 16 | Build;
memcpy(DriverVersion, &fullVersion, sizeof(LARGE_INTEGER));
}
ret = TRUE;
cleanup:
if (!ret)
{
HeapFree(GetProcessHeap(), 0, ProviderName);
*pProviderName = NULL;
}
HeapFree(GetProcessHeap(), 0, DriverVer);
return ret;
}
static BOOL
GetHardwareAndCompatibleIDsLists(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData,
OUT LPWSTR *pHardwareIDs OPTIONAL,
OUT LPDWORD pHardwareIDsRequiredSize OPTIONAL,
OUT LPWSTR *pCompatibleIDs OPTIONAL,
OUT LPDWORD pCompatibleIDsRequiredSize OPTIONAL)
{
LPWSTR HardwareIDs = NULL;
LPWSTR CompatibleIDs = NULL;
DWORD RequiredSize;
BOOL Result;
/* Get hardware IDs list */
Result = FALSE;
RequiredSize = 512; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
MyFree(HardwareIDs);
HardwareIDs = MyMalloc(RequiredSize);
if (!HardwareIDs)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
Result = SetupDiGetDeviceRegistryPropertyW(
DeviceInfoSet,
DeviceInfoData,
SPDRP_HARDWAREID,
NULL,
(PBYTE)HardwareIDs,
RequiredSize,
&RequiredSize);
}
if (!Result)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
/* No hardware ID for this device */
MyFree(HardwareIDs);
HardwareIDs = NULL;
RequiredSize = 0;
}
else
goto done;
}
if (pHardwareIDs)
*pHardwareIDs = HardwareIDs;
if (pHardwareIDsRequiredSize)
*pHardwareIDsRequiredSize = RequiredSize;
/* Get compatible IDs list */
Result = FALSE;
RequiredSize = 512; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
MyFree(CompatibleIDs);
CompatibleIDs = MyMalloc(RequiredSize);
if (!CompatibleIDs)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
Result = SetupDiGetDeviceRegistryPropertyW(
DeviceInfoSet,
DeviceInfoData,
SPDRP_COMPATIBLEIDS,
NULL,
(PBYTE)CompatibleIDs,
RequiredSize,
&RequiredSize);
}
if (!Result)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
/* No compatible ID for this device */
MyFree(CompatibleIDs);
CompatibleIDs = NULL;
RequiredSize = 0;
}
else
goto done;
}
if (pCompatibleIDs)
*pCompatibleIDs = CompatibleIDs;
if (pCompatibleIDsRequiredSize)
*pCompatibleIDsRequiredSize = RequiredSize;
Result = TRUE;
done:
if (!Result)
{
MyFree(HardwareIDs);
MyFree(CompatibleIDs);
}
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_QWORD) == 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)/sizeof(WCHAR) : 0);
dwType = REG_SZ;
if(pcbData && cbData > ((*pcbData)/sizeof(WCHAR)))
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.@)
*/
BOOL WINAPI
SetupDiBuildDriverInfoList(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN DWORD DriverType)
{
struct DeviceInfoSet *list;
SP_DEVINSTALL_PARAMS_W InstallParams;
PVOID Buffer = NULL;
struct InfFileDetails *currentInfFileDetails = NULL;
LPWSTR ProviderName = NULL;
LPWSTR ManufacturerName = NULL;
WCHAR ManufacturerSection[LINE_LEN + 1];
LPWSTR HardwareIDs = NULL;
LPWSTR CompatibleIDs = NULL;
LPWSTR FullInfFileName = NULL;
LPWSTR ExcludeFromSelect = NULL;
FILETIME DriverDate;
DWORDLONG DriverVersion = 0;
DWORD RequiredSize;
BOOL ret = FALSE;
TRACE("%p %p %ld\n", DeviceInfoSet, DeviceInfoData, DriverType);
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->HKLM != HKEY_LOCAL_MACHINE)
SetLastError(ERROR_INVALID_HANDLE);
else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
PLIST_ENTRY pDriverListHead = &list->DriverListHead;
BOOL Result;
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
Result = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
if (!Result)
goto done;
if (DeviceInfoData)
{
struct DeviceInfo *devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (!(devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
pDriverListHead = &devInfo->DriverListHead;
}
if (DriverType == SPDIT_COMPATDRIVER)
{
/* Get hardware and compatible IDs lists */
Result = GetHardwareAndCompatibleIDsLists(
DeviceInfoSet,
DeviceInfoData,
&HardwareIDs,
NULL,
&CompatibleIDs,
NULL);
if (!Result)
goto done;
if (!HardwareIDs && !CompatibleIDs)
{
SetLastError(ERROR_FILE_NOT_FOUND);
goto done;
}
}
if (InstallParams.FlagsEx & DI_FLAGSEX_INSTALLEDDRIVER)
{
HKEY hDriverKey;
WCHAR InfFileName[MAX_PATH];
WCHAR InfFileSection[MAX_PATH];
ULONG RequiredSize;
struct DeviceInfo *devInfo = (struct DeviceInfo *)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)) * sizeof(WCHAR);
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 */
RequiredSize = strlenW(InstallParams.DriverPath) + 2;
Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!Buffer)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
strcpyW(Buffer, InstallParams.DriverPath);
((LPWSTR)Buffer)[RequiredSize - 1] = 0;
Result = TRUE;
}
else
{
/* Enumerate .inf files */
Result = FALSE;
RequiredSize = 32768; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, Buffer);
Buffer = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!Buffer)
{
Result = FALSE;
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
break;
}
Result = SetupGetInfFileListW(
*InstallParams.DriverPath ? InstallParams.DriverPath : NULL,
INF_STYLE_WIN4,
Buffer, RequiredSize,
&RequiredSize);
}
if (!Result && GetLastError() == ERROR_FILE_NOT_FOUND)
{
/* No .inf file in specified directory. So, we should
* success as we created an empty driver info list.
*/
ret = TRUE;
goto done;
}
}
if (Result)
{
LPCWSTR filename;
LPWSTR pFullFilename;
if (InstallParams.Flags & DI_ENUMSINGLEINF)
{
/* Only a filename */
FullInfFileName = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
if (!FullInfFileName)
goto done;
pFullFilename = &FullInfFileName[0];
}
else if (*InstallParams.DriverPath)
{
/* Directory name specified */
DWORD len;
len = GetFullPathNameW(InstallParams.DriverPath, 0, NULL, NULL);
if (len == 0)
goto done;
FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + MAX_PATH) * sizeof(WCHAR));
if (!FullInfFileName)
goto done;
len = GetFullPathNameW(InstallParams.DriverPath, len, FullInfFileName, NULL);
if (len == 0)
goto done;
if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
strcatW(FullInfFileName, BackSlash);
pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
}
else
{
/* Nothing specified ; need to get the %SYSTEMROOT%\ directory */
DWORD len;
len = GetSystemWindowsDirectoryW(NULL, 0);
if (len == 0)
goto done;
FullInfFileName = HeapAlloc(GetProcessHeap(), 0, (len + 1 + strlenW(InfDirectory) + MAX_PATH) * sizeof(WCHAR));
if (!FullInfFileName)
goto done;
len = GetSystemWindowsDirectoryW(FullInfFileName, len);
if (len == 0)
goto done;
if (*FullInfFileName && FullInfFileName[strlenW(FullInfFileName) - 1] != '\\')
strcatW(FullInfFileName, BackSlash);
strcatW(FullInfFileName, InfDirectory);
pFullFilename = &FullInfFileName[strlenW(FullInfFileName)];
}
for (filename = (LPCWSTR)Buffer; *filename; filename += strlenW(filename) + 1)
{
INFCONTEXT ContextManufacturer, ContextDevice;
GUID ClassGuid;
strcpyW(pFullFilename, filename);
TRACE("Opening file %s\n", debugstr_w(FullInfFileName));
currentInfFileDetails = CreateInfFileDetails(FullInfFileName);
if (!currentInfFileDetails)
continue;
if (!GetVersionInformationFromInfFile(
currentInfFileDetails->hInf,
&ClassGuid,
&ProviderName,
&DriverDate,
&DriverVersion))
{
DereferenceInfFile(currentInfFileDetails);
currentInfFileDetails = NULL;
continue;
}
if (DriverType == SPDIT_CLASSDRIVER)
{
/* Check if the ClassGuid in this .inf file is corresponding with our needs */
if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
{
goto next;
}
}
if (InstallParams.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS)
{
/* Read ExcludeFromSelect control flags */
/* FIXME */
}
else
FIXME("ExcludeFromSelect list ignored\n");
/* Get the manufacturers list */
Result = SetupFindFirstLineW(currentInfFileDetails->hInf, INF_MANUFACTURER, NULL, &ContextManufacturer);
while (Result)
{
Result = SetupGetStringFieldW(
&ContextManufacturer,
0, /* Field index */
NULL, 0,
&RequiredSize);
if (Result)
{
/* We got the needed size for the buffer */
ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!ManufacturerName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
Result = SetupGetStringFieldW(
&ContextManufacturer,
0, /* Field index */
ManufacturerName, RequiredSize,
&RequiredSize);
}
/* Get manufacturer section name */
Result = SetupGetStringFieldW(
&ContextManufacturer,
1, /* Field index */
ManufacturerSection, LINE_LEN,
&RequiredSize);
if (Result)
{
ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
/* Add (possible) extension to manufacturer section name */
Result = SetupDiGetActualSectionToInstallW(
currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
if (Result)
{
TRACE("Enumerating devices in manufacturer %s\n", debugstr_w(ManufacturerSection));
Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
}
}
while (Result)
{
if (DriverType == SPDIT_CLASSDRIVER)
{
/* FIXME: Check ExcludeFromSelect list */
if (!AddDriverToList(
pDriverListHead,
DriverType,
&ClassGuid,
ContextDevice,
currentInfFileDetails,
FullInfFileName,
ProviderName,
ManufacturerName,
NULL,
DriverDate, DriverVersion,
0))
{
break;
}
}
else /* DriverType = SPDIT_COMPATDRIVER */
{
/* 1. Get all fields */
DWORD FieldCount = SetupGetFieldCount(&ContextDevice);
DWORD DriverRank;
DWORD i;
LPCWSTR currentId;
BOOL DriverAlreadyAdded;
for (i = 2; i <= FieldCount; i++)
{
LPWSTR DeviceId = NULL;
Result = FALSE;
RequiredSize = 128; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, DeviceId);
DeviceId = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!DeviceId)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto done;
}
Result = SetupGetStringFieldW(
&ContextDevice,
i,
DeviceId, RequiredSize,
&RequiredSize);
}
if (!Result)
{
HeapFree(GetProcessHeap(), 0, DeviceId);
goto done;
}
/* FIXME: Check ExcludeFromSelect list */
DriverAlreadyAdded = FALSE;
if (HardwareIDs)
{
for (DriverRank = 0, currentId = (LPCWSTR)HardwareIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
{
if (strcmpiW(DeviceId, currentId) == 0)
{
AddDriverToList(
pDriverListHead,
DriverType,
&ClassGuid,
ContextDevice,
currentInfFileDetails,
FullInfFileName,
ProviderName,
ManufacturerName,
currentId,
DriverDate, DriverVersion,
DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
DriverAlreadyAdded = TRUE;
}
}
}
if (CompatibleIDs)
{
for (DriverRank = 0, currentId = (LPCWSTR)CompatibleIDs; !DriverAlreadyAdded && *currentId; currentId += strlenW(currentId) + 1, DriverRank++)
{
if (strcmpiW(DeviceId, currentId) == 0)
{
AddDriverToList(
pDriverListHead,
DriverType,
&ClassGuid,
ContextDevice,
currentInfFileDetails,
FullInfFileName,
ProviderName,
ManufacturerName,
currentId,
DriverDate, DriverVersion,
DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
DriverAlreadyAdded = TRUE;
}
}
}
HeapFree(GetProcessHeap(), 0, DeviceId);
}
}
Result = SetupFindNextLine(&ContextDevice, &ContextDevice);
}
HeapFree(GetProcessHeap(), 0, ManufacturerName);
ManufacturerName = NULL;
Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
}
ret = TRUE;
next:
HeapFree(GetProcessHeap(), 0, ProviderName);
HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
ProviderName = ExcludeFromSelect = NULL;
DereferenceInfFile(currentInfFileDetails);
currentInfFileDetails = NULL;
}
ret = TRUE;
}
}
done:
if (ret)
{
if (DeviceInfoData)
{
InstallParams.Flags |= DI_DIDCOMPAT;
InstallParams.FlagsEx |= DI_FLAGSEX_DIDCOMPATINFO;
}
else
{
InstallParams.Flags |= DI_DIDCLASS;
InstallParams.FlagsEx |= DI_FLAGSEX_DIDINFOLIST;
}
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
}
HeapFree(GetProcessHeap(), 0, ProviderName);
HeapFree(GetProcessHeap(), 0, ManufacturerName);
MyFree(HardwareIDs);
MyFree(CompatibleIDs);
HeapFree(GetProcessHeap(), 0, FullInfFileName);
HeapFree(GetProcessHeap(), 0, ExcludeFromSelect);
if (currentInfFileDetails)
DereferenceInfFile(currentInfFileDetails);
HeapFree(GetProcessHeap(), 0, Buffer);
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiDestroyDriverInfoList (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiDestroyDriverInfoList(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN DWORD DriverType)
{
struct DeviceInfoSet *list;
BOOL ret = FALSE;
TRACE("%p %p 0x%lx\n", DeviceInfoSet, DeviceInfoData, DriverType);
if (!DeviceInfoSet)
SetLastError(ERROR_INVALID_HANDLE);
else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
SetLastError(ERROR_INVALID_HANDLE);
else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
PLIST_ENTRY ListEntry;
struct DriverInfoElement *driverInfo;
SP_DEVINSTALL_PARAMS_W InstallParams;
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams))
goto done;
if (!DeviceInfoData)
/* Fall back to destroying class driver list */
DriverType = SPDIT_CLASSDRIVER;
if (DriverType == SPDIT_CLASSDRIVER)
{
while (!IsListEmpty(&list->DriverListHead))
{
ListEntry = RemoveHeadList(&list->DriverListHead);
driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
DestroyDriverInfoElement(driverInfo);
}
InstallParams.Reserved = 0;
InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParams);
}
else
{
SP_DEVINSTALL_PARAMS_W InstallParamsSet;
struct DeviceInfo *deviceInfo;
InstallParamsSet.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
if (!SetupDiGetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet))
goto done;
deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
while (!IsListEmpty(&deviceInfo->DriverListHead))
{
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
driverInfo = CONTAINING_RECORD(ListEntry, struct DriverInfoElement, ListEntry);
if ((PVOID)InstallParamsSet.Reserved == driverInfo)
{
InstallParamsSet.Reserved = 0;
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
}
DestroyDriverInfoElement(driverInfo);
}
InstallParams.Reserved = 0;
InstallParams.Flags &= ~DI_DIDCOMPAT;
InstallParams.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
}
}
done:
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiEnumDriverInfoA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiEnumDriverInfoA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN DWORD DriverType,
IN DWORD MemberIndex,
OUT PSP_DRVINFO_DATA_A DriverInfoData)
{
SP_DRVINFO_DATA_V2_W driverInfoData2W;
BOOL ret = FALSE;
TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
DriverType, MemberIndex, DriverInfoData);
if (DriverInfoData == NULL)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
ret = SetupDiEnumDriverInfoW(DeviceInfoSet, DeviceInfoData,
DriverType, MemberIndex, &driverInfoData2W);
if (ret)
{
/* Do W->A conversion */
DriverInfoData->DriverType = driverInfoData2W.DriverType;
DriverInfoData->Reserved = driverInfoData2W.Reserved;
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->Description[0] = '\0';
ret = FALSE;
}
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->MfgName[0] = '\0';
ret = FALSE;
}
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->ProviderName[0] = '\0';
ret = FALSE;
}
if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
{
/* Copy more fields */
DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
}
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiEnumDriverInfoW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiEnumDriverInfoW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN DWORD DriverType,
IN DWORD MemberIndex,
OUT PSP_DRVINFO_DATA_W DriverInfoData)
{
PLIST_ENTRY ListHead;
BOOL ret = FALSE;
TRACE("%p %p 0x%lx %ld %p\n", DeviceInfoSet, DeviceInfoData,
DriverType, MemberIndex, DriverInfoData);
if (!DeviceInfoSet || !DriverInfoData)
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 (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
struct DeviceInfo *devInfo = NULL;
PLIST_ENTRY ItemList;
if (DeviceInfoData)
devInfo = (struct DeviceInfo *)DeviceInfoData->Reserved;
if (!devInfo || (devInfo->CreationFlags & DICD_INHERIT_CLASSDRVS))
{
ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
}
else
{
ListHead = &devInfo->DriverListHead;
}
ItemList = ListHead->Flink;
while (ItemList != ListHead && MemberIndex-- > 0)
ItemList = ItemList->Flink;
if (ItemList == ListHead)
SetLastError(ERROR_NO_MORE_ITEMS);
else
{
struct DriverInfoElement *DrvInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
memcpy(
&DriverInfoData->DriverType,
&DrvInfo->Info.DriverType,
DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
ret = TRUE;
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiGetSelectedDriverA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetSelectedDriverA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
OUT PSP_DRVINFO_DATA_A DriverInfoData)
{
SP_DRVINFO_DATA_V2_W driverInfoData2W;
BOOL ret = FALSE;
if (DriverInfoData == NULL)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
driverInfoData2W.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
ret = SetupDiGetSelectedDriverW(DeviceInfoSet,
DeviceInfoData,
&driverInfoData2W);
if (ret)
{
/* Do W->A conversion */
DriverInfoData->DriverType = driverInfoData2W.DriverType;
DriverInfoData->Reserved = driverInfoData2W.Reserved;
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.Description, -1,
DriverInfoData->Description, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->Description[0] = '\0';
ret = FALSE;
}
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.MfgName, -1,
DriverInfoData->MfgName, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->MfgName[0] = '\0';
ret = FALSE;
}
if (WideCharToMultiByte(CP_ACP, 0, driverInfoData2W.ProviderName, -1,
DriverInfoData->ProviderName, LINE_LEN, NULL, NULL) == 0)
{
DriverInfoData->ProviderName[0] = '\0';
ret = FALSE;
}
if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
{
/* Copy more fields */
DriverInfoData->DriverDate = driverInfoData2W.DriverDate;
DriverInfoData->DriverVersion = driverInfoData2W.DriverVersion;
}
}
}
return ret;
}
/***********************************************************************
* SetupDiGetSelectedDriverW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetSelectedDriverW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
OUT PSP_DRVINFO_DATA_W DriverInfoData)
{
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
if (!DeviceInfoSet || !DriverInfoData)
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 if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
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(
&DriverInfoData->DriverType,
&driverInfo->Info.DriverType,
DriverInfoData->cbSize - FIELD_OFFSET(SP_DRVINFO_DATA_W, DriverType));
ret = TRUE;
}
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiSetSelectedDriverA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSetSelectedDriverA(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL)
{
SP_DRVINFO_DATA_V1_W DriverInfoDataW;
PSP_DRVINFO_DATA_W pDriverInfoDataW = NULL;
BOOL ret = FALSE;
if (DriverInfoData != NULL)
{
if (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_A) &&
DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_A))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
DriverInfoDataW.Reserved = DriverInfoData->Reserved;
if (DriverInfoDataW.Reserved == 0)
{
DriverInfoDataW.DriverType = DriverInfoData->DriverType;
/* convert the strings to unicode */
if (!MultiByteToWideChar(CP_ACP,
0,
DriverInfoData->Description,
LINE_LEN,
DriverInfoDataW.Description,
LINE_LEN) ||
!MultiByteToWideChar(CP_ACP,
0,
DriverInfoData->ProviderName,
LINE_LEN,
DriverInfoDataW.ProviderName,
LINE_LEN))
{
return FALSE;
}
}
pDriverInfoDataW = (PSP_DRVINFO_DATA_W)&DriverInfoDataW;
}
ret = SetupDiSetSelectedDriverW(DeviceInfoSet,
DeviceInfoData,
pDriverInfoDataW);
if (ret && pDriverInfoDataW != NULL)
{
DriverInfoData->Reserved = DriverInfoDataW.Reserved;
}
return ret;
}
/***********************************************************************
* SetupDiSetSelectedDriverW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiSetSelectedDriverW(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL)
{
BOOL ret = FALSE;
TRACE("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DriverInfoData);
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 if (DriverInfoData && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1_W) && DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V2_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else
{
struct DriverInfoElement **pDriverInfo;
PLIST_ENTRY ListHead, ItemList;
if (DeviceInfoData)
{
pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved;
ListHead = &((struct DeviceInfo *)DeviceInfoData->Reserved)->DriverListHead;
}
else
{
pDriverInfo = (struct DriverInfoElement **)&((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved;
ListHead = &((struct DeviceInfoSet *)DeviceInfoSet)->DriverListHead;
}
if (!DriverInfoData)
{
*pDriverInfo = NULL;
ret = TRUE;
}
else
{
/* Search selected driver in list */
ItemList = ListHead->Flink;
while (ItemList != ListHead)
{
if (DriverInfoData->Reserved != 0)
{
if (DriverInfoData->Reserved == (ULONG_PTR)ItemList)
break;
}
else
{
/* The caller wants to compare only DriverType, Description and ProviderName fields */
struct DriverInfoElement *driverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
if (driverInfo->Info.DriverType == DriverInfoData->DriverType
&& strcmpW(driverInfo->Info.Description, DriverInfoData->Description) == 0
&& strcmpW(driverInfo->Info.ProviderName, DriverInfoData->ProviderName) == 0)
{
break;
}
}
ItemList = ItemList->Flink;
}
if (ItemList == ListHead)
SetLastError(ERROR_INVALID_PARAMETER);
else
{
*pDriverInfo = CONTAINING_RECORD(ItemList, struct DriverInfoElement, ListEntry);
DriverInfoData->Reserved = (ULONG_PTR)ItemList;
ret = TRUE;
TRACE("Choosing driver whose rank is 0x%lx\n",
(*pDriverInfo)->Params.Rank);
if (DeviceInfoData)
memcpy(&DeviceInfoData->ClassGuid, &(*pDriverInfo)->ClassGuid, sizeof(GUID));
}
}
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiGetDriverInfoDetailA (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetDriverInfoDetailA(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN PSP_DRVINFO_DATA_A DriverInfoData,
IN OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData OPTIONAL,
IN DWORD DriverInfoDetailDataSize,
OUT PDWORD RequiredSize OPTIONAL)
{
SP_DRVINFO_DATA_V2_W DriverInfoDataW;
PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailDataW = NULL;
DWORD BufSize = 0;
DWORD HardwareIDLen = 0;
BOOL ret = FALSE;
/* do some sanity checks, the unicode version might do more thorough checks */
if (DriverInfoData == NULL ||
(DriverInfoDetailData == NULL && DriverInfoDetailDataSize != 0) ||
(DriverInfoDetailData != NULL &&
(DriverInfoDetailDataSize < FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) + sizeof(CHAR) ||
DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))))
{
SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup;
}
/* make sure we support both versions of the SP_DRVINFO_DATA structure */
if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1_A))
{
DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V1_W);
}
else if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V2_A))
{
DriverInfoDataW.cbSize = sizeof(SP_DRVINFO_DATA_V2_W);
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup;
}
DriverInfoDataW.DriverType = DriverInfoData->DriverType;
DriverInfoDataW.Reserved = DriverInfoData->Reserved;
/* convert the strings to unicode */
if (MultiByteToWideChar(CP_ACP,
0,
DriverInfoData->Description,
LINE_LEN,
DriverInfoDataW.Description,
LINE_LEN) &&
MultiByteToWideChar(CP_ACP,
0,
DriverInfoData->MfgName,
LINE_LEN,
DriverInfoDataW.MfgName,
LINE_LEN) &&
MultiByteToWideChar(CP_ACP,
0,
DriverInfoData->ProviderName,
LINE_LEN,
DriverInfoDataW.ProviderName,
LINE_LEN))
{
if (DriverInfoDataW.cbSize == sizeof(SP_DRVINFO_DATA_V2_W))
{
DriverInfoDataW.DriverDate = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverDate;
DriverInfoDataW.DriverVersion = ((PSP_DRVINFO_DATA_V2_A)DriverInfoData)->DriverVersion;
}
if (DriverInfoDetailData != NULL)
{
/* calculate the unicode buffer size from the ansi buffer size */
HardwareIDLen = DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID);
BufSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID) +
(HardwareIDLen * sizeof(WCHAR));
DriverInfoDetailDataW = MyMalloc(BufSize);
if (DriverInfoDetailDataW == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Cleanup;
}
/* initialize the buffer */
ZeroMemory(DriverInfoDetailDataW,
BufSize);
DriverInfoDetailDataW->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
}
/* call the unicode version */
ret = SetupDiGetDriverInfoDetailW(DeviceInfoSet,
DeviceInfoData,
&DriverInfoDataW,
DriverInfoDetailDataW,
BufSize,
RequiredSize);
if (ret)
{
if (DriverInfoDetailDataW != NULL)
{
/* convert the SP_DRVINFO_DETAIL_DATA_W structure to ansi */
DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
DriverInfoDetailData->InfDate = DriverInfoDetailDataW->InfDate;
DriverInfoDetailData->Reserved = DriverInfoDetailDataW->Reserved;
if (WideCharToMultiByte(CP_ACP,
0,
DriverInfoDetailDataW->SectionName,
LINE_LEN,
DriverInfoDetailData->SectionName,
LINE_LEN,
NULL,
NULL) &&
WideCharToMultiByte(CP_ACP,
0,
DriverInfoDetailDataW->InfFileName,
MAX_PATH,
DriverInfoDetailData->InfFileName,
MAX_PATH,
NULL,
NULL) &&
WideCharToMultiByte(CP_ACP,
0,
DriverInfoDetailDataW->DrvDescription,
LINE_LEN,
DriverInfoDetailData->DrvDescription,
LINE_LEN,
NULL,
NULL) &&
WideCharToMultiByte(CP_ACP,
0,
DriverInfoDetailDataW->HardwareID,
HardwareIDLen,
DriverInfoDetailData->HardwareID,
HardwareIDLen,
NULL,
NULL))
{
DWORD len, cnt = 0;
DWORD hwidlen = HardwareIDLen;
CHAR *s = DriverInfoDetailData->HardwareID;
/* count the strings in the list */
while (*s != '\0')
{
len = lstrlenA(s) + 1;
if (hwidlen > len)
{
cnt++;
s += len;
hwidlen -= len;
}
else
{
/* looks like the string list wasn't terminated... */
SetLastError(ERROR_INVALID_USER_BUFFER);
ret = FALSE;
break;
}
}
/* make sure CompatIDsOffset points to the second string in the
list, if present */
if (cnt > 1)
{
DriverInfoDetailData->CompatIDsOffset = lstrlenA(DriverInfoDetailData->HardwareID) + 1;
DriverInfoDetailData->CompatIDsLength = (DWORD)(s - DriverInfoDetailData->HardwareID) -
DriverInfoDetailData->CompatIDsOffset + 1;
}
else
{
DriverInfoDetailData->CompatIDsOffset = 0;
DriverInfoDetailData->CompatIDsLength = 0;
}
}
else
{
ret = FALSE;
}
}
if (RequiredSize != NULL)
{
*RequiredSize = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_A, HardwareID) +
(((*RequiredSize) - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR));
}
}
}
Cleanup:
if (DriverInfoDetailDataW != NULL)
{
MyFree(DriverInfoDetailDataW);
}
return ret;
}
/***********************************************************************
* SetupDiGetDriverInfoDetailW (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiGetDriverInfoDetailW(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
IN PSP_DRVINFO_DATA_W DriverInfoData,
IN OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData OPTIONAL,
IN DWORD DriverInfoDetailDataSize,
OUT PDWORD RequiredSize OPTIONAL)
{
BOOL ret = FALSE;
TRACE("%p %p %p %p %lu %p\n", DeviceInfoSet, DeviceInfoData,
DriverInfoData, DriverInfoDetailData,
DriverInfoDetailDataSize, RequiredSize);
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 if (!DriverInfoData)
SetLastError(ERROR_INVALID_PARAMETER);
else if (!DriverInfoDetailData && DriverInfoDetailDataSize != 0)
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverInfoDetailData && DriverInfoDetailDataSize < sizeof(SP_DRVINFO_DETAIL_DATA_W))
SetLastError(ERROR_INVALID_PARAMETER);
else if (DriverInfoDetailData && DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_W))
SetLastError(ERROR_INVALID_USER_BUFFER);
else if (DriverInfoData->Reserved == 0)
SetLastError(ERROR_NO_DRIVER_SELECTED);
else
{
struct DriverInfoElement *driverInfoElement;
LPWSTR HardwareIDs = NULL;
LPWSTR CompatibleIDs = NULL;
LPWSTR pBuffer = NULL;
LPCWSTR DeviceID = NULL;
ULONG HardwareIDsSize, CompatibleIDsSize;
ULONG sizeNeeded, sizeLeft, size;
BOOL Result;
driverInfoElement = (struct DriverInfoElement *)DriverInfoData->Reserved;
/* Get hardware and compatible IDs lists */
Result = GetHardwareAndCompatibleIDsLists(
DeviceInfoSet,
DeviceInfoData,
&HardwareIDs, &HardwareIDsSize,
&CompatibleIDs, &CompatibleIDsSize);
if (!Result)
goto done;
sizeNeeded = FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)
+ HardwareIDsSize + CompatibleIDsSize;
if (RequiredSize)
*RequiredSize = sizeNeeded;
if (!DriverInfoDetailData)
{
ret = TRUE;
goto done;
}
memcpy(
DriverInfoDetailData,
&driverInfoElement->Details,
driverInfoElement->Details.cbSize);
DriverInfoDetailData->CompatIDsOffset = 0;
DriverInfoDetailData->CompatIDsLength = 0;
sizeLeft = (DriverInfoDetailDataSize - FIELD_OFFSET(SP_DRVINFO_DETAIL_DATA_W, HardwareID)) / sizeof(WCHAR);
pBuffer = DriverInfoDetailData->HardwareID;
/* Add as many as possible HardwareIDs in the list */
DeviceID = HardwareIDs;
while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
{
TRACE("Adding %s to list\n", debugstr_w(DeviceID));
wcscpy(pBuffer, DeviceID);
DeviceID += size + 1;
pBuffer += size + 1;
sizeLeft -= size + 1;
DriverInfoDetailData->CompatIDsOffset += size + 1;
}
if (sizeLeft > 0)
{
*pBuffer = UNICODE_NULL;
sizeLeft--;
DriverInfoDetailData->CompatIDsOffset++;
}
/* Add as many as possible CompatibleIDs in the list */
DeviceID = CompatibleIDs;
while (DeviceID && *DeviceID && (size = wcslen(DeviceID)) + 1 < sizeLeft)
{
TRACE("Adding %s to list\n", debugstr_w(DeviceID));
wcscpy(pBuffer, DeviceID);
DeviceID += size + 1;
pBuffer += size + 1;
sizeLeft -= size + 1;
DriverInfoDetailData->CompatIDsLength += size + 1;
}
if (sizeLeft > 0)
{
*pBuffer = UNICODE_NULL;
sizeLeft--;
DriverInfoDetailData->CompatIDsLength++;
}
if (sizeNeeded > DriverInfoDetailDataSize)
SetLastError(ERROR_INSUFFICIENT_BUFFER);
else
ret = TRUE;
done:
MyFree(HardwareIDs);
MyFree(CompatibleIDs);
}
TRACE("Returning %d\n", 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_DEVICE_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.@)
*/
BOOL WINAPI
SetupDiSelectBestCompatDrv(
IN HDEVINFO DeviceInfoSet,
IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
{
SP_DRVINFO_DATA_W drvInfoData;
BOOL ret;
TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
/* Drivers are sorted by rank in the driver list, so
* the first driver in the list is the best one.
*/
drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
ret = SetupDiEnumDriverInfoW(
DeviceInfoSet,
DeviceInfoData,
SPDIT_COMPATDRIVER,
0, /* Member index */
&drvInfoData);
if (ret)
{
ret = SetupDiSetSelectedDriverW(
DeviceInfoSet,
DeviceInfoData,
&drvInfoData);
}
TRACE("Returning %d\n", ret);
return ret;
}
/***********************************************************************
* SetupDiInstallDriverFiles (SETUPAPI.@)
*/
BOOL WINAPI
SetupDiInstallDriverFiles(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData)
{
BOOL ret = FALSE;
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 if (DeviceInfoData && ((struct DeviceInfo *)DeviceInfoData->Reserved)->InstallParams.Reserved == 0)
SetLastError(ERROR_NO_DRIVER_SELECTED);
else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->InstallParams.Reserved == 0)
SetLastError(ERROR_NO_DRIVER_SELECTED);
else
{
SP_DEVINSTALL_PARAMS_W InstallParams;
struct DriverInfoElement *SelectedDriver;
WCHAR SectionName[MAX_PATH];
DWORD SectionNameLength = 0;
PVOID InstallMsgHandler;
PVOID InstallMsgHandlerContext;
PVOID Context = NULL;
InstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
ret = SetupDiGetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
if (!ret)
goto done;
SelectedDriver = (struct DriverInfoElement *)InstallParams.Reserved;
if (!SelectedDriver)
{
SetLastError(ERROR_NO_DRIVER_SELECTED);
goto done;
}
ret = SetupDiGetActualSectionToInstallW(
SelectedDriver->InfFileDetails->hInf,
SelectedDriver->Details.SectionName,
SectionName, MAX_PATH - strlenW(DotCoInstallers), &SectionNameLength, NULL);
if (!ret)
goto done;
if (InstallParams.InstallMsgHandler)
{
InstallMsgHandler = InstallParams.InstallMsgHandler;
InstallMsgHandlerContext = InstallParams.InstallMsgHandlerContext;
}
else
{
Context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
if (!Context)
goto cleanup;
InstallMsgHandler = SetupDefaultQueueCallbackW;
InstallMsgHandlerContext = Context;
}
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
InstallMsgHandler, InstallMsgHandlerContext,
DeviceInfoSet, DeviceInfoData);
if (!ret)
goto done;
/* Install files from .CoInstallers section */
lstrcatW(SectionName, DotCoInstallers);
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
SPINST_FILES, NULL, SelectedDriver->InfFileDetails->DirectoryName, SP_COPY_NEWER,
InstallMsgHandler, InstallMsgHandlerContext,
DeviceInfoSet, DeviceInfoData);
if (!ret)
goto done;
/* Set the DI_NOFILECOPY flag to prevent another
* installation during SetupDiInstallDevice */
InstallParams.Flags |= DI_NOFILECOPY;
ret = SetupDiSetDeviceInstallParamsW(DeviceInfoSet, DeviceInfoData, &InstallParams);
cleanup:
if (Context)
SetupTermDefaultQueueCallback(Context);
}
done:
TRACE("Returning %d\n", ret);
return ret;
}