Don't leak memory when destroying device info set and driver lists

Try to keep .inf files handles instead of opening/parsing them at each device installation step

svn path=/trunk/; revision=18731
This commit is contained in:
Hervé Poussineau 2005-10-24 09:16:34 +00:00
parent c29c9e80df
commit 1d328d2072

View file

@ -116,6 +116,14 @@ struct DeviceInterface /* Element of DeviceInfoElement.InterfaceListHead */
WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */ WCHAR SymbolicLink[0]; /* \\?\ACPI#PNP0501#4&2658d0a0&0#{GUID} */
}; };
/* We don't want to open the .inf file to read only one information in it, so keep a handle to it once it
* has been already loaded once. Keep also a reference counter */
struct InfFileDetails
{
HINF hInf;
ULONG References;
};
struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */ struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceInfoElement.DriverListHead */
{ {
LIST_ENTRY ListEntry; LIST_ENTRY ListEntry;
@ -125,6 +133,7 @@ struct DriverInfoElement /* Element of DeviceInfoSet.DriverListHead and DeviceIn
SP_DRVINFO_DETAIL_DATA_W Details; SP_DRVINFO_DETAIL_DATA_W Details;
GUID ClassGuid; GUID ClassGuid;
LPWSTR MatchingId; LPWSTR MatchingId;
struct InfFileDetails *InfFileDetails;
}; };
struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */ struct DeviceInfoElement /* Element of DeviceInfoSet.ListHead */
@ -1934,6 +1943,57 @@ BOOL WINAPI SetupDiEnumDeviceInterfaces(
return ret; return ret;
} }
static BOOL DestroyDriverInfoElement(struct DriverInfoElement* driverInfo)
{
if (InterlockedDecrement(&driverInfo->InfFileDetails->References) == 0)
{
SetupCloseInfFile(driverInfo->InfFileDetails->hInf);
HeapFree(GetProcessHeap(), 0, driverInfo->InfFileDetails);
}
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId);
HeapFree(GetProcessHeap(), 0, driverInfo);
return TRUE;
}
static BOOL DestroyDeviceInfoElement(struct DeviceInfoElement* deviceInfo)
{
PLIST_ENTRY ListEntry;
struct DriverInfoElement *driverInfo;
while (!IsListEmpty(&deviceInfo->DriverListHead))
{
ListEntry = RemoveHeadList(&deviceInfo->DriverListHead);
driverInfo = (struct DriverInfoElement *)ListEntry;
if (!DestroyDriverInfoElement(driverInfo))
return FALSE;
}
while (!IsListEmpty(&deviceInfo->InterfaceListHead))
{
ListEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
HeapFree(GetProcessHeap(), 0, ListEntry);
}
HeapFree(GetProcessHeap(), 0, deviceInfo);
return TRUE;
}
static BOOL DestroyDeviceInfoSet(struct DeviceInfoSet* list)
{
PLIST_ENTRY ListEntry;
struct DeviceInfoElement *deviceInfo;
while (!IsListEmpty(&list->ListHead))
{
ListEntry = RemoveHeadList(&list->ListHead);
deviceInfo = (struct DeviceInfoElement *)ListEntry;
if (!DestroyDeviceInfoElement(deviceInfo))
return FALSE;
}
if (list->HKLM != HKEY_LOCAL_MACHINE)
RegCloseKey(list->HKLM);
HeapFree(GetProcessHeap(), 0, list);
return TRUE;
}
/*********************************************************************** /***********************************************************************
* SetupDiDestroyDeviceInfoList (SETUPAPI.@) * SetupDiDestroyDeviceInfoList (SETUPAPI.@)
*/ */
@ -1947,25 +2007,7 @@ BOOL WINAPI SetupDiDestroyDeviceInfoList(HDEVINFO devinfo)
struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo; struct DeviceInfoSet *list = (struct DeviceInfoSet *)devinfo;
if (list->magic == SETUP_DEV_INFO_SET_MAGIC) if (list->magic == SETUP_DEV_INFO_SET_MAGIC)
{ ret = DestroyDeviceInfoSet(list);
PLIST_ENTRY ListEntry, InterfaceEntry;
struct DeviceInfoElement *deviceInfo;
while (!IsListEmpty(&list->ListHead))
{
ListEntry = RemoveHeadList(&list->ListHead);
deviceInfo = (struct DeviceInfoElement *)ListEntry;
while (!IsListEmpty(&deviceInfo->InterfaceListHead))
{
InterfaceEntry = RemoveHeadList(&deviceInfo->InterfaceListHead);
HeapFree(GetProcessHeap(), 0, InterfaceEntry);
}
HeapFree(GetProcessHeap(), 0, ListEntry);
}
if (list->HKLM != HKEY_LOCAL_MACHINE)
RegCloseKey(list->HKLM);
HeapFree(GetProcessHeap(), 0, list);
ret = TRUE;
}
else else
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
} }
@ -3824,6 +3866,7 @@ AddDriverToList(
IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */ IN DWORD DriverType, /* SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER */
IN LPGUID ClassGuid, IN LPGUID ClassGuid,
IN INFCONTEXT ContextDevice, IN INFCONTEXT ContextDevice,
IN struct InfFileDetails *InfFileDetails,
IN LPCWSTR InfFile, IN LPCWSTR InfFile,
IN LPCWSTR ProviderName, IN LPCWSTR ProviderName,
IN LPCWSTR ManufacturerName, IN LPCWSTR ManufacturerName,
@ -3929,6 +3972,8 @@ AddDriverToList(
driverInfo->Info.ProviderName[0] = '\0'; driverInfo->Info.ProviderName[0] = '\0';
driverInfo->Info.DriverDate = DriverDate; driverInfo->Info.DriverDate = DriverDate;
driverInfo->Info.DriverVersion = DriverVersion; driverInfo->Info.DriverVersion = DriverVersion;
InterlockedIncrement(&InfFileDetails->References);
driverInfo->InfFileDetails = InfFileDetails;
/* Insert current driver in driver list, according to its rank */ /* Insert current driver in driver list, according to its rank */
PreviousEntry = DriverListHead->Flink; PreviousEntry = DriverListHead->Flink;
@ -4094,7 +4139,7 @@ SetupDiBuildDriverInfoList(
struct DeviceInfoSet *list; struct DeviceInfoSet *list;
SP_DEVINSTALL_PARAMS_W InstallParams; SP_DEVINSTALL_PARAMS_W InstallParams;
PVOID Buffer = NULL; PVOID Buffer = NULL;
HINF hInf = INVALID_HANDLE_VALUE; struct InfFileDetails *currentInfFileDetails = NULL;
LPWSTR ProviderName = NULL; LPWSTR ProviderName = NULL;
LPWSTR ManufacturerName = NULL; LPWSTR ManufacturerName = NULL;
WCHAR ManufacturerSection[LINE_LEN + 1]; WCHAR ManufacturerSection[LINE_LEN + 1];
@ -4220,19 +4265,29 @@ SetupDiBuildDriverInfoList(
GUID ClassGuid; GUID ClassGuid;
TRACE("Opening file %S\n", filename); TRACE("Opening file %S\n", filename);
hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL); currentInfFileDetails = HeapAlloc(GetProcessHeap(), 0, sizeof(struct InfFileDetails));
if (hInf == INVALID_HANDLE_VALUE) if (!currentInfFileDetails)
continue; continue;
memset(currentInfFileDetails, 0, sizeof(struct InfFileDetails));
currentInfFileDetails->hInf = SetupOpenInfFileW(filename, NULL, INF_STYLE_WIN4, NULL);
if (currentInfFileDetails->hInf == INVALID_HANDLE_VALUE)
{
HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
currentInfFileDetails = NULL;
continue;
}
if (!GetVersionInformationFromInfFile( if (!GetVersionInformationFromInfFile(
hInf, currentInfFileDetails->hInf,
&ClassGuid, &ClassGuid,
&ProviderName, &ProviderName,
&DriverDate, &DriverDate,
&DriverVersion)) &DriverVersion))
{ {
SetupCloseInfFile(hInf); SetupCloseInfFile(currentInfFileDetails->hInf);
hInf = INVALID_HANDLE_VALUE; HeapFree(GetProcessHeap(), 0, currentInfFileDetails->hInf);
currentInfFileDetails = NULL;
continue; continue;
} }
@ -4246,7 +4301,7 @@ SetupDiBuildDriverInfoList(
} }
/* Get the manufacturers list */ /* Get the manufacturers list */
Result = SetupFindFirstLineW(hInf, L"Manufacturer", NULL, &ContextManufacturer); Result = SetupFindFirstLineW(currentInfFileDetails->hInf, L"Manufacturer", NULL, &ContextManufacturer);
while (Result) while (Result)
{ {
Result = SetupGetStringFieldW( Result = SetupGetStringFieldW(
@ -4280,11 +4335,11 @@ SetupDiBuildDriverInfoList(
ManufacturerSection[RequiredSize] = 0; /* Final NULL char */ ManufacturerSection[RequiredSize] = 0; /* Final NULL char */
/* Add (possible) extension to manufacturer section name */ /* Add (possible) extension to manufacturer section name */
Result = SetupDiGetActualSectionToInstallW( Result = SetupDiGetActualSectionToInstallW(
hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL); currentInfFileDetails->hInf, ManufacturerSection, ManufacturerSection, LINE_LEN, NULL, NULL);
if (Result) if (Result)
{ {
TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection); TRACE("Enumerating devices in manufacturer %S\n", ManufacturerSection);
Result = SetupFindFirstLineW(hInf, ManufacturerSection, NULL, &ContextDevice); Result = SetupFindFirstLineW(currentInfFileDetails->hInf, ManufacturerSection, NULL, &ContextDevice);
} }
} }
while (Result) while (Result)
@ -4297,6 +4352,7 @@ SetupDiBuildDriverInfoList(
DriverType, DriverType,
&ClassGuid, &ClassGuid,
ContextDevice, ContextDevice,
currentInfFileDetails,
filename, filename,
ProviderName, ProviderName,
ManufacturerName, ManufacturerName,
@ -4352,6 +4408,7 @@ SetupDiBuildDriverInfoList(
DriverType, DriverType,
&ClassGuid, &ClassGuid,
ContextDevice, ContextDevice,
currentInfFileDetails,
filename, filename,
ProviderName, ProviderName,
ManufacturerName, ManufacturerName,
@ -4372,6 +4429,7 @@ SetupDiBuildDriverInfoList(
DriverType, DriverType,
&ClassGuid, &ClassGuid,
ContextDevice, ContextDevice,
currentInfFileDetails,
filename, filename,
ProviderName, ProviderName,
ManufacturerName, ManufacturerName,
@ -4398,8 +4456,12 @@ next:
HeapFree(GetProcessHeap(), 0, ProviderName); HeapFree(GetProcessHeap(), 0, ProviderName);
ProviderName = NULL; ProviderName = NULL;
SetupCloseInfFile(hInf); if (currentInfFileDetails->References == 0)
hInf = INVALID_HANDLE_VALUE; {
SetupCloseInfFile(currentInfFileDetails->hInf);
HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
currentInfFileDetails = NULL;
}
} }
ret = TRUE; ret = TRUE;
} }
@ -4425,8 +4487,11 @@ done:
HeapFree(GetProcessHeap(), 0, ManufacturerName); HeapFree(GetProcessHeap(), 0, ManufacturerName);
HeapFree(GetProcessHeap(), 0, HardwareIDs); HeapFree(GetProcessHeap(), 0, HardwareIDs);
HeapFree(GetProcessHeap(), 0, CompatibleIDs); HeapFree(GetProcessHeap(), 0, CompatibleIDs);
if (hInf != INVALID_HANDLE_VALUE) if (currentInfFileDetails && currentInfFileDetails->References == 0)
SetupCloseInfFile(hInf); {
SetupCloseInfFile(currentInfFileDetails->hInf);
HeapFree(GetProcessHeap(), 0, currentInfFileDetails);
}
HeapFree(GetProcessHeap(), 0, Buffer); HeapFree(GetProcessHeap(), 0, Buffer);
TRACE("Returning %d\n", ret); TRACE("Returning %d\n", ret);
@ -4505,8 +4570,7 @@ SetupDiDestroyDriverInfoList(
{ {
ListEntry = RemoveHeadList(&list->DriverListHead); ListEntry = RemoveHeadList(&list->DriverListHead);
driverInfo = (struct DriverInfoElement *)ListEntry; driverInfo = (struct DriverInfoElement *)ListEntry;
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId); DestroyDriverInfoElement(driverInfo);
HeapFree(GetProcessHeap(), 0, driverInfo);
} }
InstallParams.Reserved = 0; InstallParams.Reserved = 0;
InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS); InstallParams.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
@ -4531,8 +4595,7 @@ SetupDiDestroyDriverInfoList(
InstallParamsSet.Reserved = 0; InstallParamsSet.Reserved = 0;
SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet); SetupDiSetDeviceInstallParamsW(DeviceInfoSet, NULL, &InstallParamsSet);
} }
HeapFree(GetProcessHeap(), 0, driverInfo->MatchingId); DestroyDriverInfoElement(driverInfo);
HeapFree(GetProcessHeap(), 0, driverInfo);
} }
InstallParams.Reserved = 0; InstallParams.Reserved = 0;
InstallParams.Flags &= ~DI_DIDCOMPAT; InstallParams.Flags &= ~DI_DIDCOMPAT;
@ -5263,7 +5326,6 @@ SetupDiInstallDriverFiles(
else else
{ {
SP_DEVINSTALL_PARAMS_W InstallParams; SP_DEVINSTALL_PARAMS_W InstallParams;
HINF hInf = INVALID_HANDLE_VALUE;
struct DriverInfoElement *SelectedDriver; struct DriverInfoElement *SelectedDriver;
WCHAR SectionName[MAX_PATH]; WCHAR SectionName[MAX_PATH];
DWORD SectionNameLength = 0; DWORD SectionNameLength = 0;
@ -5280,18 +5342,17 @@ SetupDiInstallDriverFiles(
goto cleanup; goto cleanup;
} }
hInf = SetupOpenInfFileW(SelectedDriver->Details.InfFileName, NULL, INF_STYLE_WIN4, NULL); ret = SetupDiGetActualSectionToInstallW(
if (hInf == INVALID_HANDLE_VALUE) SelectedDriver->InfFileDetails->hInf,
goto cleanup; SelectedDriver->Details.SectionName,
ret = SetupDiGetActualSectionToInstallW(hInf, SelectedDriver->Details.SectionName,
SectionName, MAX_PATH, &SectionNameLength, NULL); SectionName, MAX_PATH, &SectionNameLength, NULL);
if (!ret) if (!ret)
goto cleanup; goto cleanup;
if (InstallParams.InstallMsgHandler) if (InstallParams.InstallMsgHandler)
{ {
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent, hInf, SectionName, ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
SPINST_FILES, NULL, NULL, SP_COPY_NEWER, SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
DeviceInfoSet, DeviceInfoData); DeviceInfoSet, DeviceInfoData);
@ -5299,15 +5360,14 @@ SetupDiInstallDriverFiles(
else else
{ {
PVOID callback_context = SetupInitDefaultQueueCallback(InstallParams.hwndParent); PVOID callback_context = SetupInitDefaultQueueCallback(InstallParams.hwndParent);
ret = SetupInstallFromInfSectionW(InstallParams.hwndParent, hInf, SectionName, ret = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
SPINST_FILES, NULL, NULL, SP_COPY_NEWER, SPINST_FILES, NULL, NULL, SP_COPY_NEWER,
SetupDefaultQueueCallbackW, callback_context, SetupDefaultQueueCallbackW, callback_context,
DeviceInfoSet, DeviceInfoData); DeviceInfoSet, DeviceInfoData);
SetupTermDefaultQueueCallback(callback_context); SetupTermDefaultQueueCallback(callback_context);
} }
cleanup: cleanup:
if (hInf != INVALID_HANDLE_VALUE)
SetupCloseInfFile(hInf);
if (ret) if (ret)
{ {
InstallParams.Flags |= DI_NOFILECOPY; InstallParams.Flags |= DI_NOFILECOPY;
@ -5371,10 +5431,9 @@ SetupDiInstallDevice(
INT Flags; INT Flags;
ULONG DoAction; ULONG DoAction;
DWORD RequiredSize; DWORD RequiredSize;
HINF hInf = INVALID_HANDLE_VALUE;
LPCWSTR AssociatedService = NULL; LPCWSTR AssociatedService = NULL;
LPWSTR pSectionName = NULL; LPWSTR pSectionName = NULL;
LPWSTR ClassName = NULL; WCHAR ClassName[MAX_CLASS_NAME_LEN];
GUID ClassGuid; GUID ClassGuid;
LPWSTR lpGuidString = NULL, lpFullGuidString = NULL; LPWSTR lpGuidString = NULL, lpFullGuidString = NULL;
BOOL RebootRequired = FALSE; BOOL RebootRequired = FALSE;
@ -5422,32 +5481,17 @@ SetupDiInstallDevice(
FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate); FileTimeToSystemTime(&SelectedDriver->Info.DriverDate, &DriverDate);
hInf = SetupOpenInfFileW(SelectedDriver->Details.InfFileName, NULL, INF_STYLE_WIN4, NULL); Result = SetupDiGetActualSectionToInstallW(
if (hInf == INVALID_HANDLE_VALUE) SelectedDriver->InfFileDetails->hInf,
goto cleanup; SelectedDriver->Details.SectionName,
Result = SetupDiGetActualSectionToInstallW(hInf, SelectedDriver->Details.SectionName,
SectionName, MAX_PATH, &SectionNameLength, NULL); SectionName, MAX_PATH, &SectionNameLength, NULL);
if (!Result || SectionNameLength > MAX_PATH - 9) if (!Result || SectionNameLength > MAX_PATH - 9)
goto cleanup; goto cleanup;
pSectionName = &SectionName[wcslen(SectionName)]; pSectionName = &SectionName[wcslen(SectionName)];
/* Get information from [Version] section */ /* Get information from [Version] section */
ClassName = NULL; if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, MAX_CLASS_NAME_LEN, &RequiredSize))
RequiredSize = 0; goto cleanup;
if (!SetupDiGetINFClassW(SelectedDriver->Details.InfFileName, &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(SelectedDriver->Details.InfFileName, &ClassGuid, ClassName, RequiredSize, &RequiredSize))
goto cleanup;
}
/* Format ClassGuid to a string */ /* Format ClassGuid to a string */
if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK) if (UuidToStringW((UUID*)&ClassGuid, &lpGuidString) != RPC_S_OK)
goto cleanup; goto cleanup;
@ -5481,7 +5525,8 @@ SetupDiInstallDevice(
/* Files have already been copied in SetupDiInstallDriverFiles. /* Files have already been copied in SetupDiInstallDriverFiles.
* Process only registry entries. */ * Process only registry entries. */
*pSectionName = '\0'; *pSectionName = '\0';
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent, hInf, SectionName, Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
DoAction, hKey, NULL, SP_COPY_NEWER, DoAction, hKey, NULL, SP_COPY_NEWER,
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
DeviceInfoSet, DeviceInfoData); DeviceInfoSet, DeviceInfoData);
@ -5541,7 +5586,7 @@ SetupDiInstallDevice(
/* Install .Services section */ /* Install .Services section */
wcscpy(pSectionName, L".Services"); wcscpy(pSectionName, L".Services");
Result = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService); Result = SetupFindFirstLineW(SelectedDriver->InfFileDetails->hInf, SectionName, NULL, &ContextService);
while (Result) while (Result)
{ {
LPWSTR ServiceName = NULL; LPWSTR ServiceName = NULL;
@ -5600,12 +5645,14 @@ SetupDiInstallDevice(
&ContextService, &ContextService,
3, /* Field index */ 3, /* Field index */
ServiceSection, RequiredSize, ServiceSection, RequiredSize,
&RequiredSize); &RequiredSize);
if (!Result) if (!Result)
goto nextfile; goto nextfile;
} }
SetLastError(ERROR_SUCCESS); SetLastError(ERROR_SUCCESS);
Result = SetupInstallServicesFromInfSectionExW(hInf, ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL); Result = SetupInstallServicesFromInfSectionExW(
SelectedDriver->InfFileDetails->hInf,
ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL);
if (Result && (Flags & SPSVCINST_ASSOCSERVICE)) if (Result && (Flags & SPSVCINST_ASSOCSERVICE))
{ {
AssociatedService = ServiceName; AssociatedService = ServiceName;
@ -5631,7 +5678,8 @@ nextfile:
/* Install .HW section */ /* Install .HW section */
wcscpy(pSectionName, L".HW"); wcscpy(pSectionName, L".HW");
Result = SetupInstallFromInfSectionW(InstallParams.hwndParent, hInf, SectionName, Result = SetupInstallFromInfSectionW(InstallParams.hwndParent,
SelectedDriver->InfFileDetails->hInf, SectionName,
SPINST_REGISTRY, hKey, NULL, 0, SPINST_REGISTRY, hKey, NULL, 0,
InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext, InstallParams.InstallMsgHandler, InstallParams.InstallMsgHandlerContext,
DeviceInfoSet, DeviceInfoData); DeviceInfoSet, DeviceInfoData);
@ -5681,10 +5729,7 @@ cleanup:
if (lpGuidString) if (lpGuidString)
RpcStringFreeW(&lpGuidString); RpcStringFreeW(&lpGuidString);
HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService); HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService);
HeapFree(GetProcessHeap(), 0, ClassName);
HeapFree(GetProcessHeap(), 0, lpFullGuidString); HeapFree(GetProcessHeap(), 0, lpFullGuidString);
if (hInf != INVALID_HANDLE_VALUE)
SetupCloseInfFile(hInf);
TRACE("Returning %d\n", ret); TRACE("Returning %d\n", ret);
return ret; return ret;