/* FIXME: header mess */
DEFINE_GUID(GUID_NULL,
0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+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);
#define SETUP_DEV_INFO_SET_MAGIC 0xd00ff057
+struct CoInstallerElement
+{
+ LIST_ENTRY ListEntry;
+
+ COINSTALLER_PROC Function;
+ BOOL DoPostProcessing;
+ PVOID PrivateData;
+};
+
struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
{
LIST_ENTRY ListEntry;
{
LIST_ENTRY ListEntry;
+ DWORD DriverRank;
SP_DRVINFO_DATA_V2_W Info;
+ LPWSTR InfPath;
+ LPWSTR InfSection;
+ LPWSTR MatchingId;
};
struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
* SetupDiCallClassInstaller (SETUPAPI.@)
*/
BOOL WINAPI SetupDiCallClassInstaller(
- DI_FUNCTION InstallFunction,
- HDEVINFO DeviceInfoSet,
- PSP_DEVINFO_DATA DeviceInfoData)
+ IN DI_FUNCTION InstallFunction,
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL)
{
- FIXME("%ld %p %p\n", InstallFunction, DeviceInfoSet, DeviceInfoData);
- return FALSE;
+ BOOL ret = FALSE;
+
+ TRACE("%ld %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_DEV_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
+ {
+#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_ALLOW_INSTALL:
+ 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_REGISTER_COINSTALLERS:
+ CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+ DefaultHandler = SetupDiRegisterCoDeviceInstallers;
+ break;
+ case DIF_SELECTBESTCOMPATDRV:
+ CanHandle = CLASS_COINSTALLER | CLASS_INSTALLER;
+ DefaultHandler = SetupDiSelectBestCompatDrv;
+ break;
+ default:
+ FIXME("Install function %ld not implemented\n", InstallFunction);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+
+ if (CanHandle != 0)
+ {
+ LIST_ENTRY ClassCoInstallersListHead;
+ LIST_ENTRY DeviceCoInstallersListHead;
+ 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)
+ {
+ FIXME("Doesn't use Device co-installers at the moment\n");
+ }
+ if (CanHandle & CLASS_COINSTALLER)
+ {
+ rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\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, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
+ if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+ {
+ LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+ if (KeyBuffer != NULL)
+ {
+ rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+ if (rc == ERROR_SUCCESS)
+ {
+ LPCWSTR ptr;
+ for (ptr = KeyBuffer; *ptr; ptr += strlenW(ptr) + 1)
+ {
+ /* Add coinstaller to ClassCoInstallersListHead list */
+ FIXME("Class coinstaller is '%S'. UNIMPLEMENTED!\n", ptr);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, KeyBuffer);
+ }
+ }
+ RpcStringFreeW(&lpGuidString);
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ if (CanHandle & CLASS_INSTALLER)
+ {
+ hKey = SetupDiOpenClassRegKey(&DeviceInfoData->ClassGuid, KEY_QUERY_VALUE);
+ if (hKey != INVALID_HANDLE_VALUE)
+ {
+ rc = RegQueryValueExW(hKey, L"Installer32", NULL, &dwRegType, NULL, &dwLength);
+ if (rc == ERROR_SUCCESS && dwRegType == REG_SZ)
+ {
+ LPWSTR KeyBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
+ if (KeyBuffer != NULL)
+ {
+ rc = RegQueryValueExW(hKey, L"Installer32", NULL, NULL, (LPBYTE)KeyBuffer, &dwLength);
+ if (rc == ERROR_SUCCESS)
+ {
+ /* Set ClassInstaller function pointer */
+ FIXME("Installer is '%S'\n", KeyBuffer);
+ }
+ 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 = (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 = (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);
+ else
+ rc = ERROR_DI_DO_DEFAULT;
+
+ /* Call default handler */
+ if (rc == ERROR_DI_DO_DEFAULT)
+ {
+ if (DefaultHandler /*FIXME && DI_NODI_DEFAULTACTION not set */)
+ {
+ 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 = (struct CoInstallerElement *)ListEntry;
+ if (coinstaller->DoPostProcessing)
+ {
+ Context.InstallResult = rc;
+ Context.PrivateData = coinstaller->PrivateData;
+ rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+ }
+ ListEntry = ListEntry->Flink;
+ }
+
+ /* Call Device co-installers that required postprocessing */
+ ListEntry = DeviceCoInstallersListHead.Flink;
+ while (ListEntry != &DeviceCoInstallersListHead)
+ {
+ struct CoInstallerElement *coinstaller = (struct CoInstallerElement *)ListEntry;
+ if (coinstaller->DoPostProcessing)
+ {
+ Context.InstallResult = rc;
+ Context.PrivateData = coinstaller->PrivateData;
+ rc = (*coinstaller->Function)(InstallFunction, DeviceInfoSet, DeviceInfoData, &Context);
+ }
+ ListEntry = ListEntry->Flink;
+ }
+
+ /* Free allocated memory */
+ while (!IsListEmpty(&ClassCoInstallersListHead))
+ {
+ ListEntry = RemoveHeadList(&ClassCoInstallersListHead);
+ HeapFree(GetProcessHeap(), 0, ListEntry);
+ }
+ while (!IsListEmpty(&DeviceCoInstallersListHead))
+ {
+ ListEntry = RemoveHeadList(&DeviceCoInstallersListHead);
+ HeapFree(GetProcessHeap(), 0, 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)
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ OUT 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;
+}
+
+/***********************************************************************
+ * SetupDiGetDeviceInstallParamsW (SETUPAPI.@)
+ */
+BOOL WINAPI SetupDiGetDeviceInstallParamsW(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData,
+ OUT PSP_DEVINSTALL_PARAMS_W DeviceInstallParams)
{
FIXME("%p %p %p\n", DeviceInfoSet, DeviceInfoData, DeviceInstallParams);
return FALSE;
IN LPCWSTR InfFile,
IN LPCWSTR ProviderName,
IN LPCWSTR ManufacturerName,
+ IN LPCWSTR MatchingId,
FILETIME DriverDate,
DWORDLONG DriverVersion,
IN DWORD Rank)
{
- struct DriverInfoElement *driverInfo;
+ struct DriverInfoElement *driverInfo = NULL;
DWORD RequiredSize = 128; /* Initial buffer size */
BOOL Result = FALSE;
+ PLIST_ENTRY PreviousEntry;
LPWSTR DeviceDescription = NULL;
LPWSTR InfInstallSection = NULL;
+ BOOL ret = FALSE;
driverInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(struct DriverInfoElement));
if (!driverInfo)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
+ goto cleanup;
+ }
+ memset(driverInfo, 0, sizeof(struct DriverInfoElement));
+
+ /* Fill InfSection field */
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
+ driverInfo->InfSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ if (!driverInfo->InfSection)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+ Result = SetupGetStringFieldW(
+ &ContextDevice,
+ 1,
+ driverInfo->InfSection, RequiredSize,
+ &RequiredSize);
+ }
+ if (!Result)
+ goto cleanup;
+
+ /* Copy InfFile information */
+ driverInfo->InfPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(InfFile) + 1) * sizeof(WCHAR));
+ if (!driverInfo->InfPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+ RtlCopyMemory(driverInfo->InfPath, InfFile, (wcslen(InfFile) + 1) * sizeof(WCHAR));
+
+ /* Copy MatchingId information */
+ driverInfo->MatchingId = HeapAlloc(GetProcessHeap(), 0, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
+ if (!driverInfo->MatchingId)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
}
+ RtlCopyMemory(driverInfo->MatchingId, MatchingId, (wcslen(MatchingId) + 1) * sizeof(WCHAR));
+ /* Get device description */
+ Result = FALSE;
+ RequiredSize = 128; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, DeviceDescription);
DeviceDescription = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!DeviceDescription)
- return FALSE;
+ goto cleanup;
Result = SetupGetStringFieldW(
&ContextDevice,
0, /* Field index */
&RequiredSize);
}
if (!Result)
- {
- HeapFree(GetProcessHeap(), 0, driverInfo);
- HeapFree(GetProcessHeap(), 0, DeviceDescription);
- return FALSE;
- }
+ goto cleanup;
+ /* Get inf install section */
Result = FALSE;
RequiredSize = 128; /* Initial buffer size */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
HeapFree(GetProcessHeap(), 0, InfInstallSection);
InfInstallSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!InfInstallSection)
- {
- HeapFree(GetProcessHeap(), 0, driverInfo);
- HeapFree(GetProcessHeap(), 0, DeviceDescription);
- return FALSE;
- }
+ goto cleanup;
Result = SetupGetStringFieldW(
&ContextDevice,
1, /* Field index */
&RequiredSize);
}
if (!Result)
- {
- HeapFree(GetProcessHeap(), 0, driverInfo);
- HeapFree(GetProcessHeap(), 0, DeviceDescription);
- HeapFree(GetProcessHeap(), 0, InfInstallSection);
- return FALSE;
- }
+ goto cleanup;
TRACE("Adding driver '%S' [%S/%S] (Rank 0x%lx)\n",
DeviceDescription, InfFile, InfInstallSection, Rank);
+ driverInfo->DriverRank = Rank;
driverInfo->Info.DriverType = DriverType;
driverInfo->Info.Reserved = (ULONG_PTR)driverInfo;
wcsncpy(driverInfo->Info.Description, DeviceDescription, LINE_LEN - 1);
driverInfo->Info.ProviderName[0] = '\0';
driverInfo->Info.DriverDate = DriverDate;
driverInfo->Info.DriverVersion = DriverVersion;
- InsertTailList(DriverListHead, &driverInfo->ListEntry);
+ /* Insert current driver in driver list, according to its rank */
+ PreviousEntry = DriverListHead->Flink;
+ while (PreviousEntry != DriverListHead)
+ {
+ if (((struct DriverInfoElement *)PreviousEntry)->DriverRank >= Rank)
+ {
+ /* Insert before the current item */
+ InsertHeadList(PreviousEntry, &driverInfo->ListEntry);
+ break;
+ }
+ }
+ 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->InfPath);
+ HeapFree(GetProcessHeap(), 0, driverInfo->InfSection);
+ HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
+ }
+ HeapFree(GetProcessHeap(), 0, driverInfo);
+ }
HeapFree(GetProcessHeap(), 0, DeviceDescription);
HeapFree(GetProcessHeap(), 0, InfInstallSection);
- return TRUE;
+
+ return ret;
}
static BOOL
{
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,
guidW, sizeof(guidW),
NULL /* Required size */))
{
- return FALSE;
+ goto cleanup;
}
-
- /* Get Provider name, driver date, and driver version */
-
guidW[37] = '\0'; /* Replace the } by a NULL character */
if (UuidFromStringW(&guidW[1], ClassGuid) != RPC_S_OK)
{
- return FALSE;
+ SetLastError(ERROR_GEN_FAILURE);
+ goto cleanup;
}
+
+ /* Get provider name */
Result = SetupGetLineTextW(
NULL, /* Context */
hInf, L"Version", L"Provider",
NULL, 0,
&RequiredSize);
- if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ if (Result)
{
+ /* We know know the needed buffer size */
ProviderName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!ProviderName)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
+ goto cleanup;
}
Result = SetupGetLineTextW(
NULL, /* Context */
ProviderName, RequiredSize,
&RequiredSize);
}
- //FIXME: DriverDate = Version.DriverVer => invalid date = 00/00/00
- //FIXME: DriverVersion = Version.DriverVer => invalid = 0
-
+ if (!Result)
+ goto cleanup;
*pProviderName = ProviderName;
- return TRUE;
+
+ /* Read the "DriverVer" value */
+ Result = SetupGetLineTextW(
+ NULL, /* Context */
+ hInf, L"Version", L"DriverVer",
+ 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, L"Version", L"DriverVer",
+ DriverVer, RequiredSize,
+ &RequiredSize);
+ }
+ if (!Result)
+ goto cleanup;
+
+ /* Get driver date and driver version, by analyzing the "DriverVer" value */
+ pComma = wcschr(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 (wcslen(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;
+ /* FIXME: use pVersion to fill DriverVersion variable */
+
+ ret = TRUE;
+
+cleanup:
+ if (!ret)
+ HeapFree(GetProcessHeap(), 0, ProviderName);
+ HeapFree(GetProcessHeap(), 0, DriverVer);
+
+ TRACE("Returning %d\n", ret);
+ return ret;
}
/***********************************************************************
LPWSTR HardwareIDs = NULL;
LPWSTR CompatibleIDs = NULL;
FILETIME DriverDate;
- DWORDLONG DriverVersion;
+ DWORDLONG DriverVersion = 0;
DWORD RequiredSize;
BOOL ret = FALSE;
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, HardwareIDs);
- HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ HardwareIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
if (!HardwareIDs)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
while (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
HeapFree(GetProcessHeap(), 0, CompatibleIDs);
- CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ CompatibleIDs = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
if (!CompatibleIDs)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
/* Check if the ClassGuid in this .inf file is corresponding with our needs */
if (!IsEqualIID(&list->ClassGuid, &GUID_NULL) && !IsEqualIID(&list->ClassGuid, &ClassGuid))
{
- SetupCloseInfFile(hInf);
- hInf = INVALID_HANDLE_VALUE;
- continue;
+ goto next;
}
}
0, /* Field index */
NULL, 0,
&RequiredSize);
- if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ if (Result)
{
+ /* We got the needed size for the buffer */
ManufacturerName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!ManufacturerName)
{
1, /* Field index */
NULL, 0,
&RequiredSize);
- if (!Result && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ if (Result)
{
+ /* We got the needed size for the buffer */
ManufacturerSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
if (!ManufacturerSection)
{
filename,
ProviderName,
ManufacturerName,
+ NULL,
DriverDate, DriverVersion,
0))
{
filename,
ProviderName,
ManufacturerName,
+ currentId,
DriverDate, DriverVersion,
DriverRank + (i == 2 ? 0 : 0x1000 + i - 3));
DriverAlreadyAdded = TRUE;
filename,
ProviderName,
ManufacturerName,
+ currentId,
DriverDate, DriverVersion,
DriverRank + (i == 2 ? 0x2000 : 0x3000 + i - 3));
DriverAlreadyAdded = TRUE;
ManufacturerName = ManufacturerSection = NULL;
Result = SetupFindNextLine(&ContextManufacturer, &ContextManufacturer);
}
+
+ ret = TRUE;
+next:
HeapFree(GetProcessHeap(), 0, ProviderName);
ProviderName = NULL;
- ret = TRUE;
SetupCloseInfFile(hInf);
hInf = INVALID_HANDLE_VALUE;
{
if (DeviceInfoData)
{
- struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData;
+ struct DeviceInfoElement *deviceInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
deviceInfo->Flags |= DI_DIDCOMPAT;
}
else
if (deviceInfo)
{
/* good one found */
- if (DeviceInfoData)
- {
- memcpy(&DeviceInfoData->ClassGuid, &deviceInfo->ClassGuid, sizeof(GUID));
- DeviceInfoData->DevInst = 0; /* FIXME */
- DeviceInfoData->Reserved = (ULONG_PTR)deviceInfo;
- }
ret = TRUE;
}
else
*pDriverInfo = (struct DriverInfoElement *)ItemList;
DriverInfoData->Reserved = (ULONG_PTR)ItemList;
ret = TRUE;
+ TRACE("Choosing driver whose rank is 0x%lx\n",
+ ((struct DriverInfoElement *)ItemList)->DriverRank);
+ }
+ }
+ }
+
+ TRACE("Returning %d\n", ret);
+ return ret;
+}
+
+/***********************************************************************
+ * SetupDiSelectBestCompatDrv (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiSelectBestCompatDrv(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+ 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 OPTIONAL)
+{
+ 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_DEV_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 DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else
+ {
+ struct DriverInfoElement *DriverInfo;
+ HWND hWnd;
+ HINF hInf;
+
+ if (DeviceInfoData)
+ {
+ DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
+ hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
+ }
+ else
+ {
+ DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
+ hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
+ }
+
+ hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
+ if (hInf != INVALID_HANDLE_VALUE)
+ {
+ WCHAR SectionName[MAX_PATH];
+ DWORD SectionNameLength = 0;
+
+ ret = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
+ SectionName, MAX_PATH, &SectionNameLength, NULL);
+ if (ret)
+ {
+ PVOID callback_context = SetupInitDefaultQueueCallback(hWnd);
+ ret = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
+ SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
+ SetupDefaultQueueCallbackW, callback_context,
+ NULL, NULL);
+ SetupTermDefaultQueueCallback(callback_context);
}
+ SetupCloseInfFile(hInf);
}
}
TRACE("Returning %d\n", ret);
return ret;
}
+
+/***********************************************************************
+ * SetupDiRegisterCoDeviceInstallers (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiRegisterCoDeviceInstallers(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+ TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+ FIXME("SetupDiRegisterCoDeviceInstallers not implemented. Doing nothing\n");
+ //SetLastError(ERROR_GEN_FAILURE);
+ //return FALSE;
+ return TRUE;
+}
+
+/***********************************************************************
+ * SetupDiInstallDeviceInterfaces (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallDeviceInterfaces(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+ TRACE("%p %p\n", DeviceInfoSet, DeviceInfoData);
+
+ FIXME("SetupDiInstallDeviceInterfaces not implemented. Doing nothing\n");
+ //SetLastError(ERROR_GEN_FAILURE);
+ //return FALSE;
+ return TRUE;
+}
+
+/***********************************************************************
+ * SetupDiInstallDevice (SETUPAPI.@)
+ */
+BOOL WINAPI
+SetupDiInstallDevice(
+ IN HDEVINFO DeviceInfoSet,
+ IN PSP_DEVINFO_DATA DeviceInfoData)
+{
+ struct DriverInfoElement *DriverInfo;
+ struct DeviceInfoSet *DevInfoSet = (struct DeviceInfoSet *)DeviceInfoSet;
+ struct DeviceInfoElement *DevInfo = (struct DeviceInfoElement *)DeviceInfoData->Reserved;
+ SYSTEMTIME DriverDate;
+ WCHAR SectionName[MAX_PATH];
+ WCHAR Buffer[32];
+ DWORD SectionNameLength = 0;
+ BOOL Result = FALSE;
+ INFCONTEXT ContextService;
+ INT Flags;
+ DWORD RequiredSize;
+ HINF hInf = INVALID_HANDLE_VALUE;
+ LPCWSTR AssociatedService = NULL;
+ LPWSTR pSectionName = NULL;
+ LPWSTR ClassName = NULL;
+ GUID ClassGuid;
+ LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
+ BOOL RebootRequired = FALSE;
+ HKEY hEnumKey, hKey = INVALID_HANDLE_VALUE;
+ HKEY hClassKey = INVALID_HANDLE_VALUE;
+ LPWSTR DriverKey = NULL; /* {GUID}\Index */
+ LPWSTR pDeviceInstance; /* Points into DriverKey, on the Index field */
+ DWORD Index; /* Index used in the DriverKey name */
+ LONG rc;
+ HWND hWnd;
+ PVOID callback_context;
+ 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_DEV_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 DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver == NULL)
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else if (!DeviceInfoData && ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver == NULL)
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else
+ Result = TRUE;
+
+ if (!Result)
+ {
+ /* One parameter is bad */
+ goto cleanup;
+ }
+
+ /* FIXME: If DI_FLAGSEX_SETFAILEDINSTALL is set, set FAILEDINSTALL flag in ConfigFlags registry and exit */
+
+ if (DeviceInfoData)
+ {
+ DriverInfo = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->SelectedDriver;
+ hWnd = ((struct DeviceInfoElement *)DeviceInfoData->Reserved)->hwndParent;
+ }
+ else
+ {
+ DriverInfo = ((struct DeviceInfoSet *)DeviceInfoSet)->SelectedDriver;
+ hWnd = ((struct DeviceInfoSet *)DeviceInfoSet)->hwndParent;
+ }
+ FileTimeToSystemTime(&DriverInfo->Info.DriverDate, &DriverDate);
+
+ hInf = SetupOpenInfFileW(DriverInfo->InfPath, NULL, INF_STYLE_WIN4, NULL);
+ if (hInf == INVALID_HANDLE_VALUE)
+ goto cleanup;
+
+ Result = SetupDiGetActualSectionToInstallW(hInf, DriverInfo->InfSection,
+ SectionName, MAX_PATH, &SectionNameLength, NULL);
+ if (!Result || SectionNameLength > MAX_PATH - 9)
+ goto cleanup;
+ pSectionName = &SectionName[wcslen(SectionName)];
+
+ /* Get information from [Version] section */
+ ClassName = NULL;
+ RequiredSize = 0;
+ if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto cleanup;
+ ClassName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ if (!ClassName)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+ if (!SetupDiGetINFClassW(DriverInfo->InfPath, &ClassGuid, ClassName, RequiredSize, &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';
+
+ /* Create driver key information */
+ /* The driver key is in HKLM\System\CurrentControlSet\Control\Class\{GUID}\{#ID} */
+ DriverKey = HeapAlloc(GetProcessHeap(), 0, (wcslen(lpFullGuidString) + 6) * sizeof(WCHAR));
+ if (!DriverKey)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+ wcscpy(DriverKey, lpFullGuidString);
+ wcscat(DriverKey, L"\\");
+ pDeviceInstance = &DriverKey[wcslen(DriverKey)];
+ rc = RegOpenKeyExW(DevInfoSet->HKLM,
+ ControlClass,
+ 0,
+ KEY_CREATE_SUB_KEY,
+ &hClassKey);
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+ /* Try all values for Index between 0 and 9999 */
+ Index = 0;
+ while (Index <= 9999)
+ {
+ DWORD Disposition;
+ wsprintf(pDeviceInstance, L"%04lu", Index);
+ rc = RegCreateKeyEx(hClassKey,
+ DriverKey,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE,
+ NULL,
+ &hKey,
+ &Disposition);
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+ if (Disposition == REG_CREATED_NEW_KEY)
+ break;
+ RegCloseKey(hKey);
+ hKey = INVALID_HANDLE_VALUE;
+ Index++;
+ }
+ if (Index > 9999)
+ {
+ /* Unable to create more than 9999 devices within the same class */
+ SetLastError(ERROR_GEN_FAILURE);
+ goto cleanup;
+ }
+
+ /* Write information to driver key */
+ *pSectionName = UNICODE_NULL;
+ TRACE("Write information to driver key\n");
+ TRACE("DriverDate : '%u-%u-%u'\n", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
+ TRACE("DriverDesc : '%S'\n", DriverInfo->Info.Description);
+ TRACE("DriverVersion : '%u.%u.%u.%u'\n", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
+ TRACE("InfPath : '%S'\n", DriverInfo->InfPath);
+ TRACE("InfSection : '%S'\n", DriverInfo->InfSection);
+ TRACE("InfSectionExt : '%S'\n", &SectionName[wcslen(DriverInfo->InfSection)]); /* FIXME */
+ TRACE("MatchingDeviceId: '%S'\n", DriverInfo->MatchingId);
+ TRACE("ProviderName : '%S'\n", DriverInfo->Info.ProviderName);
+ swprintf(Buffer, L"%u-%u-%u", DriverDate.wMonth, DriverDate.wDay, DriverDate.wYear);
+ rc = RegSetValueEx(hKey, L"DriverDate", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"DriverDateData", 0, REG_BINARY, (const BYTE *)&DriverInfo->Info.DriverDate, sizeof(FILETIME));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"DriverDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ {
+ swprintf(Buffer, L"%u.%u.%u.%u", DriverInfo->Info.DriverVersion & 0xff, (DriverInfo->Info.DriverVersion >> 8) & 0xff, (DriverInfo->Info.DriverVersion >> 16) & 0xff, (DriverInfo->Info.DriverVersion >> 24) & 0xff);
+ rc = RegSetValueEx(hKey, L"DriverVersion", 0, REG_SZ, (const BYTE *)Buffer, (wcslen(Buffer) + 1) * sizeof(WCHAR));
+ }
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"InfPath", 0, REG_SZ, (const BYTE *)DriverInfo->InfPath, (wcslen(DriverInfo->InfPath) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"InfSection", 0, REG_SZ, (const BYTE *)DriverInfo->InfSection, (wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"InfSectionExt", 0, REG_SZ, (const BYTE *)&SectionName[wcslen(DriverInfo->InfSection)], (wcslen(SectionName) - wcslen(DriverInfo->InfSection) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"MatchingDeviceId", 0, REG_SZ, (const BYTE *)DriverInfo->MatchingId, (wcslen(DriverInfo->MatchingId) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"ProviderName", 0, REG_SZ, (const BYTE *)DriverInfo->Info.ProviderName, (wcslen(DriverInfo->Info.ProviderName) + 1) * sizeof(WCHAR));
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+ RegCloseKey(hKey);
+ hKey = INVALID_HANDLE_VALUE;
+
+ /* Install .Services section */
+ wcscpy(pSectionName, L".Services");
+ Result = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService);
+ while (Result)
+ {
+ LPWSTR ServiceName = NULL;
+ LPWSTR ServiceSection = NULL;
+
+ Result = SetupGetStringFieldW(
+ &ContextService,
+ 1, /* Field index */
+ NULL, 0,
+ &RequiredSize);
+ if (!Result)
+ goto nextfile;
+ if (RequiredSize > 0)
+ {
+ /* We got the needed size for the buffer */
+ ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ if (!ServiceName)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto nextfile;
+ }
+ Result = SetupGetStringFieldW(
+ &ContextService,
+ 1, /* Field index */
+ ServiceName, RequiredSize,
+ &RequiredSize);
+ if (!Result)
+ goto nextfile;
+ }
+ Result = SetupGetIntField(
+ &ContextService,
+ 2, /* Field index */
+ &Flags);
+ if (!Result)
+ {
+ /* The field may be empty. Ignore the error */
+ Flags = 0;
+ }
+ Result = SetupGetStringFieldW(
+ &ContextService,
+ 3, /* Field index */
+ NULL, 0,
+ &RequiredSize);
+ if (!Result)
+ goto nextfile;
+ if (RequiredSize > 0)
+ {
+ /* We got the needed size for the buffer */
+ ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR));
+ if (!ServiceSection)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto nextfile;
+ }
+ Result = SetupGetStringFieldW(
+ &ContextService,
+ 3, /* Field index */
+ ServiceSection, RequiredSize,
+ &RequiredSize);
+ if (!Result)
+ goto nextfile;
+ }
+ SetLastError(ERROR_SUCCESS);
+ Result = SetupInstallServicesFromInfSectionExW(hInf, ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
+ if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
+ {
+ AssociatedService = ServiceName;
+ ServiceName = NULL;
+ if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
+ RebootRequired = TRUE;
+ }
+nextfile:
+ HeapFree(GetProcessHeap(), 0, ServiceName);
+ HeapFree(GetProcessHeap(), 0, ServiceSection);
+ if (!Result)
+ goto cleanup;
+ Result = SetupFindNextLine(&ContextService, &ContextService);
+ }
+
+ /* Copy .inf file to Inf\ directory */
+ FIXME("FIXME: Copy .inf file to Inf\\ directory\n"); /* SetupCopyOEMInf */
+
+ /* Open enum key */
+ rc = RegOpenKeyExW(DevInfoSet->HKLM,
+ EnumKeyName,
+ 0,
+ KEY_ENUMERATE_SUB_KEYS,
+ &hEnumKey);
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+ rc = RegOpenKeyExW(
+ hEnumKey,
+ DevInfo->DeviceName,
+ 0, /* Options */
+ KEY_SET_VALUE,
+ &hKey);
+ RegCloseKey(hEnumKey);
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+
+ /* Install .HW section */
+ wcscpy(pSectionName, L".HW");
+ callback_context = SetupInitDefaultQueueCallback(hWnd);
+ Result = SetupInstallFromInfSectionW(hWnd, hInf, SectionName,
+ SPINST_REGISTRY, hKey, NULL, 0,
+ SetupDefaultQueueCallbackW, callback_context,
+ NULL, NULL);
+ SetupTermDefaultQueueCallback(callback_context);
+ if (!Result)
+ goto cleanup;
+
+ /* Write information to enum key */
+ TRACE("Write information to enum key\n");
+ TRACE("Service : '%S'\n", AssociatedService);
+ TRACE("Class : '%S'\n", ClassName);
+ TRACE("ClassGUID : '%S'\n", lpFullGuidString);
+ TRACE("DeviceDesc : '%S'\n", DriverInfo->Info.Description);
+ TRACE("Driver : '%S'\n", DriverKey);
+ TRACE("Mfg : '%S'\n", DriverInfo->Info.MfgName);
+ rc = RegSetValueEx(hKey, L"Service", 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"Class", 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"ClassGUID", 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"DeviceDesc", 0, REG_SZ, (const BYTE *)DriverInfo->Info.Description, (wcslen(DriverInfo->Info.Description) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"Driver", 0, REG_SZ, (const BYTE *)DriverKey, (wcslen(DriverKey) + 1) * sizeof(WCHAR));
+ if (rc == ERROR_SUCCESS)
+ rc = RegSetValueEx(hKey, L"Mfg", 0, REG_SZ, (const BYTE *)DriverInfo->Info.MfgName, (wcslen(DriverInfo->Info.MfgName) + 1) * sizeof(WCHAR));
+ if (rc != ERROR_SUCCESS)
+ {
+ SetLastError(rc);
+ goto cleanup;
+ }
+
+ /* Load the driver/call AddDevice */
+ FIXME("FIXME: Load the driver/call AddDevice\n");
+
+ /* Send IRP_MN_START_DEVICE if needed */
+ //if (!RebootRequired && !(Flags & (DI_NEEDRESTART | DI_NEEDREBOOT | DI_DONOTCALLCONFIGMG)))
+ FIXME("FIXME: Send IRP_MN_START_DEVICE\n");
+
+ ret = TRUE;
+
+cleanup:
+ /* End of installation */
+ if (hClassKey != INVALID_HANDLE_VALUE)
+ RegCloseKey(hClassKey);
+ if (hKey != INVALID_HANDLE_VALUE)
+ RegCloseKey(hKey);
+ if (lpGuidString)
+ RpcStringFreeW(&lpGuidString);
+ HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
+ HeapFree(GetProcessHeap(), 0, DriverKey);
+ HeapFree(GetProcessHeap(), 0, ClassName);
+ HeapFree(GetProcessHeap(), 0, lpFullGuidString);
+ if (hInf != INVALID_HANDLE_VALUE)
+ SetupCloseInfFile(hInf);
+
+ TRACE("Returning %d\n", ret);
+ return ret;
+}