You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1800 lines
44 KiB
1800 lines
44 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
register.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of exception package migration registration.
|
|
|
|
An exception package consists is a setupapi package that can be installed
|
|
on the system. The package consists of an exception INF, a catalog file,
|
|
and the corresponding files for the package. All files in this package
|
|
must be signed. The catalog is signed and contains signatures for all
|
|
other files in the catalog (including the INF).
|
|
|
|
Packages to be migrated from downlevel systems are registered with the
|
|
following APIs in this module. The APIs simply validate that the package
|
|
is put together properly and stores migration information in the registry
|
|
in a well-known location.
|
|
|
|
The data is stored under the following key:
|
|
|
|
Software\Microsoft\Windows\CurrentVersion\Setup\ExceptionComponents
|
|
|
|
There is one subkey corresponding to the GUID for each component.
|
|
The data for each component is then stored under this key.
|
|
|
|
In addition, the toplevel key has a "ComponentList" REG_EXPAND_SZ, which
|
|
lists the order in which the components should be enumerated.
|
|
|
|
Note that the following code only uses common system APIs instead of
|
|
any pre-defined library routines. This is to ensure that this library can
|
|
run on downlevel systems without any odd dependencies.
|
|
|
|
Author:
|
|
|
|
Andrew Ritz (AndrewR) 21-Oct-1999
|
|
|
|
Revision History:
|
|
|
|
Andrew Ritz (andrewr) 21-Oct-1999 : Created It
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <setupapi.h>
|
|
#include <ole2.h>
|
|
#include <excppkg.h>
|
|
|
|
#define COMPONENT_KEY L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\ExceptionComponents"
|
|
#define COMPONENT_LIST L"ComponentList"
|
|
|
|
#define EXCEPTION_CLASS_GUID L"{F5776D81-AE53-4935-8E84-B0B283D8BCEF}"
|
|
|
|
#define COMPONENT_FRIENDLY_NAME L"FriendlyName"
|
|
#define COMPONENT_GUID L"ComponentGUID"
|
|
#define COMPONENT_VERSION L"Version"
|
|
#define COMPONENT_SUBVERSION L"Sub-Version"
|
|
#define EXCEPTION_INF_NAME L"ExceptionInfName"
|
|
#define EXCEPTION_CATALOG_NAME L"ExceptionCatalogName"
|
|
|
|
#define MALLOC(_size_) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, _size_ )
|
|
#define FREE(_ptr_) HeapFree( GetProcessHeap(), 0 , _ptr_ )
|
|
|
|
|
|
typedef struct _COMPONENT_ENUMERATION_LIST {
|
|
LPGUID InputComponentList;
|
|
DWORD ComponentCount;
|
|
DWORD ValidatedCount;
|
|
PDWORD ComponentVector;
|
|
} COMPONENT_ENUMERATION_LIST, *PCOMPONENT_ENUMERATION_LIST;
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
_SetupSetRegisteredOsComponentsOrder(
|
|
IN DWORD ComponentCount,
|
|
IN const LPGUID ComponentList,
|
|
IN BOOL DoValidation
|
|
);
|
|
|
|
BOOL
|
|
pSetComponentData(
|
|
IN HKEY hKey,
|
|
IN const PSETUP_OS_COMPONENT_DATA ComponentData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set's the data in the SETUP_OS_COMPONENT_DATA structure in the
|
|
registry at the specified registry key
|
|
|
|
Arguments:
|
|
|
|
hKey - registry key specifying location to insert data at
|
|
ComponentData - specifies the data to be set in the registry
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the data was successfully set in the registry.
|
|
|
|
--*/
|
|
{
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD value;
|
|
PWSTR GuidString;
|
|
|
|
//
|
|
// just set the data, assume that it's already been validated
|
|
//
|
|
|
|
//
|
|
// FriendlyName
|
|
//
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
COMPONENT_FRIENDLY_NAME,
|
|
0,
|
|
REG_SZ,
|
|
(CONST PBYTE)ComponentData->FriendlyName,
|
|
(wcslen(ComponentData->FriendlyName)+1)*sizeof(WCHAR));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
|
|
StringFromIID( &ComponentData->ComponentGuid, &GuidString );
|
|
|
|
//
|
|
// ComponentGUID
|
|
//
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
COMPONENT_GUID,
|
|
0,
|
|
REG_SZ,
|
|
(CONST PBYTE)GuidString,
|
|
(wcslen(GuidString)+1)*sizeof(WCHAR));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// Version
|
|
//
|
|
value = MAKELONG( ComponentData->VersionMinor, ComponentData->VersionMajor );
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
COMPONENT_VERSION,
|
|
0,
|
|
REG_DWORD,
|
|
(CONST PBYTE)&value,
|
|
sizeof(DWORD));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// build+QFE
|
|
//
|
|
value = MAKELONG( ComponentData->QFENumber, ComponentData->BuildNumber );
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
COMPONENT_SUBVERSION,
|
|
0,
|
|
REG_DWORD,
|
|
(CONST PBYTE)&value,
|
|
sizeof(DWORD));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e1:
|
|
CoTaskMemFree( GuidString );
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
BOOL
|
|
pGetComponentData(
|
|
IN HKEY hKey,
|
|
IN const PSETUP_OS_COMPONENT_DATA ComponentData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retreives the data in the SETUP_OS_COMPONENT_DATA structure in the
|
|
registry at the specified registry key
|
|
|
|
Arguments:
|
|
|
|
hKey - registry key specifying location to insert data at
|
|
ComponentData - specifies the data to be set in the registry
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the data was successfully retreived.
|
|
|
|
--*/
|
|
{
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Type,Size;
|
|
DWORD Version;
|
|
DWORD SubVersion;
|
|
WCHAR GuidString[40];
|
|
|
|
//
|
|
// FriendlyName
|
|
//
|
|
Size = sizeof(ComponentData->FriendlyName);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_FRIENDLY_NAME,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)ComponentData->FriendlyName,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
if (Type != REG_SZ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// ComponentGUID
|
|
//
|
|
Size = sizeof(GuidString);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_GUID,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)GuidString,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (Type != REG_SZ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
|
|
if (IIDFromString( GuidString, &ComponentData->ComponentGuid ) != S_OK) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
|
|
//
|
|
// Version
|
|
//
|
|
Size = sizeof(Version);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_VERSION,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)&Version,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
if (Type != REG_DWORD) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
ComponentData->VersionMajor = HIWORD(Version);
|
|
ComponentData->VersionMinor = LOWORD(Version);
|
|
|
|
//
|
|
// Sub-Version
|
|
//
|
|
Size = sizeof(SubVersion);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_SUBVERSION,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)&SubVersion,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
if (Type != REG_DWORD) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
ComponentData->BuildNumber = HIWORD(SubVersion);
|
|
ComponentData->QFENumber = LOWORD(SubVersion);
|
|
|
|
RetVal = TRUE;
|
|
goto e0;
|
|
|
|
e3:
|
|
ComponentData->VersionMajor = 0;
|
|
ComponentData->VersionMinor = 0;
|
|
e2:
|
|
ZeroMemory(
|
|
&ComponentData->ComponentGuid,
|
|
sizeof(ComponentData->ComponentGuid));
|
|
e1:
|
|
ComponentData->FriendlyName[0] = L'0';
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
BOOL
|
|
pSetExceptionData(
|
|
IN HKEY hKey,
|
|
IN const PSETUP_OS_EXCEPTION_DATA ExceptionData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set's the data in the SETUP_OS_EXCEPTION_DATA structure in the
|
|
registry at the specified registry key
|
|
|
|
Arguments:
|
|
|
|
hKey - registry key specifying location to insert data at
|
|
ComponentData - specifies the data to be set in the registry
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the data is successfully stored in the registry.
|
|
|
|
--*/
|
|
{
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
|
|
//
|
|
// just set the data, assume that it's already been validated
|
|
//
|
|
|
|
//
|
|
// InfName
|
|
//
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
EXCEPTION_INF_NAME,
|
|
0,
|
|
REG_EXPAND_SZ,
|
|
(CONST PBYTE)ExceptionData->ExceptionInfName,
|
|
(wcslen(ExceptionData->ExceptionInfName)+1)*sizeof(WCHAR));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// CatalogName
|
|
//
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
EXCEPTION_CATALOG_NAME,
|
|
0,
|
|
REG_EXPAND_SZ,
|
|
(CONST PBYTE)ExceptionData->CatalogFileName,
|
|
(wcslen(ExceptionData->CatalogFileName)+1)*sizeof(WCHAR));
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
BOOL
|
|
pGetExceptionData(
|
|
IN HKEY hKey,
|
|
IN const PSETUP_OS_EXCEPTION_DATA ExceptionData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retreives the data in the SETUP_OS_EXCEPTION_DATA structure in the
|
|
registry at the specified registry key
|
|
|
|
Arguments:
|
|
|
|
hKey - registry key specifying location to insert data at
|
|
ComponentData - specifies the data to be set in the registry
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the data is successfully retreived from the registry.
|
|
|
|
--*/
|
|
{
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Type,Size;
|
|
WCHAR Buffer[MAX_PATH];
|
|
|
|
//
|
|
// InfName
|
|
//
|
|
Size = sizeof(Buffer);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
EXCEPTION_INF_NAME,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)Buffer,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
if (Type != REG_EXPAND_SZ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
if (!ExpandEnvironmentStrings(
|
|
Buffer,
|
|
ExceptionData->ExceptionInfName,
|
|
sizeof(ExceptionData->ExceptionInfName)/sizeof(WCHAR))) {
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// Catalog Name
|
|
//
|
|
Size = sizeof(Buffer);
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
EXCEPTION_CATALOG_NAME,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)Buffer,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (Type != REG_EXPAND_SZ) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if(!ExpandEnvironmentStrings(
|
|
Buffer,
|
|
ExceptionData->CatalogFileName,
|
|
sizeof(ExceptionData->CatalogFileName)/sizeof(WCHAR))) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
goto e0;
|
|
|
|
|
|
e1:
|
|
ExceptionData->ExceptionInfName[0] = L'0';
|
|
e0:
|
|
return(RetVal);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupRegisterOsComponent(
|
|
IN const PSETUP_OS_COMPONENT_DATA ComponentData,
|
|
IN const PSETUP_OS_EXCEPTION_DATA ExceptionData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Registers the specified component as a exception migration component.
|
|
|
|
This function does validation of the package, trying to assert that the
|
|
package has a good probability of succeeding installation. It then
|
|
records the data about the package in the registry.
|
|
|
|
|
|
Arguments:
|
|
|
|
ComponentData - specifies the component identification data
|
|
ExceptionData - specifies the exception package identification data
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component is successfully registered with the operating system.
|
|
|
|
--*/
|
|
{
|
|
BOOL RetVal;
|
|
HKEY hKey,hKeyComponent;
|
|
LONG rslt;
|
|
HINF hInf;
|
|
DWORD ErrorLine;
|
|
INFCONTEXT InfContext;
|
|
WCHAR InfComponentGuid[64];
|
|
PWSTR InputGuidString;
|
|
WCHAR InfName[MAX_PATH];
|
|
WCHAR CatalogName[MAX_PATH];
|
|
WCHAR InfCatName[MAX_PATH];
|
|
DWORD Disposition;
|
|
|
|
DWORD ComponentCount;
|
|
DWORD Size;
|
|
PWSTR p;
|
|
LPGUID ComponentList;
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
if (!ComponentData || !ExceptionData) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// make sure we only register a component for a revision level
|
|
// which we understand.
|
|
//
|
|
if ((ComponentData->SizeOfStruct != sizeof(SETUP_OS_COMPONENT_DATA)) ||
|
|
(ExceptionData->SizeOfStruct != sizeof(SETUP_OS_EXCEPTION_DATA))) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// All of the parameters in the structure are required
|
|
//
|
|
if (!*ComponentData->FriendlyName ||
|
|
!*ExceptionData->ExceptionInfName || !*ExceptionData->CatalogFileName) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// Make sure that the INF and catalog are both present.
|
|
//
|
|
ExpandEnvironmentStrings(
|
|
ExceptionData->ExceptionInfName,
|
|
InfName,
|
|
sizeof(InfName)/sizeof(WCHAR));
|
|
|
|
ExpandEnvironmentStrings(
|
|
ExceptionData->CatalogFileName,
|
|
CatalogName,
|
|
sizeof(CatalogName)/sizeof(WCHAR));
|
|
|
|
if (GetFileAttributes(InfName) == -1 ||
|
|
GetFileAttributes(CatalogName) == -1) {
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// open the INF to do some validation
|
|
//
|
|
hInf = SetupOpenInfFile( InfName,
|
|
NULL, //EXCEPTION_CLASS_GUID,
|
|
INF_STYLE_WIN4,
|
|
&ErrorLine);
|
|
|
|
if (hInf == INVALID_HANDLE_VALUE) {
|
|
// return last error code from setupopeninffile
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// Make sure the class GUID matches the expected exception class
|
|
// class GUID.
|
|
//
|
|
if (!SetupFindFirstLine(
|
|
hInf,
|
|
L"Version",
|
|
L"ClassGUID",
|
|
&InfContext)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
InfComponentGuid,
|
|
sizeof(InfComponentGuid) / sizeof(InfComponentGuid[0]),
|
|
&ErrorLine)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (_wcsicmp(EXCEPTION_CLASS_GUID, InfComponentGuid)) {
|
|
SetLastError(ERROR_INVALID_CLASS);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// Make sure that the INF component ID matches the supplied GUID
|
|
//
|
|
if (!SetupFindFirstLine(
|
|
hInf,
|
|
L"Version",
|
|
L"ComponentId",
|
|
&InfContext)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
InfComponentGuid,
|
|
sizeof(InfComponentGuid) / sizeof(InfComponentGuid[0]),
|
|
&ErrorLine)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
StringFromIID( &ComponentData->ComponentGuid, &InputGuidString );
|
|
|
|
if (_wcsicmp(InfComponentGuid, InputGuidString)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// Make sure the INF has a catalogfile= line, and that this line matches
|
|
// the specified catalog file
|
|
//
|
|
//
|
|
if (!SetupFindFirstLine(
|
|
hInf,
|
|
L"Version",
|
|
L"CatalogFile",
|
|
&InfContext)) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
if (!SetupGetStringField(
|
|
&InfContext,
|
|
1,
|
|
InfCatName,
|
|
sizeof(InfCatName) / sizeof(InfCatName[0]),
|
|
&ErrorLine)) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
p = wcsrchr( CatalogName, L'\\' );
|
|
if (p) {
|
|
p += 1;
|
|
} else {
|
|
p = CatalogName;
|
|
}
|
|
|
|
if (_wcsicmp(p, InfCatName)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
|
|
//
|
|
// Everything seems to validate. Try to add the new component.
|
|
//
|
|
|
|
//
|
|
// Before we try to add the component, get the list of existing components
|
|
// so we can set the component in the list of components.
|
|
//
|
|
Size = 0;
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
NULL
|
|
)) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
ComponentList = (LPGUID)MALLOC((ComponentCount+1)*sizeof(GUID));
|
|
if (!ComponentList) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
ComponentList)) {
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
//
|
|
// put the new component at the tail of the component list (since this is
|
|
// a zero-based array, this is easy to insert).
|
|
//
|
|
RtlMoveMemory(
|
|
&ComponentList[ComponentCount],
|
|
&ComponentData->ComponentGuid,
|
|
sizeof(ComponentData->ComponentGuid));
|
|
|
|
//
|
|
// First open the main key which all components live under
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
//
|
|
// now look at the actual key we'll store this component under
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
hKey,
|
|
InputGuidString,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKeyComponent,
|
|
&Disposition);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e4;
|
|
}
|
|
|
|
//
|
|
// If this component is already registered, then bail
|
|
//
|
|
if (Disposition != REG_CREATED_NEW_KEY) {
|
|
SetLastError(ERROR_ALREADY_EXISTS);
|
|
RetVal = FALSE;
|
|
goto e5;
|
|
}
|
|
|
|
//
|
|
// The key is created, now set all of the data under the key
|
|
//
|
|
if (!pSetComponentData(hKeyComponent, ComponentData) ||
|
|
!pSetExceptionData(hKeyComponent, ExceptionData)) {
|
|
//
|
|
// if we failed, we need to delete everything under this key
|
|
//
|
|
rslt = GetLastError();
|
|
RegDeleteKey( hKey, InputGuidString );
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e5;
|
|
}
|
|
|
|
//
|
|
// now set the component order in the registry
|
|
//
|
|
if (!_SetupSetRegisteredOsComponentsOrder(
|
|
ComponentCount+1,
|
|
ComponentList,
|
|
FALSE)) {
|
|
rslt = GetLastError();
|
|
RegDeleteKey( hKey, InputGuidString );
|
|
SetLastError(rslt);
|
|
RetVal = FALSE;
|
|
goto e5;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e5:
|
|
RegCloseKey(hKeyComponent);
|
|
e4:
|
|
RegCloseKey(hKey);
|
|
e3:
|
|
FREE(ComponentList);
|
|
e2:
|
|
CoTaskMemFree(InputGuidString);
|
|
e1:
|
|
SetupCloseInfFile(hInf);
|
|
e0:
|
|
return(RetVal);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupUnRegisterOsComponent(
|
|
IN const LPGUID ComponentGuid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
De-Registers the specified component as a exception migration component.
|
|
|
|
This function only removes the exception package data from the registry.
|
|
It does not remove any on-disk files which correspond with the migration
|
|
component data.
|
|
|
|
|
|
Arguments:
|
|
|
|
ComponentData - specifies the component identification data
|
|
ExceptionData - specifies the exception package identification data
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component is successfully registered with the operating system.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Disposition;
|
|
DWORD Size,ComponentCount;
|
|
PWSTR GuidString;
|
|
LPGUID ComponentList,NewList,src,dst;
|
|
DWORD i;
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
if (!ComponentGuid) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
StringFromIID( ComponentGuid, &GuidString );
|
|
|
|
//
|
|
// open the main component key where all of the subcomponents live
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// query the component order list so that we can remove this component
|
|
// from the list
|
|
//
|
|
Size = 0;
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
NULL)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
ComponentList = (LPGUID)MALLOC((ComponentCount)*sizeof(GUID));
|
|
if (!ComponentList) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
NewList = (LPGUID)MALLOC((ComponentCount)*sizeof(GUID));
|
|
if (!NewList) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
ComponentList)) {
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
if (ComponentCount) {
|
|
//
|
|
// Iterate through the list of components, keeping all of the components
|
|
// except for the one we're removing.
|
|
//
|
|
BOOL FoundEntry;
|
|
src = ComponentList;
|
|
dst = NewList;
|
|
i = 0;
|
|
FoundEntry = FALSE;
|
|
while(i < ComponentCount) {
|
|
if (!IsEqualGUID(src,ComponentGuid)) {
|
|
RtlMoveMemory(dst,src,sizeof(GUID));
|
|
dst = dst + 1;
|
|
} else {
|
|
FoundEntry = TRUE;
|
|
}
|
|
|
|
src = src + 1;
|
|
i +=1;
|
|
}
|
|
|
|
if (!FoundEntry) {
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
if (!_SetupSetRegisteredOsComponentsOrder(
|
|
ComponentCount-1,
|
|
NewList,
|
|
FALSE)) {
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete the key corresponding to the specified component.
|
|
//
|
|
rslt = RegDeleteKey( hKey, GuidString );
|
|
if (rslt != ERROR_SUCCESS) {
|
|
//
|
|
// If this fails, we don't bother to put the component back in the list
|
|
//
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e3:
|
|
FREE(NewList);
|
|
e2:
|
|
FREE(ComponentList);
|
|
e1:
|
|
RegCloseKey( hKey );
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupEnumerateRegisteredOsComponents(
|
|
IN PSETUPCOMPONENTCALLBACK SetupOsComponentCallback,
|
|
IN DWORD_PTR Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls the specified callback function once for each
|
|
registered component. The registered components are enumerated in
|
|
the order defined by the "ComponentList".
|
|
|
|
The enumeration stops if the enumerator returns FALSE or when all
|
|
of the installed packages have been enumerated.
|
|
|
|
Arguments:
|
|
|
|
SetupOsComponentCallback - specifies a callback function which is called
|
|
once for each component.
|
|
Context - specifies an opaque context point passed onto the callback
|
|
function
|
|
|
|
The callback is of the form:
|
|
|
|
typedef BOOL
|
|
(CALLBACK *PSETUPCOMPONENTCALLBACK) (
|
|
IN const PSETUP_OS_COMPONENT_DATA SetupOsComponentData,
|
|
IN const PSETUP_OS_EXCEPTION_DATA SetupOsExceptionData,
|
|
IN OUT DWORD_PTR Context
|
|
);
|
|
|
|
where
|
|
|
|
SetupOsComponentData - specifies the component identification data for the
|
|
component
|
|
SetupOsExceptionData - specifies the exception package data for the
|
|
component
|
|
Context - the context pointer passed into this function is passed
|
|
into the callback function
|
|
|
|
Return Value:
|
|
|
|
TRUE if all of the components are enumerated. If the callback stops
|
|
enumeration, the function returns FALSE and GetLastError() returns
|
|
ERROR_CANCELLED.
|
|
|
|
--*/
|
|
{
|
|
BOOL RetVal;
|
|
LONG rslt;
|
|
HKEY hKey;
|
|
HKEY hKeyEnum = NULL;
|
|
DWORD Index = 0;
|
|
DWORD Disposition;
|
|
WCHAR SubKeyName[100];
|
|
DWORD Size;
|
|
DWORD ComponentCount = 0;
|
|
LPGUID ComponentList;
|
|
|
|
SETUP_OS_EXCEPTION_DATA OsExceptionDataInternal;
|
|
SETUP_OS_COMPONENT_DATA OsComponentDataInternal;
|
|
|
|
//
|
|
// Caller must supply a callback
|
|
//
|
|
if (!SetupOsComponentCallback) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// open the main component key where all of the subcomponents live
|
|
// (Note that we only require READ access)
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
|
|
//
|
|
// query the component order list so that we can remove this component
|
|
// from the list
|
|
//
|
|
Size = 0;
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
NULL)) {
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (!ComponentCount) {
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
RetVal = TRUE;
|
|
goto e1;
|
|
}
|
|
|
|
ComponentList = (LPGUID)MALLOC(ComponentCount*sizeof(GUID));
|
|
if (!ComponentList) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (!SetupQueryRegisteredOsComponentsOrder(
|
|
&ComponentCount,
|
|
ComponentList)) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// Iterate through the list of components, calling into the callback
|
|
// for each one
|
|
//
|
|
for (Index = 0; Index < ComponentCount; Index++) {
|
|
PWSTR GuidString;
|
|
|
|
StringFromIID( &ComponentList[Index], &GuidString );
|
|
|
|
//
|
|
// open that key name
|
|
//
|
|
rslt = RegOpenKeyEx(
|
|
hKey,
|
|
GuidString,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyEnum);
|
|
|
|
CoTaskMemFree( GuidString );
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// retreive the data under this key
|
|
//
|
|
OsComponentDataInternal.SizeOfStruct = sizeof(SETUP_OS_COMPONENT_DATA);
|
|
OsExceptionDataInternal.SizeOfStruct = sizeof(SETUP_OS_EXCEPTION_DATA);
|
|
if (!pGetComponentData(hKeyEnum, &OsComponentDataInternal) ||
|
|
!pGetExceptionData(hKeyEnum, &OsExceptionDataInternal)) {
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
if (!SetupOsComponentCallback(
|
|
&OsComponentDataInternal,
|
|
&OsExceptionDataInternal,
|
|
Context )) {
|
|
SetLastError(ERROR_CANCELLED);
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
RegCloseKey( hKeyEnum );
|
|
hKeyEnum = NULL;
|
|
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e3:
|
|
if (hKeyEnum) {
|
|
RegCloseKey( hKeyEnum );
|
|
}
|
|
e2:
|
|
FREE( ComponentList );
|
|
e1:
|
|
RegCloseKey( hKey );
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupQueryRegisteredOsComponent(
|
|
IN LPGUID ComponentGuid,
|
|
OUT PSETUP_OS_COMPONENT_DATA SetupOsComponentData,
|
|
OUT PSETUP_OS_EXCEPTION_DATA SetupOsExceptionData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves information about the specified component.
|
|
|
|
Arguments:
|
|
|
|
ComponentGuid - specifies the GUID for the component to retreive data about
|
|
ComponentData - receives the component identification data
|
|
ExceptionData - receives the exception package identification data
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component data is successfully retreieved.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey,hKeyComponent;
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Disposition;
|
|
SETUP_OS_EXCEPTION_DATA OsExceptionDataInternal;
|
|
SETUP_OS_COMPONENT_DATA OsComponentDataInternal;
|
|
PWSTR GuidString;
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
if (!ComponentGuid || !SetupOsComponentData || !SetupOsExceptionData) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// make sure we only retreive a component for a revision level
|
|
// which we understand
|
|
//
|
|
if (SetupOsComponentData->SizeOfStruct > sizeof(SETUP_OS_COMPONENT_DATA) ||
|
|
SetupOsExceptionData->SizeOfStruct > sizeof(SETUP_OS_EXCEPTION_DATA)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// open the main component key where all of the subcomponents live
|
|
// (note that we only need READ access)
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
StringFromIID( ComponentGuid, &GuidString );
|
|
|
|
//
|
|
// now look at the actual key this component lives under
|
|
//
|
|
rslt = RegOpenKeyEx(
|
|
hKey,
|
|
GuidString,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyComponent);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// retrieve the data into internal buffers
|
|
//
|
|
OsComponentDataInternal.SizeOfStruct = sizeof(SETUP_OS_COMPONENT_DATA);
|
|
OsExceptionDataInternal.SizeOfStruct = sizeof(SETUP_OS_EXCEPTION_DATA);
|
|
if (!pGetComponentData(hKeyComponent, &OsComponentDataInternal) ||
|
|
!pGetExceptionData(hKeyComponent, &OsExceptionDataInternal)) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// move the data into the caller supplied buffer, but only copy as much
|
|
// data as the caller will understand
|
|
//
|
|
RtlMoveMemory(SetupOsComponentData,&OsComponentDataInternal,SetupOsComponentData->SizeOfStruct);
|
|
RtlMoveMemory(SetupOsExceptionData,&OsExceptionDataInternal,SetupOsExceptionData->SizeOfStruct);
|
|
|
|
|
|
RetVal = TRUE;
|
|
e2:
|
|
RegCloseKey( hKeyComponent );
|
|
e1:
|
|
CoTaskMemFree( GuidString );
|
|
RegCloseKey( hKey );
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupQueryRegisteredOsComponentsOrder(
|
|
OUT PDWORD ComponentCount,
|
|
OUT LPGUID ComponentList OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves a list which specifies the order in which components will be applied.
|
|
|
|
Arguments:
|
|
|
|
ComponentCount - Receives the number of installed components
|
|
ComponentList - This buffer receives an array of component GUIDs. If
|
|
this parameter is specified, it must be at least
|
|
)ComponentCount *sizeof(GUID)) bytes large.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component ordering data is successfully retreieved.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Disposition;
|
|
DWORD Type,Size;
|
|
DWORD Count;
|
|
GUID CurrentGuid;
|
|
DWORD Index;
|
|
PWSTR RegData;
|
|
PWSTR p;
|
|
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
if (!ComponentCount) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// open the main component key where the component order list lives.
|
|
// (note that we only need READ access)
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// if the key was just created, then there can be no registered components
|
|
//
|
|
if (Disposition == REG_CREATED_NEW_KEY) {
|
|
*ComponentCount = 0;
|
|
SetLastError( ERROR_SUCCESS );
|
|
RetVal = TRUE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// try to access the registry value, seeing how much space we need for the
|
|
// component;
|
|
//
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_LIST,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)NULL,
|
|
&Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
if (rslt == ERROR_FILE_NOT_FOUND) {
|
|
*ComponentCount = 0;
|
|
SetLastError( ERROR_SUCCESS );
|
|
RetVal = TRUE;
|
|
goto e1;
|
|
} else {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// allocate enough space to retrieve the data (plus some slop)
|
|
//
|
|
RegData = (PWSTR) MALLOC(Size+4);
|
|
if (!RegData) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
RetVal = TRUE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// Now query the data
|
|
//
|
|
rslt = RegQueryValueEx(
|
|
hKey,
|
|
COMPONENT_LIST,
|
|
0,
|
|
&Type,
|
|
(LPBYTE)RegData,
|
|
&Size);
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// Count how many registry entries we have
|
|
//
|
|
Count = 0;
|
|
p = RegData;
|
|
while(*p) {
|
|
p += wcslen(p)+1;
|
|
Count += 1;
|
|
}
|
|
|
|
*ComponentCount = Count;
|
|
|
|
//
|
|
// if the caller didn't specify the ComponentList parameter, they just
|
|
// wanted to know how much space to allocate, so we're done.
|
|
//
|
|
if (!ComponentList) {
|
|
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
RetVal = TRUE;
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// loop through the component list again, converting the string GUID
|
|
// into a GUID structure, and copy this into the caller supplied buffer
|
|
//
|
|
for(Index = 0,p=RegData; Index < Count ; Index++,p += wcslen(p)+1) {
|
|
if (IIDFromString( p, &CurrentGuid ) != S_OK) {
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
RtlMoveMemory(&ComponentList[Index],&CurrentGuid,sizeof(GUID));
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e2:
|
|
FREE( RegData );
|
|
e1:
|
|
RegCloseKey( hKey );
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CALLBACK
|
|
pComponentListValidator(
|
|
IN const PSETUP_OS_COMPONENT_DATA SetupOsComponentData,
|
|
IN const PSETUP_OS_EXCEPTION_DATA SetupOsExceptionData,
|
|
IN OUT DWORD_PTR Context
|
|
)
|
|
{
|
|
PCOMPONENT_ENUMERATION_LIST cel = (PCOMPONENT_ENUMERATION_LIST) Context;
|
|
|
|
DWORD i;
|
|
|
|
i = 0;
|
|
//
|
|
// make sure that each component GUID is in our list once.
|
|
//
|
|
while(i < cel->ComponentCount) {
|
|
if (IsEqualGUID(
|
|
&SetupOsComponentData->ComponentGuid,
|
|
&cel->InputComponentList[i])) {
|
|
//
|
|
// if the vector is already set, this means that the GUID
|
|
// is already in the list and we've hit a dup.
|
|
//
|
|
if(cel->ComponentVector[i]) {
|
|
return(FALSE);
|
|
}
|
|
cel->ComponentVector[i] = 1;
|
|
cel->ValidatedCount += 1;
|
|
break;
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
_SetupSetRegisteredOsComponentsOrder(
|
|
IN DWORD ComponentCount,
|
|
IN const LPGUID ComponentList,
|
|
IN BOOL DoValidation
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allows the caller to specify the order in which components should be
|
|
applied.
|
|
|
|
This is an internal call that allows us to control whether or not we do
|
|
parameter validation (We don't validate parameters on internal calls
|
|
because we are adding or removing components in internal calls and our
|
|
validation checks will all be off by one.)
|
|
|
|
Arguments:
|
|
|
|
ComponentCount - specifies the component order (by GUID).
|
|
ComponentList - specifies the number of registered components
|
|
DoValidation - specifies whether the component list should be validated
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component order is successfully changed.
|
|
|
|
--*/
|
|
{
|
|
HKEY hKey;
|
|
LONG rslt;
|
|
BOOL RetVal;
|
|
DWORD Disposition;
|
|
DWORD Type,Size;
|
|
DWORD Count;
|
|
PWSTR RegData,p,GuidString;
|
|
COMPONENT_ENUMERATION_LIST cel;
|
|
|
|
cel.ComponentVector = NULL;
|
|
|
|
if (DoValidation) {
|
|
DWORD ActualComponentCount;
|
|
|
|
//
|
|
// parameter validation
|
|
//
|
|
if (!ComponentCount || !ComponentList) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
//
|
|
// Make sure that the specified list contains all of the components and
|
|
// that all components are only listed once.
|
|
//
|
|
cel.InputComponentList = ComponentList;
|
|
cel.ComponentCount = ComponentCount;
|
|
cel.ValidatedCount = 0;
|
|
cel.ComponentVector = MALLOC( ComponentCount * sizeof(DWORD));
|
|
if (!cel.ComponentVector) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
RetVal = FALSE;
|
|
goto e0;
|
|
}
|
|
|
|
RtlZeroMemory( cel.ComponentVector, ComponentCount * sizeof(DWORD));
|
|
|
|
if (!SetupEnumerateRegisteredOsComponents( pComponentListValidator, (DWORD_PTR)&cel)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
if (cel.ValidatedCount != ComponentCount) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
//
|
|
// make sure that the caller is specifying the actual number of
|
|
// registered components
|
|
//
|
|
if (!SetupQueryRegisteredOsComponentsOrder(&ActualComponentCount, NULL) ||
|
|
ActualComponentCount != ComponentCount) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// open the main component key where the component order list lives.
|
|
//
|
|
rslt = RegCreateKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
COMPONENT_KEY,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&Disposition);
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e1;
|
|
}
|
|
|
|
|
|
//
|
|
// if the count is zero, we remove the value.
|
|
//
|
|
if (ComponentCount == 0) {
|
|
rslt = RegDeleteValue(
|
|
hKey,
|
|
COMPONENT_LIST);
|
|
|
|
SetLastError( rslt );
|
|
RetVal = (rslt == ERROR_SUCCESS);
|
|
goto e2;
|
|
}
|
|
|
|
//
|
|
// allocate space for the string we will set in the registry
|
|
// size = (# of components * (40 WCHAR for GuidString + 1 for NULL)
|
|
// +terminating NULL)
|
|
//
|
|
RegData = (PWSTR) MALLOC( sizeof(WCHAR) +
|
|
(ComponentCount * (41*sizeof(WCHAR))) );
|
|
if (!RegData) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
RetVal = FALSE;
|
|
goto e2;
|
|
}
|
|
|
|
Size = 0;
|
|
for (Count = 0,p = RegData; Count < ComponentCount; Count++) {
|
|
|
|
HRESULT hr = StringFromIID( &ComponentList[Count], &GuidString );
|
|
|
|
if(FAILED(hr)) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
wcscpy( p, GuidString );
|
|
Size += (wcslen(p)+1)*sizeof(WCHAR);
|
|
p += wcslen(p)+1;
|
|
|
|
CoTaskMemFree( GuidString );
|
|
|
|
}
|
|
|
|
//
|
|
// add in one more character for the double-null terminator
|
|
//
|
|
Size += sizeof(WCHAR);
|
|
|
|
//
|
|
// now set the data
|
|
//
|
|
rslt = RegSetValueEx(
|
|
hKey,
|
|
COMPONENT_LIST,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(LPBYTE)RegData,
|
|
Size);
|
|
|
|
if (rslt != ERROR_SUCCESS) {
|
|
SetLastError( rslt );
|
|
RetVal = FALSE;
|
|
goto e3;
|
|
}
|
|
|
|
RetVal = TRUE;
|
|
|
|
e3:
|
|
FREE( RegData );
|
|
e2:
|
|
RegCloseKey( hKey );
|
|
e1:
|
|
if (cel.ComponentVector) {
|
|
FREE( cel.ComponentVector );
|
|
}
|
|
e0:
|
|
return(RetVal);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetupSetRegisteredOsComponentsOrder(
|
|
IN DWORD ComponentCount,
|
|
IN const LPGUID ComponentList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allows the caller to specify the order in which components should be applied.
|
|
|
|
Arguments:
|
|
|
|
ComponentCount - specifies the component order (by string GUID) in a NULL
|
|
separated list
|
|
ComponentList - specifies the number of registered components
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if the component order is successfully changed.
|
|
|
|
--*/
|
|
{
|
|
return(_SetupSetRegisteredOsComponentsOrder(
|
|
ComponentCount,
|
|
ComponentList,
|
|
TRUE));
|
|
}
|