4694 lines
107 KiB
C
4694 lines
107 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
octest.c
|
|
|
|
Abstract:
|
|
|
|
The code for the component setup DLL. This includes ComponentSetupProc,
|
|
the DLL's entry point that is called by the OC Manager, as well as some
|
|
routines that test the private data calls and the private functions calls.
|
|
|
|
Author:
|
|
|
|
Bogdan Andreiu (bogdana) 10-Feb-1997 Created.
|
|
Jason Allor (jasonall) 24-Feb-1998 Took over the project.
|
|
Sean Edmison (SEdmison) 21-Feb-2000 Took over the project.
|
|
|
|
Revision History:
|
|
|
|
10-Feb-1997 bogdana
|
|
First draft.
|
|
|
|
20-Feb-1997 bogdana
|
|
Added multistring testing for the private data
|
|
|
|
19-Mar-1997 bogdana
|
|
Modified and added routines that test the private functions call
|
|
|
|
21-Feb-2000 SEdmison
|
|
Initialized a bunch of variables.
|
|
Added casts to avoid compiler warnings.
|
|
Added a return TRUE to avoid compiler error.
|
|
|
|
--*/
|
|
#include "octest.h"
|
|
|
|
const static PTCHAR g_atszStringValues[MAX_STRINGS_FOR_PRIVATE_DATA] =
|
|
{
|
|
TEXT("First value to set"),
|
|
TEXT("Second value to set"),
|
|
TEXT("The third and longest value to set"),
|
|
TEXT(""),
|
|
TEXT("A"),
|
|
TEXT("AB"),
|
|
TEXT("ABC"),
|
|
TEXT("The final value : \\//\\//\\//\\")
|
|
};
|
|
|
|
const static PTCHAR g_atszMultiStringValues[MAX_MULTI_STRINGS_FOR_PRIVATE_DATA] =
|
|
{
|
|
TEXT("A\0B\0C\0D\0E\0\0"),
|
|
TEXT("\0\0"),
|
|
TEXT("One\0Two\0Three\0\0"),
|
|
TEXT("String1\0\0"),
|
|
TEXT("0\01\02\03\0\0"),
|
|
TEXT("Multi\0String\0\\0\0\0")
|
|
};
|
|
|
|
/*++
|
|
|
|
Routine Description: DllMain (1.24)
|
|
|
|
main routine
|
|
|
|
Arguments:
|
|
|
|
standard DllMain arguments
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
|
|
--*/
|
|
BOOL WINAPI DllMain(IN HINSTANCE hInstance,
|
|
IN DWORD fdwReason,
|
|
IN PVOID pvReserved)
|
|
{
|
|
USHORT i = 0;
|
|
TCHAR tszModulePath[MAX_PATH], szMsg[MAX_MSG_LEN];
|
|
PTCHAR tszLogPath = NULL;
|
|
PTCHAR tszAux = NULL;
|
|
static UINT uiThreadCount = 0;
|
|
|
|
switch (fdwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
InitializeMemoryManager();
|
|
InitGlobals();
|
|
|
|
ParseCommandLine();
|
|
|
|
//
|
|
// Randomize, save the module instance and in initialize the log
|
|
//
|
|
srand((unsigned) time(NULL));
|
|
g_hDllInstance = hInstance;
|
|
InitCommonControls();
|
|
GetModuleFileName(g_hDllInstance, tszModulePath, MAX_PATH);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
CleanUpTest();
|
|
ExitLog();
|
|
CheckAllocs();
|
|
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
|
|
//
|
|
// If we added a participant, we have to remoce it
|
|
//
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
|
|
//
|
|
// Otherwise we won't be able to log on correctly
|
|
//
|
|
uiThreadCount++;
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
return TRUE;
|
|
|
|
} // DllMain //
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Functions to set up UI
|
|
//
|
|
//==========================================================================
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ChooseVersionDlgProc (1.26)
|
|
|
|
Dialog procedure that allows the user to choose a component version
|
|
less, equal or greater then the one of the OC Manager's.
|
|
|
|
Arguments:
|
|
|
|
Standard dialog procedure parameters
|
|
|
|
Return Value:
|
|
|
|
Standard dialog procedure return value
|
|
|
|
--*/
|
|
BOOL CALLBACK ChooseVersionDlgProc(IN HWND hwnd,
|
|
IN UINT uiMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
PTSTR tszComponentId = NULL;
|
|
INT iVersion = 0;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
CheckRadioButton(hwnd, IDC_LESS, IDC_GREATER, IDC_EQUAL);
|
|
tszComponentId = (PTSTR)lParam;
|
|
SetDlgItemText(hwnd, IDC_COMPONENT1, tszComponentId);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
|
|
//
|
|
// Retrieve the current selection
|
|
//
|
|
if (QueryButtonCheck(hwnd, IDC_LESS))
|
|
{
|
|
iVersion = -1;
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_EQUAL))
|
|
{
|
|
iVersion = 0;
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_GREATER))
|
|
{
|
|
iVersion = 1;
|
|
}
|
|
|
|
//
|
|
// Send the version chosen back to ChooseVersionEx
|
|
//
|
|
EndDialog(hwnd, iVersion);
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hwnd, 0);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
|
|
} // ChooseVersionDlgProc //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ChooseSubcomponentDlgProc (1.27)
|
|
|
|
Dialog procedure that allows the user to select a different
|
|
initial state for a component than the one found by the OC Manager
|
|
|
|
Arguments:
|
|
|
|
Standard dialog procedure parameters
|
|
|
|
Return Value:
|
|
|
|
Standard dialog procedure return value
|
|
|
|
--*/
|
|
BOOL CALLBACK ChooseSubcomponentDlgProc(IN HWND hwnd,
|
|
IN UINT uiMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
PTSTR tszComponentId = NULL;
|
|
SubComponentState scsInitialState;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
CheckRadioButton(hwnd, IDC_DEFAULT, IDC_OFF, IDC_DEFAULT);
|
|
tszComponentId = (PTSTR)lParam;
|
|
SetDlgItemText(hwnd, IDC_COMPONENT1, tszComponentId);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
|
|
//
|
|
// Retrieve the current selection
|
|
//
|
|
if (QueryButtonCheck(hwnd, IDC_DEFAULT))
|
|
{
|
|
scsInitialState = SubcompUseOcManagerDefault;
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_OFF))
|
|
{
|
|
scsInitialState = SubcompOff;
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_ON))
|
|
{
|
|
scsInitialState = SubcompOn;
|
|
}
|
|
|
|
EndDialog(hwnd, 0);
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hwnd, 0);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
|
|
} // ChooseSubcomponentDlgProc //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ChooseVersionEx (1.29)
|
|
|
|
"Wrapper" routine for the dialog box procedure ChooseVersionDlgProc.
|
|
Retrieves the value chosen by the user and sets the version field of
|
|
pInitComponent accordingly.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
pInitComponent: supplies the address of the initialization structure.
|
|
After return the "Version" field of that structure will
|
|
reflect the user's selection
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID ChooseVersionEx(IN LPCVOID lpcvComponentId,
|
|
IN OUT PSETUP_INIT_COMPONENT psicInitComponent)
|
|
{
|
|
INT iVersion = 0;
|
|
|
|
//
|
|
// We will display a dialog box so the user can choose the
|
|
// version he/she wants
|
|
//
|
|
iVersion = DialogBoxParam(g_hDllInstance,
|
|
MAKEINTRESOURCE(IDD_DIALOG2),
|
|
NULL,
|
|
ChooseVersionDlgProc,
|
|
(LPARAM)lpcvComponentId);
|
|
|
|
//
|
|
// We set the version choosen in a structure that will be sent
|
|
// back to the Oc Manager
|
|
//
|
|
psicInitComponent->ComponentVersion =
|
|
psicInitComponent->OCManagerVersion + iVersion;
|
|
|
|
return;
|
|
|
|
} // ChooseVersionEx //
|
|
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Test functions. The ocmanager will call these functions.
|
|
//
|
|
//==========================================================================
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ComponentSetupProc (1.6)
|
|
|
|
The DLL entry point. This function is called by the OC Manager whenever
|
|
it wants to send/recieve setup information to/from the component.
|
|
Note that the ComponentId and SubcomponentId are LPCVOID because we
|
|
don't know in advance if they are ANSI or Unicode.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiFunction: one of OC_XXX.
|
|
uiParam1: its meaning depends on the function.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
Depends on the function (e.g. TRUE/FALSE for the language supported,
|
|
the number of pages supplied by the component, etc.).
|
|
|
|
--*/
|
|
EXPORT DWORD ComponentSetupProc(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiFunction,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2)
|
|
{
|
|
double fn = 1.6;
|
|
|
|
DWORD dwRetval = NO_ERROR;
|
|
PTCHAR tszComponentId = (PTCHAR)lpcvComponentId;
|
|
PTCHAR tszSubcomponentId = (PTCHAR)lpcvSubcomponentId;
|
|
TCHAR tsz[MAX_MSG_LEN];
|
|
PCOMPONENT_DATA pcdComponentData = NULL;
|
|
TCHAR tszDlgMessage[256];
|
|
|
|
PTCHAR tszDummy = NULL;
|
|
|
|
ReturnOrAV raValue;
|
|
|
|
static BOOL bFirstTime = TRUE;
|
|
|
|
//
|
|
// Log the details about the call
|
|
//
|
|
LogOCFunction(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiFunction,
|
|
uiParam1,
|
|
pvParam2);
|
|
|
|
//if (uiFunction == g_uiFunctionToAV && uiFunction != OC_PREINITIALIZE && uiFunction != OC_INIT_COMPONENT) {
|
|
// testAV(TRUE);
|
|
//}
|
|
|
|
causeAVPerComponent(uiFunction, lpcvComponentId);
|
|
|
|
#ifndef UNICODE
|
|
//if (g_bAccessViolation && !g_uiFunctionToAV) {
|
|
// causeAV(uiFunction);
|
|
//}
|
|
#endif
|
|
|
|
//
|
|
// Check to see if valid component and subcomponent IDs were received
|
|
//
|
|
if (uiFunction > OC_INIT_COMPONENT && uiFunction < OCP_TEST_PRIVATE_BASE)
|
|
{
|
|
if (!FindSubcomponentInformationNode((PTCHAR)lpcvComponentId,
|
|
(PTCHAR)lpcvSubcomponentId))
|
|
{
|
|
Log(fn, SEV2, TEXT("ComponentSetupProc function received %s.%s. ")
|
|
TEXT("This is not a valid component.subcomponent."),
|
|
lpcvComponentId, lpcvSubcomponentId);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Whenever the user hits the next or back button, check all
|
|
// the needs dependencies, exclude dependencies,
|
|
// and parent child dependencies
|
|
//
|
|
if (uiFunction == OC_QUERY_SKIP_PAGE ||
|
|
uiFunction == OC_QUEUE_FILE_OPS ||
|
|
uiFunction == OC_ABOUT_TO_COMMIT_QUEUE ||
|
|
uiFunction == OC_COMPLETE_INSTALLATION)
|
|
{
|
|
//
|
|
// Check selection status of components to make sure all
|
|
// dependency relationships are being fulfilled.
|
|
//
|
|
CheckNeedsDependencies();
|
|
CheckExcludeDependencies();
|
|
CheckParentDependencies();
|
|
}
|
|
|
|
//
|
|
// Enable the use of private functions
|
|
//
|
|
g_bUsePrivateFunctions = TRUE;
|
|
|
|
if (g_bTestExtended || !bFirstTime){
|
|
|
|
bFirstTime = FALSE;
|
|
|
|
// Prepare to call TestReturnValueAndAV
|
|
raValue.tszComponent = NULL;
|
|
raValue.tszSubComponent = NULL;
|
|
raValue.bOverride = FALSE;
|
|
raValue.iReturnValue = 0;
|
|
|
|
TestReturnValueAndAV(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiFunction,
|
|
uiParam1,
|
|
pvParam2,
|
|
&raValue);
|
|
|
|
}
|
|
|
|
|
|
switch (uiFunction)
|
|
{
|
|
case OC_PREINITIALIZE:
|
|
//testAV(g_bAccessViolation);
|
|
#ifdef UNICODE
|
|
testAV(g_bCrashUnicode);
|
|
#endif
|
|
|
|
dwRetval = RunOcPreinitialize(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiParam1);
|
|
break;
|
|
|
|
case OC_INIT_COMPONENT:
|
|
__ASSERT(pvParam2 != NULL);
|
|
|
|
//
|
|
// Init the log, now that OC Manager knows whether we
|
|
// are ANSI or Unicode
|
|
//
|
|
_stprintf(tsz, TEXT("%s.log"), (PTCHAR)lpcvComponentId);
|
|
InitLog(tsz, TEXT("OCManager Test Log"), TRUE);
|
|
|
|
dwRetval = RunOcInitComponent(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
pvParam2);
|
|
#ifdef UNICODE
|
|
if (g_bCloseInf && hInfGlobal != NULL){
|
|
SetupCloseInfFile(pcdComponentData->hinfMyInfHandle);
|
|
}
|
|
#endif
|
|
|
|
// Let's read the INF file and decide the values of some global variables
|
|
|
|
if ((pcdComponentData = LocateComponent(lpcvComponentId)) &&
|
|
(pcdComponentData->hinfMyInfHandle != NULL) &&
|
|
!(pcdComponentData->dwlFlags & SETUPOP_BATCH))
|
|
{
|
|
SetGlobalsFromINF(pcdComponentData->hinfMyInfHandle);
|
|
}
|
|
|
|
//if (g_bNoWizPage) {
|
|
// Check is there is a default mode specified in [OCTest] section
|
|
SetDefaultMode(pcdComponentData);
|
|
//}
|
|
break;
|
|
|
|
case OC_QUERY_STATE:
|
|
dwRetval = RunOcQueryState(lpcvComponentId,
|
|
lpcvSubcomponentId);
|
|
if (dwRetval == SubcompOn) {
|
|
//MessageBox(NULL, TEXT("Let's turn it on"), TEXT("OC_QUERY_STATE"), MB_OK);
|
|
}
|
|
break;
|
|
|
|
case OC_SET_LANGUAGE:
|
|
dwRetval = RunOcSetLanguage(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiParam1);
|
|
if (g_bNoLangSupport) {
|
|
//MessageBox(NULL, TEXT("No Language Support"), TEXT("OC_SET_LANGUAGE"), MB_OK);
|
|
dwRetval = FALSE;
|
|
}
|
|
break;
|
|
|
|
case OC_QUERY_IMAGE:
|
|
if (g_bInvalidBitmap){
|
|
dwRetval = 1000;
|
|
}
|
|
else{
|
|
dwRetval = RunOcQueryImage(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
pvParam2);
|
|
}
|
|
break;
|
|
|
|
case OC_REQUEST_PAGES:
|
|
|
|
if (g_bNoWizPage){
|
|
dwRetval = 0;
|
|
}
|
|
else{
|
|
dwRetval = RunOcRequestPages(lpcvComponentId,
|
|
uiParam1,
|
|
pvParam2);
|
|
}
|
|
break;
|
|
|
|
case OC_QUERY_CHANGE_SEL_STATE:
|
|
dwRetval = RunOcQueryChangeSelState(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiParam1);
|
|
break;
|
|
|
|
case OC_CALC_DISK_SPACE:
|
|
dwRetval = RunOcCalcDiskSpace(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
uiParam1,
|
|
pvParam2);
|
|
break;
|
|
|
|
case OC_QUEUE_FILE_OPS:
|
|
dwRetval = RunOcQueueFileOps(lpcvComponentId,
|
|
lpcvSubcomponentId,
|
|
pvParam2);
|
|
break;
|
|
|
|
case OC_NEED_MEDIA:
|
|
//if (!g_bNoNeedMedia){
|
|
// dwRetval = RunOcNeedMedia(lpcvComponentId,
|
|
// uiParam1,
|
|
// pvParam2);
|
|
//}
|
|
//else{
|
|
dwRetval = NO_ERROR;
|
|
Log(fn, SEV2, TEXT("OC_NEED_MEDIA is passed in for %s.%s. ")
|
|
TEXT("This should not happen according to the spec."),
|
|
lpcvComponentId, lpcvSubcomponentId);
|
|
//MessageBox(NULL, TEXT("OC_NEED_MEDIA is passed to the DLL."), TEXT("OC_NEED_MEDIA"), MB_OK);
|
|
//}
|
|
break;
|
|
|
|
case OC_QUERY_STEP_COUNT:
|
|
dwRetval = RunOcQueryStepCount(lpcvComponentId);
|
|
break;
|
|
|
|
case OC_COMPLETE_INSTALLATION:
|
|
dwRetval = RunOcCompleteInstallation(lpcvComponentId,
|
|
lpcvSubcomponentId);
|
|
|
|
if (g_bReboot) {
|
|
if ((pcdComponentData = LocateComponent(lpcvComponentId)) &&
|
|
(pcdComponentData->hinfMyInfHandle != NULL) &&
|
|
!(pcdComponentData->dwlFlags & SETUPOP_BATCH))
|
|
{
|
|
//MessageBox(NULL, TEXT("A reboot is queued"), TEXT("Reboot"), MB_OK);
|
|
//OcHelperSetReboot(pcdComponentData->ocrHelperRoutines.OcManagerContext, NULL);
|
|
pcdComponentData->ocrHelperRoutines.SetReboot(pcdComponentData->ocrHelperRoutines.OcManagerContext,TRUE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OC_CLEANUP:
|
|
dwRetval = RunOcCleanup(lpcvComponentId);
|
|
break;
|
|
|
|
case OCP_TEST_PRIVATE_BASE:
|
|
dwRetval = RunTestOcPrivateBase(lpcvSubcomponentId,
|
|
uiParam1,
|
|
pvParam2);
|
|
break;
|
|
|
|
case OCP_CHECK_NEEDS:
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
dwRetval = CheckLocalNeedsDependencies(
|
|
pcdComponentData->ocrHelperRoutines,
|
|
(PSUBCOMP)uiParam1,
|
|
((PCHECK_NEEDS)pvParam2)->pclNeeds,
|
|
((PCHECK_NEEDS)pvParam2)->tszNodesVisited);
|
|
|
|
((PCHECK_NEEDS)pvParam2)->bResult = (BOOL)dwRetval;
|
|
dwRetval = (DWORD)pvParam2;
|
|
}
|
|
else
|
|
{
|
|
Log(fn, SEV2, TEXT("Could not get component data of %s"),
|
|
lpcvComponentId);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwRetval = (DWORD)FALSE;
|
|
}
|
|
|
|
if ((g_bTestExtended || !bFirstTime) && BeginTest() && raValue.bOverride){
|
|
return raValue.iReturnValue;
|
|
}
|
|
else {
|
|
return dwRetval;
|
|
}
|
|
|
|
} // ComponentSetupProc //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcPreinitialize (1.7)
|
|
|
|
Code to run if OC_PREINITIALIZE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiParam1: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcPreinitialize(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiParam1)
|
|
{
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
|
|
//
|
|
// If the test is not extended, the return value
|
|
// matches the native character width.
|
|
//
|
|
#ifdef UNICODE
|
|
dwComponentReturnValue = OCFLAG_UNICODE;
|
|
#else
|
|
dwComponentReturnValue = OCFLAG_ANSI;
|
|
#endif
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcPreinitialize //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcInitComponent (1.8)
|
|
|
|
Code to run if OC_INIT_COMPONENT is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcInitComponent(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN PVOID pvParam2)
|
|
{
|
|
double fn = 1.8;
|
|
|
|
PSETUP_INIT_COMPONENT psicInitComponent;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
|
|
TCHAR tszFunctionName[256];
|
|
BOOL bSuccess;
|
|
|
|
INFCONTEXT infContext;
|
|
|
|
int nRequiredBufferSize = 255;
|
|
|
|
TCHAR tszMsg[256];
|
|
|
|
psicInitComponent = (PSETUP_INIT_COMPONENT)pvParam2;
|
|
|
|
hInfGlobal = psicInitComponent->OCInfHandle;
|
|
|
|
|
|
if (pcdComponentData = AddNewComponent(lpcvComponentId))
|
|
{
|
|
//
|
|
// Save the INF file handle
|
|
//
|
|
pcdComponentData->hinfMyInfHandle =
|
|
(psicInitComponent->ComponentInfHandle == INVALID_HANDLE_VALUE)
|
|
? NULL : psicInitComponent->ComponentInfHandle;
|
|
|
|
if (pcdComponentData->hinfMyInfHandle)
|
|
{
|
|
SetupOpenAppendInfFile(NULL,
|
|
pcdComponentData->hinfMyInfHandle,
|
|
NULL);
|
|
}
|
|
|
|
CreateSubcomponentInformationList(pcdComponentData->hinfMyInfHandle);
|
|
|
|
_tcscpy(pcdComponentData->tszSourcePath,
|
|
psicInitComponent->SetupData.SourcePath);
|
|
|
|
_tcscpy(pcdComponentData->tszUnattendFile,
|
|
psicInitComponent->SetupData.UnattendFile);
|
|
|
|
pcdComponentData->ocrHelperRoutines =
|
|
psicInitComponent->HelperRoutines;
|
|
pcdComponentData->dwlFlags =
|
|
psicInitComponent->SetupData.OperationFlags;
|
|
dwComponentReturnValue = NO_ERROR;
|
|
|
|
//
|
|
// Initialize the "witness" file queue
|
|
//
|
|
if ((g_FileQueue = SetupOpenFileQueue()) == INVALID_HANDLE_VALUE)
|
|
{
|
|
Log(fn, SEV2, TEXT("Unable to create file queue"));
|
|
}
|
|
|
|
// Determine where to AV
|
|
bSuccess = SetupFindFirstLine(pcdComponentData->hinfMyInfHandle, TEXT("OCTest"), TEXT("AccessViolation"), &infContext);
|
|
|
|
if (bSuccess) {
|
|
pcdComponentData->bAccessViolation = TRUE;
|
|
bSuccess = SetupGetStringField(&infContext, 1, tszFunctionName, 255, &nRequiredBufferSize);
|
|
if (bSuccess) {
|
|
//_stprintf(tszMsg, TEXT("An access violation will be generated at %s of %s"), tszFunctionName, lpcvComponentId);
|
|
//MessageBox(NULL, tszMsg, TEXT("Access Violation"), MB_OK);
|
|
pcdComponentData->uiFunctionToAV = GetOCFunctionName(tszFunctionName);
|
|
}
|
|
}
|
|
else{
|
|
pcdComponentData->bAccessViolation = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (g_bTestExtended && (dwComponentReturnValue == NO_ERROR))
|
|
{
|
|
//
|
|
// Let the user decide if the component is
|
|
// compatible with the OC Manager
|
|
//
|
|
ChooseVersionEx(lpcvComponentId, psicInitComponent);
|
|
//ChooseAccessViolationEx();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We put the same component version to be sure that can go on
|
|
//
|
|
psicInitComponent->ComponentVersion =
|
|
psicInitComponent->OCManagerVersion;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcInitComponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcQueryState (1.9)
|
|
|
|
Code to run if OC_QUERY_STATE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcQueryState(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId)
|
|
{
|
|
PCOMPONENT_DATA pcdComponentData = NULL;
|
|
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
|
|
BOOL bSuccess;
|
|
|
|
TCHAR tszKeyName[256];
|
|
|
|
INFCONTEXT infContext;
|
|
|
|
int nRequiredSize;
|
|
|
|
TCHAR tszState[256];
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
if (!g_bTestExtended)
|
|
{
|
|
dwComponentReturnValue = SubcompUseOcManagerDefault;
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue =
|
|
ChooseSubcomponentInitialState(lpcvComponentId,
|
|
lpcvSubcomponentId);
|
|
}
|
|
|
|
_stprintf(tszKeyName, TEXT("%s.initState"),lpcvSubcomponentId);
|
|
|
|
//MessageBox(NULL, TEXT("Going to look for the key"), tszKeyName, MB_OK);
|
|
|
|
bSuccess = SetupFindFirstLine(pcdComponentData->hinfMyInfHandle,
|
|
TEXT("OCTest"),
|
|
tszKeyName,
|
|
&infContext);
|
|
|
|
if (bSuccess) {
|
|
//MessageBox(NULL, TEXT("Key Found"), tszKeyName, MB_OK);
|
|
bSuccess = SetupGetStringField(&infContext,
|
|
1,
|
|
tszState,
|
|
255,
|
|
&nRequiredSize);
|
|
if (bSuccess) {
|
|
//MessageBox(NULL, TEXT("String field fetched"), tszState, MB_OK);
|
|
if (_tcscmp(tszState, TEXT("On")) == 0) {
|
|
dwComponentReturnValue = SubcompOn;
|
|
}
|
|
else if (_tcscmp(tszState, TEXT("Off")) == 0) {
|
|
dwComponentReturnValue = SubcompOff;
|
|
}
|
|
else{
|
|
dwComponentReturnValue = SubcompUseOcManagerDefault;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = SubcompUseOcManagerDefault;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcQueryState //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcSetLanguage (1.11)
|
|
|
|
Code to run if OC_SET_LANGUAGE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiParam1: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcSetLanguage(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiParam1)
|
|
{
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
//
|
|
// If we won't support the language, the OC Manager won't
|
|
// continue, so we have to return TRUE
|
|
//
|
|
dwComponentReturnValue = (DWORD)TRUE;
|
|
pcdComponentData->LanguageId = (LANGID)uiParam1;
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = (DWORD)FALSE;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcSetLanguage //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcQueryImage (1.12)
|
|
|
|
Code to run if OC_QUERY_IMAGE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcQueryImage(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN PVOID pvParam2)
|
|
{
|
|
double fn = 1.12;
|
|
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
BOOL bAux;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
TCHAR tszResourceName[MAX_PATH];
|
|
INFCONTEXT infContext;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
|
|
#ifdef DEBUG
|
|
Log(fn, INFO, TEXT("Height = %d, Width = %d"),
|
|
HIWORD(pvParam2), LOWORD(pvParam2));
|
|
#endif
|
|
|
|
if ((pcdComponentData = LocateComponent(lpcvComponentId)) &&
|
|
(pcdComponentData->hinfMyInfHandle))
|
|
{
|
|
__ASSERT(LOWORD(uiParam1) == SubCompInfoSmallIcon);
|
|
|
|
_stprintf(tszMsg, TEXT("%s.%s"), lpcvComponentId, lpcvSubcomponentId);
|
|
|
|
if (SetupFindFirstLine(pcdComponentData->hinfMyInfHandle, tszMsg,
|
|
TEXT("Bitmap"), &infContext))
|
|
{
|
|
bAux = SetupGetStringField(&infContext, 1, tszResourceName,
|
|
sizeof(tszResourceName) /
|
|
sizeof(TCHAR), NULL);
|
|
|
|
if (bAux)
|
|
{
|
|
//
|
|
// Try to use Param1 and Param2 to resize the icon
|
|
//
|
|
dwComponentReturnValue = (DWORD)LoadBitmap(g_hDllInstance,
|
|
tszResourceName);
|
|
|
|
bAux = SetBitmapDimensionEx((HBITMAP)dwComponentReturnValue,
|
|
LOWORD(pvParam2),
|
|
HIWORD(pvParam2),
|
|
NULL);
|
|
#ifdef DEBUG
|
|
if (bAux)
|
|
{
|
|
Log(fn, PASS, TEXT("Success"));
|
|
}
|
|
else
|
|
{
|
|
_stprintf(tszMsg, TEXT("Can't resize %d"),
|
|
GetLastError());
|
|
Log(fn, PASS, tszMsg);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcQueryImage //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcRequestPages (1.13)
|
|
|
|
Code to run if OC_REQUEST_PAGES is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
uiParam1: its meaning depends on the function.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcRequestPages(IN LPCVOID lpcvComponentId,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2)
|
|
{
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
TCHAR tsz[256];
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
dwComponentReturnValue = DoPageRequest(
|
|
pcdComponentData->tszComponentId,
|
|
uiParam1,
|
|
(PSETUP_REQUEST_PAGES)pvParam2,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Some kind of error, 0 pages
|
|
//
|
|
dwComponentReturnValue = -1;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcRequestPages //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcQueryChangeSelState (1.14)
|
|
|
|
Code to run if OC_QUERY_CHANGE_SEL_STATE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiParam1: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcQueryChangeSelState(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiParam1)
|
|
{
|
|
DWORD dwComponentReturnValue = TRUE;
|
|
TCHAR tszText[MAX_MSG_LEN];
|
|
TCHAR tszSectionName[MAX_MSG_LEN];
|
|
INFCONTEXT infContext;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
if ((pcdComponentData = LocateComponent(lpcvComponentId)) &&
|
|
(pcdComponentData->hinfMyInfHandle != NULL) &&
|
|
!(pcdComponentData->dwlFlags & SETUPOP_BATCH))
|
|
{
|
|
//
|
|
// Check to see if this component should refuse to enable or
|
|
// disable. The component should refuse if there is a field
|
|
// called "RefuseSelect" or "RefuseDeselect" in the INF file.
|
|
//
|
|
if (lpcvSubcomponentId == NULL ||
|
|
_tcscmp((PTCHAR)lpcvSubcomponentId, TEXT("(null)")) == 0 ||
|
|
((PTCHAR)lpcvSubcomponentId)[0] == TEXT('\0'))
|
|
{
|
|
_stprintf(tszSectionName, (PTCHAR)lpcvComponentId);
|
|
}
|
|
else
|
|
{
|
|
_stprintf(tszSectionName, (PTCHAR)lpcvSubcomponentId);
|
|
}
|
|
|
|
if (SetupFindFirstLine(
|
|
pcdComponentData->hinfMyInfHandle,
|
|
tszSectionName,
|
|
uiParam1 ? TEXT("RefuseSelect") : TEXT("RefuseDeselect"),
|
|
&infContext))
|
|
{
|
|
dwComponentReturnValue = FALSE;
|
|
}
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = FALSE;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcQueryChangerSelState //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcCalcDiskSpace (1.15)
|
|
|
|
Code to run if OC_CALC_DISK_SPACE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiParam1: its meaning depends on the function.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcCalcDiskSpace(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2)
|
|
{
|
|
DWORD dwComponentReturnValue = TRUE;
|
|
BOOL bAux, bRetval;
|
|
TCHAR tszSectionName[MAX_PATH];
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
INFCONTEXT infContext;
|
|
|
|
if ((pcdComponentData = LocateComponent(lpcvComponentId)) &&
|
|
(pcdComponentData->hinfMyInfHandle))
|
|
{
|
|
//
|
|
// Check to see if the file to be copied in this section is called
|
|
// "hugefile.txt" If it is, don't add the real size of this file.
|
|
// Instead, add a gigantic file size so large that there won't
|
|
// be enough disk space to complete the operation.
|
|
//
|
|
_stprintf(tszMsg, TEXT("%s.%s.copyfiles"),
|
|
lpcvComponentId, lpcvSubcomponentId);
|
|
|
|
bAux = SetupFindFirstLine(pcdComponentData->hinfMyInfHandle,
|
|
tszSectionName,
|
|
TEXT("hugefile.txt"),
|
|
&infContext);
|
|
|
|
bAux = bAux && g_bHugeSize;
|
|
|
|
if (bAux)
|
|
{
|
|
//
|
|
// hugefile.txt is present.
|
|
//
|
|
if (uiParam1)
|
|
{
|
|
//
|
|
// Add gigantic file size
|
|
//
|
|
bRetval = SetupAddToDiskSpaceList((HDSKSPC)pvParam2,
|
|
TEXT("c:\\file.big"),
|
|
ONE_HUNDRED_GIG,
|
|
FILEOP_COPY,
|
|
0, 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remove a gigantic file size
|
|
//
|
|
bRetval = SetupAddToDiskSpaceList((HDSKSPC)pvParam2,
|
|
TEXT("c:\\file.big"),
|
|
ONE_HUNDRED_GIG,
|
|
FILEOP_COPY,
|
|
0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the section name
|
|
//
|
|
_stprintf(tszMsg, TEXT("%s.%s"), lpcvComponentId, lpcvSubcomponentId);
|
|
|
|
if (uiParam1)
|
|
{
|
|
//
|
|
// Adding
|
|
//
|
|
bRetval = SetupAddInstallSectionToDiskSpaceList(
|
|
(HDSKSPC)pvParam2,
|
|
pcdComponentData->hinfMyInfHandle,
|
|
NULL, tszMsg, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Removing
|
|
//
|
|
bRetval = SetupRemoveInstallSectionFromDiskSpaceList(
|
|
(HDSKSPC)pvParam2,
|
|
pcdComponentData->hinfMyInfHandle,
|
|
NULL, tszMsg, 0, 0);
|
|
}
|
|
}
|
|
|
|
dwComponentReturnValue = bRetval ? NO_ERROR : GetLastError();
|
|
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcCalcDiskSpace //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcQueueFileOps (1.16)
|
|
|
|
Code to run if OC_QUEUE_FILE_OPS is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcQueueFileOps(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN PVOID pvParam2)
|
|
{
|
|
double fn = 1.16;
|
|
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
BOOL bAux;
|
|
BOOL bCurrentState, bOriginalState;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
TCHAR tszSectionName[MAX_PATH];
|
|
INFCONTEXT infContext;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
PSUBCOMP pscTemp;
|
|
|
|
//
|
|
// Check to make sure this subcomponent is allowed to do work.
|
|
// If the subcomponent is not a bottom leaf on the subcomponent
|
|
// tree, it is not allowed to do any work. So we will check to
|
|
// see if it has any children.
|
|
//
|
|
for (pscTemp = g_pscHead; pscTemp != NULL; pscTemp = pscTemp->Next)
|
|
{
|
|
if (lpcvSubcomponentId && _tcscmp(pscTemp->tszSubcomponentId,
|
|
(PTCHAR)lpcvSubcomponentId) == 0)
|
|
{
|
|
if (pscTemp->pclChildren)
|
|
{
|
|
//
|
|
// This subcomponent has children. OcManager should not be
|
|
// try to queue file ops for this subcomponent. This is
|
|
// a failure.
|
|
//
|
|
Log(fn, SEV2, TEXT("OC Manager is trying to queue file ops ")
|
|
TEXT("for subcomponent %s of component %s. ")
|
|
TEXT("This subcomponent has children and ")
|
|
TEXT("should not be allowed to do any work."),
|
|
lpcvSubcomponentId, lpcvComponentId);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpcvSubcomponentId &&
|
|
(pcdComponentData = LocateComponent(lpcvComponentId)))
|
|
{
|
|
//
|
|
// Get original and current state. If the state didn't change,
|
|
// nothing to do.
|
|
//
|
|
bOriginalState =
|
|
pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
lpcvSubcomponentId,
|
|
OCSELSTATETYPE_ORIGINAL);
|
|
|
|
bCurrentState =
|
|
pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
lpcvSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT);
|
|
|
|
_stprintf(tszSectionName, TEXT("%s.%s"),
|
|
lpcvComponentId, lpcvSubcomponentId);
|
|
|
|
bAux = TRUE;
|
|
|
|
if (!bCurrentState)
|
|
{
|
|
//
|
|
// Being uninstalled. Fetch uninstall section name.
|
|
//
|
|
bAux = SetupFindFirstLine(pcdComponentData->hinfMyInfHandle,
|
|
tszSectionName,
|
|
TEXT("Uninstall"),
|
|
&infContext);
|
|
|
|
if (bAux)
|
|
{
|
|
bAux = SetupGetStringField(&infContext, 1, tszSectionName,
|
|
sizeof(tszSectionName) /
|
|
sizeof(TCHAR), NULL);
|
|
}
|
|
}
|
|
|
|
if (bAux)
|
|
{
|
|
bAux = SetupInstallFilesFromInfSection(
|
|
pcdComponentData->hinfMyInfHandle,
|
|
NULL,
|
|
pvParam2,
|
|
tszSectionName,
|
|
pcdComponentData->tszSourcePath,
|
|
bCurrentState ? SP_COPY_NEWER : 0);
|
|
|
|
SetupInstallFilesFromInfSection(
|
|
pcdComponentData->hinfMyInfHandle,
|
|
NULL,
|
|
g_FileQueue,
|
|
tszSectionName,
|
|
pcdComponentData->tszSourcePath,
|
|
bCurrentState ? SP_COPY_NEWER : 0);
|
|
|
|
dwComponentReturnValue = bAux ? NO_ERROR : GetLastError();
|
|
}
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcQueueFileOps //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcNeedMedia (1.17)
|
|
|
|
Code to run if OC_NEED_MEDIA is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
uiParam1: its meaning depends on the function.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcNeedMedia(IN LPCVOID lpcvComponentId,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2)
|
|
{
|
|
PVOID pvQueueContext;
|
|
DWORD dwComponentReturnValue;
|
|
|
|
//
|
|
// Nothing special to do if media is needed
|
|
// Call the default queue routine
|
|
//
|
|
pvQueueContext = SetupInitDefaultQueueCallback(NULL);
|
|
dwComponentReturnValue = SetupDefaultQueueCallback(pvQueueContext,
|
|
SPFILENOTIFY_NEEDMEDIA,
|
|
uiParam1,
|
|
(UINT)pvParam2);
|
|
|
|
SetupTermDefaultQueueCallback(pvQueueContext);
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcNeedMedia //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcQueryStepCount (1.18)
|
|
|
|
Code to run if OC_QUERY_STEP_COUNT is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcQueryStepCount(IN LPCVOID lpcvComponentId)
|
|
{
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
|
|
return NO_STEPS_FINAL;
|
|
|
|
} // RunOcQueryStepCount //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcCompleteInstallation (1.19)
|
|
|
|
Code to run if OC_COMPLETE_INSTALLATION is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcCompleteInstallation(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId)
|
|
{
|
|
double fn = 1.19;
|
|
|
|
DWORD dwComponentReturnValue = NO_ERROR;
|
|
DWORD dwResult;
|
|
INT iCount;
|
|
BOOL bAux;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
PVOID pvCallbackContext;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
//
|
|
// Output the name of the component that is currently working
|
|
//
|
|
_stprintf(tszMsg, TEXT("OC_COMPLETE_INSTALLATION: Copying files for %s\n"), lpcvSubcomponentId);
|
|
OutputDebugString(tszMsg);
|
|
|
|
if (pcdComponentData = LocateComponent(lpcvComponentId))
|
|
{
|
|
//
|
|
// We perform the check for the top-level component
|
|
// We will scan the witness queue
|
|
//
|
|
pvCallbackContext = SetupInitDefaultQueueCallback(NULL);
|
|
|
|
bAux = SetupScanFileQueue(g_FileQueue,
|
|
SPQ_SCAN_FILE_PRESENCE,
|
|
NULL,
|
|
SetupDefaultQueueCallback,
|
|
pvCallbackContext,
|
|
&dwResult);
|
|
|
|
SetupTermDefaultQueueCallback(pvCallbackContext);
|
|
|
|
if (!dwResult)
|
|
{
|
|
Log(fn, SEV2, TEXT("Not all the files are on the target!"));
|
|
}
|
|
|
|
//
|
|
// Check the helper routines
|
|
//
|
|
for (iCount = 0; iCount < nStepsFinal; iCount++)
|
|
{
|
|
//
|
|
// From time to time (every 3 "ticks") change the progress text
|
|
//
|
|
pcdComponentData->ocrHelperRoutines.TickGauge(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext);
|
|
|
|
if (iCount % 3 == 1)
|
|
{
|
|
_stprintf(tszMsg, TEXT("%s Progress Text Changed Step %d "),
|
|
lpcvSubcomponentId, iCount);
|
|
|
|
pcdComponentData->ocrHelperRoutines.SetProgressText(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
tszMsg);
|
|
}
|
|
|
|
Sleep(10 * TICK_TIME);
|
|
}
|
|
|
|
//
|
|
// Test the helper routines
|
|
//
|
|
TestHelperRoutines(lpcvComponentId,
|
|
pcdComponentData->ocrHelperRoutines);
|
|
}
|
|
else
|
|
{
|
|
dwComponentReturnValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // RunOcCompleteInstallation //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunOcCleanup (1.21)
|
|
|
|
Code to run if OC_CLEANUP is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunOcCleanup(IN LPCVOID lpcvComponentId)
|
|
{
|
|
UINT uiCount;
|
|
|
|
RemoveComponent(lpcvComponentId);
|
|
|
|
g_bFirstTime = TRUE;
|
|
|
|
//
|
|
// Close the witness file queue
|
|
//
|
|
SetupCloseFileQueue(g_FileQueue);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // RunOcCleanup //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RunTestOcPrivateBase (1.22)
|
|
|
|
Code to run if OCP_TEST_PRIVATE_BASE is called.
|
|
|
|
Arguments:
|
|
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
uiParam1: its meaning depends on the function.
|
|
pvParam2: its meaning depends on the function.
|
|
|
|
Return Value:
|
|
|
|
DWORD: returns error status
|
|
|
|
--*/
|
|
DWORD RunTestOcPrivateBase(IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2)
|
|
{
|
|
//
|
|
// Will send back the value in Param1.
|
|
// But first, assert that the subcomponent is NULL,
|
|
// as well as the Param2
|
|
//
|
|
__ASSERT((lpcvSubcomponentId == NULL) && (pvParam2 == NULL));
|
|
|
|
return uiParam1;
|
|
|
|
} // RunTestOcPrivateBase //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: TestHelperRoutines (1.5)
|
|
|
|
Tests the helper routines, using the functions above.
|
|
|
|
Arguments:
|
|
|
|
OCManagerRoutines: the helper routines.
|
|
|
|
Return Value:
|
|
|
|
DWORD: error return
|
|
|
|
--*/
|
|
DWORD TestHelperRoutines(IN LPCVOID lpcvComponentId,
|
|
IN OCMANAGER_ROUTINES OCManagerRoutines)
|
|
{
|
|
double fn = 1.5;
|
|
|
|
DWORD dwPreviousMode, dwSetPreviousMode, dwSetupMode, dwRandomSetupMode;
|
|
DWORD dwComponentReturnValue;
|
|
DWORD dwError;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
BOOL bQueryReturn;
|
|
|
|
//
|
|
// Test TickGauge - the call is ignored except when the component
|
|
// is allowed to perform its own (final) setup and informs the OC Manager
|
|
// about the number of steps this setup will require.
|
|
// For each such step, the OC Manager ticks the gauge once.
|
|
//
|
|
OCManagerRoutines.TickGauge(OCManagerRoutines.OcManagerContext);
|
|
|
|
//
|
|
// Test SetProgressText - the call is ignored except the final stage
|
|
// (the text above the tick gauge is set this way)
|
|
//
|
|
OCManagerRoutines.SetProgressText(OCManagerRoutines.OcManagerContext,
|
|
TEXT("Progress text"));
|
|
|
|
//
|
|
// Test Get/SetPrivateData
|
|
//
|
|
TestPrivateData(OCManagerRoutines);
|
|
|
|
//
|
|
// Test Get/SetSetupMode
|
|
//
|
|
|
|
//
|
|
// Get the original mode first
|
|
//
|
|
dwPreviousMode = OCManagerRoutines.GetSetupMode(
|
|
OCManagerRoutines.OcManagerContext);
|
|
|
|
dwRandomSetupMode = (DWORD)rand();
|
|
|
|
//
|
|
// The return value should be the previous mode
|
|
//
|
|
dwSetPreviousMode = OCManagerRoutines.SetSetupMode(
|
|
OCManagerRoutines.OcManagerContext,
|
|
dwRandomSetupMode);
|
|
|
|
if (dwPreviousMode != dwSetPreviousMode)
|
|
{
|
|
Log(fn, SEV2, TEXT("SetSetupMode failed. Return value is not equal ")
|
|
TEXT("to previous mode: Previous = %lu Return = %lu ")
|
|
TEXT("New Mode = %lu"),
|
|
dwPreviousMode, dwSetPreviousMode, dwRandomSetupMode);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the mode again
|
|
// The first 24 bits are private data, the last 8 are the mode
|
|
//
|
|
dwSetupMode = ((DWORD)rand()) << 8;
|
|
|
|
//
|
|
// So, get the last 8 bits from PreviousMode
|
|
//
|
|
dwSetupMode |= (dwPreviousMode & 0xFF);
|
|
dwSetPreviousMode = OCManagerRoutines.SetSetupMode(
|
|
OCManagerRoutines.OcManagerContext,
|
|
dwSetupMode);
|
|
|
|
if (dwRandomSetupMode != dwSetPreviousMode)
|
|
{
|
|
Log(fn, SEV2, TEXT("SetSetupMode failed. Return value is not ")
|
|
TEXT("equal to previous mode: Previous = %lu ")
|
|
TEXT("Return = %lu New Mode = %lu"),
|
|
dwRandomSetupMode, dwSetPreviousMode, dwSetupMode);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Leave the mode back at its original state
|
|
//
|
|
dwSetPreviousMode = OCManagerRoutines.SetSetupMode(
|
|
OCManagerRoutines.OcManagerContext,
|
|
dwPreviousMode);
|
|
|
|
//
|
|
// Test QuerySelectionState
|
|
//
|
|
|
|
//
|
|
// Perform negative testing first : use an inexistent component name
|
|
// Expect to get ERROR_INVALID_NAME
|
|
//
|
|
bQueryReturn = OCManagerRoutines.QuerySelectionState(
|
|
OCManagerRoutines.OcManagerContext,
|
|
TEXT("Phony component"),
|
|
OCSELSTATETYPE_ORIGINAL);
|
|
|
|
if ((bQueryReturn == FALSE) &&
|
|
((dwError = GetLastError()) != ERROR_INVALID_NAME ))
|
|
{
|
|
Log(fn, SEV2, TEXT("QuerySelectionState returned error %lu ")
|
|
TEXT("when called with phony name"), dwError);
|
|
}
|
|
|
|
bQueryReturn = OCManagerRoutines.QuerySelectionState(
|
|
OCManagerRoutines.OcManagerContext,
|
|
TEXT("Phony component"),
|
|
OCSELSTATETYPE_CURRENT);
|
|
|
|
if ((bQueryReturn == FALSE) &&
|
|
((dwError = GetLastError()) != ERROR_INVALID_NAME ))
|
|
{
|
|
Log(fn, SEV2, TEXT("QuerySelectionState returned error %lu ")
|
|
TEXT("when called with phony name"), dwError);
|
|
}
|
|
|
|
SetLastError(NO_ERROR);
|
|
|
|
//
|
|
// Tests the private function calls
|
|
// Save the return value first : this is done because another
|
|
// component is called and the return value is modified
|
|
//
|
|
dwComponentReturnValue = TestPrivateFunction(lpcvComponentId,
|
|
OCManagerRoutines);
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // TestHelperRountines //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: TestPrivateFunction (1.4)
|
|
|
|
Tests the private function calls
|
|
(these are used for inter-component communication)
|
|
|
|
Arguments:
|
|
|
|
OCManagerRoutines: the helper routines (CallPrivateFunction is a member
|
|
of this structure)
|
|
|
|
Return Value:
|
|
|
|
DWORD: error value
|
|
|
|
--*/
|
|
DWORD TestPrivateFunction(IN LPCVOID lpcvComponentId,
|
|
IN OCMANAGER_ROUTINES OCManagerRoutines)
|
|
{
|
|
double fn = 1.4;
|
|
|
|
DWORD dwComponentReturnValue = ERROR_SUCCESS;
|
|
UINT uiRemoteResult = 0;
|
|
UINT uiLocalResult = 0;
|
|
UINT uiRandomValue = 0;
|
|
BOOL bBlank = FALSE;
|
|
BOOL bOtherComponent = FALSE;
|
|
TCHAR tszComponent[MAX_PATH];
|
|
TCHAR tszOtherComponent[MAX_PATH];
|
|
TCHAR tszStandalone[MAX_PATH];
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
TCHAR tszSubComp[] = TEXT("");
|
|
PSUBCOMP pscTemp;
|
|
|
|
//
|
|
// Copy the current component
|
|
//
|
|
_tcscpy(tszComponent, (PTCHAR)lpcvComponentId);
|
|
|
|
//
|
|
// Find another component, if one exists
|
|
//
|
|
for (pscTemp = g_pscHead; pscTemp != NULL; pscTemp = pscTemp->Next)
|
|
{
|
|
if (_tcscmp(tszComponent, pscTemp->tszComponentId) != 0)
|
|
{
|
|
bOtherComponent = TRUE;
|
|
_tcscpy(tszOtherComponent, pscTemp->tszComponentId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 1. Call the same component
|
|
//
|
|
uiLocalResult = OCManagerRoutines.CallPrivateFunction(
|
|
OCManagerRoutines.OcManagerContext,
|
|
tszComponent,
|
|
tszSubComp,
|
|
OCP_TEST_PRIVATE_BASE,
|
|
0, 0, &uiRemoteResult);
|
|
|
|
if (uiLocalResult != ERROR_BAD_ENVIRONMENT)
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: expected ")
|
|
TEXT("ERROR_BAD_ENVIRONMENT, received %lu"),
|
|
uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
//
|
|
// 2. Call a non-existing component
|
|
//
|
|
uiLocalResult = OCManagerRoutines.CallPrivateFunction(
|
|
OCManagerRoutines.OcManagerContext,
|
|
TEXT("No component"),
|
|
tszSubComp,
|
|
OCP_TEST_PRIVATE_BASE,
|
|
0, 0, &uiRemoteResult);
|
|
|
|
if (uiLocalResult != ERROR_INVALID_FUNCTION)
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: expected ")
|
|
TEXT("ERROR_INVALID_FUNCTION, received %lu"),
|
|
uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
//
|
|
// 3. Call the standalone component
|
|
//
|
|
uiLocalResult = OCManagerRoutines.CallPrivateFunction(
|
|
OCManagerRoutines.OcManagerContext,
|
|
tszStandalone,
|
|
tszSubComp,
|
|
OCP_TEST_PRIVATE_BASE,
|
|
0, 0, &uiRemoteResult);
|
|
|
|
if (uiLocalResult != ERROR_INVALID_FUNCTION)
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: expected ")
|
|
TEXT("ERROR_INVALID_FUNCTION, received %lu"),
|
|
uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
if (bOtherComponent)
|
|
{
|
|
//
|
|
// 4. Call the other component with OC_PRIVATE_BASE - 1
|
|
//
|
|
uiLocalResult = OCManagerRoutines.CallPrivateFunction(
|
|
OCManagerRoutines.OcManagerContext,
|
|
tszOtherComponent,
|
|
tszSubComp,
|
|
OC_PRIVATE_BASE - 1,
|
|
0, 0, &uiRemoteResult);
|
|
|
|
if (uiLocalResult != ERROR_INVALID_FUNCTION)
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: expected ")
|
|
TEXT("ERROR_INVALID_FUNCTION, received %lu"),
|
|
uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
//
|
|
// 5. A normal call : we will supply a random number and will expect
|
|
// to receive as a result the same value. This is true if the
|
|
// private calls are allowed
|
|
//
|
|
uiRandomValue = (UINT)(rand() + 1);
|
|
|
|
//
|
|
// To be sure the two values are not equal
|
|
//
|
|
uiRemoteResult = 0;
|
|
uiLocalResult = OCManagerRoutines.CallPrivateFunction(
|
|
OCManagerRoutines.OcManagerContext,
|
|
tszOtherComponent,
|
|
tszSubComp,
|
|
OCP_TEST_PRIVATE_BASE,
|
|
uiRandomValue,
|
|
0,
|
|
&uiRemoteResult);
|
|
|
|
if (uiLocalResult != ERROR_ACCESS_DENIED)
|
|
{
|
|
if (g_bUsePrivateFunctions && (uiLocalResult != NO_ERROR))
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction called on %s for ")
|
|
TEXT("OCP_TEST_PRIVATE_BASE returned %lu"),
|
|
tszOtherComponent, uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
if (!g_bUsePrivateFunctions &&
|
|
(uiLocalResult != ERROR_BAD_ENVIRONMENT))
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: expected ")
|
|
TEXT("ERROR_BAD_ENVIRONMENT, received %lu"),
|
|
uiLocalResult);
|
|
bBlank = TRUE;
|
|
}
|
|
|
|
if (g_bUsePrivateFunctions && (uiRemoteResult != uiRandomValue))
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction: received invalid data ")
|
|
TEXT("from routine. Expected %lu, received %lu"),
|
|
uiRandomValue, uiRemoteResult);
|
|
bBlank = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bBlank) LogBlankLine();
|
|
|
|
return dwComponentReturnValue;
|
|
|
|
} // TestPrivateFunction //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: TestPrivateData (1.3)
|
|
|
|
Checks all the OC Manager values against the local ones,
|
|
then it randomly changes one value.
|
|
|
|
Arguments:
|
|
|
|
OCManagerRoutines: the helper routines (Get/SetPrivateData are members
|
|
of this structure)
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID TestPrivateData(IN OCMANAGER_ROUTINES OCManagerRoutines)
|
|
{
|
|
double fn = 1.3;
|
|
|
|
PVOID pvBuffer;
|
|
UINT uiCount, uiRandomValue;
|
|
BOOL bResult;
|
|
|
|
PRIVATE_DATA aPrivateDataTable[] =
|
|
{
|
|
{TEXT("Binary value"), REG_BINARY, 0, NULL, NULL},
|
|
{TEXT("Binary value 2"), REG_BINARY, 0, NULL, NULL},
|
|
{TEXT("String value"), REG_SZ, 0, NULL, NULL},
|
|
{TEXT("String value 2"), REG_SZ, 0, NULL, NULL},
|
|
{TEXT("Multi String value"), REG_MULTI_SZ, 0, NULL, NULL},
|
|
{TEXT("Multi String value 2"), REG_MULTI_SZ, 0, NULL, NULL},
|
|
{TEXT("DWORD value"), REG_DWORD, 0, NULL, NULL},
|
|
{TEXT("DWORD value 2"), REG_DWORD, 0, NULL, NULL}
|
|
};
|
|
|
|
//
|
|
// Set all the values
|
|
//
|
|
for (uiCount = 0; uiCount < MAX_PRIVATE_VALUES; uiCount++)
|
|
{
|
|
bResult = SetAValue(OCManagerRoutines, uiCount, aPrivateDataTable);
|
|
}
|
|
|
|
//
|
|
// Check all the values against the local table
|
|
//
|
|
CheckPrivateValues(OCManagerRoutines, aPrivateDataTable);
|
|
|
|
free(aPrivateDataTable[0].pvBuffer);
|
|
free(aPrivateDataTable[1].pvBuffer);
|
|
free(aPrivateDataTable[2].pvBuffer);
|
|
free(aPrivateDataTable[3].pvBuffer);
|
|
free(aPrivateDataTable[4].pbBuffer);
|
|
free(aPrivateDataTable[5].pbBuffer);
|
|
free(aPrivateDataTable[6].pvBuffer);
|
|
free(aPrivateDataTable[7].pvBuffer);
|
|
|
|
return;
|
|
|
|
} // TestPrivateData //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckPrivateValues (1.2)
|
|
|
|
Checks the values of the private data stored by the OC Manager against
|
|
those stored internally by the application.
|
|
|
|
Arguments:
|
|
|
|
OCManagerRoutines: the helper routines (GetPrivateData is a member of
|
|
this structure)
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CheckPrivateValues(IN OCMANAGER_ROUTINES OCManagerRoutines,
|
|
IN PRIVATE_DATA *aPrivateDataTable)
|
|
{
|
|
double fn = 1.2;
|
|
|
|
UINT uiCount, uiSize, uiType;
|
|
DWORD dwErrorCode;
|
|
PVOID pvBuffer = NULL;
|
|
PTCHAR tszBuffer;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
TCHAR tszError[MAX_ERROR_LEN];
|
|
|
|
for (uiCount = 0; uiCount < MAX_PRIVATE_VALUES; uiCount++)
|
|
{
|
|
//
|
|
// First call is used only to get the size of the data
|
|
// Only the second one will actually retrieve it
|
|
//
|
|
dwErrorCode = OCManagerRoutines.GetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
NULL,
|
|
aPrivateDataTable[uiCount].tszName,
|
|
NULL,
|
|
&uiSize,
|
|
&uiType);
|
|
|
|
if (dwErrorCode != NO_ERROR)
|
|
{
|
|
Log(fn, SEV2, TEXT("GetPrivateData failed for %s: %s"),
|
|
aPrivateDataTable[uiCount].tszName,
|
|
ErrorMsg(dwErrorCode, tszError));
|
|
continue;
|
|
}
|
|
|
|
|
|
if (pvBuffer) __Free(&pvBuffer);
|
|
__Malloc(&pvBuffer, uiSize);
|
|
|
|
dwErrorCode = OCManagerRoutines.GetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
NULL,
|
|
aPrivateDataTable[uiCount].tszName,
|
|
pvBuffer,
|
|
&uiSize,
|
|
&uiType);
|
|
|
|
if (dwErrorCode != NO_ERROR)
|
|
{
|
|
Log(fn, SEV2, TEXT("GetPrivateData failed for %s: %s"),
|
|
aPrivateDataTable[uiCount].tszName,
|
|
ErrorMsg(dwErrorCode, tszError));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Now perform the actual checking
|
|
// The type first
|
|
//
|
|
if (uiType != aPrivateDataTable[uiCount].uiType)
|
|
{
|
|
Log(fn, SEV2, TEXT("GetPrivateData: Retrieved type %d ")
|
|
TEXT("instead of %d"),
|
|
uiType, aPrivateDataTable[uiCount].uiType);
|
|
}
|
|
|
|
//
|
|
// Then the size
|
|
//
|
|
if (uiSize != aPrivateDataTable[uiCount].uiSize)
|
|
{
|
|
if (uiType == REG_SZ)
|
|
{
|
|
tszBuffer = (PTCHAR)pvBuffer;
|
|
_stprintf(tszMsg, TEXT("GetPrivateData: Size retrieved %d ")
|
|
TEXT("expected %d, ")
|
|
TEXT("pvBuffer = %s, known buffer = %s, ")
|
|
TEXT("Chars %u %u %u %u"),
|
|
uiSize,
|
|
aPrivateDataTable[uiCount].uiSize,
|
|
tszBuffer,
|
|
aPrivateDataTable[uiCount].pvBuffer,
|
|
tszBuffer[uiSize - 4],
|
|
tszBuffer[uiSize - 3],
|
|
tszBuffer[uiSize - 2],
|
|
tszBuffer[uiSize - 1]);
|
|
}
|
|
else
|
|
{
|
|
if (uiType == REG_MULTI_SZ)
|
|
{
|
|
TCHAR tszAux[MAX_MSG_LEN];
|
|
|
|
_stprintf(tszMsg, TEXT("MULTI_SZ Size retrieved %d, ")
|
|
TEXT("expected %d, pvBuffer = "),
|
|
uiSize, aPrivateDataTable[uiCount].uiSize);
|
|
tszBuffer = (PTCHAR)pvBuffer;
|
|
MultiStringToString(tszBuffer, tszAux);
|
|
_tcscat(tszMsg, tszAux);
|
|
|
|
_tcscat(tszMsg, TEXT(" and known buffer = "));
|
|
|
|
tszBuffer = (PTCHAR)aPrivateDataTable[uiCount].pvBuffer;
|
|
MultiStringToString(tszBuffer, tszAux);
|
|
_tcscat(tszMsg, tszAux);
|
|
}
|
|
else
|
|
{
|
|
_stprintf(tszMsg, TEXT("Size retrieved %d instead %d"),
|
|
uiSize, aPrivateDataTable[uiCount].uiSize);
|
|
}
|
|
}
|
|
|
|
Log(fn, SEV2, tszMsg);
|
|
}
|
|
|
|
if (uiType == REG_BINARY)
|
|
{
|
|
if (memcmp(pvBuffer,
|
|
aPrivateDataTable[uiCount].pbBuffer,
|
|
aPrivateDataTable[uiCount].uiSize))
|
|
{
|
|
Log(fn, SEV2, TEXT("Private data %s, Received %s expected %s"),
|
|
aPrivateDataTable[uiCount].tszName,
|
|
(PTSTR)pvBuffer,
|
|
(PTSTR)aPrivateDataTable[uiCount].pbBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (memcmp(pvBuffer,
|
|
aPrivateDataTable[uiCount].pvBuffer,
|
|
aPrivateDataTable[uiCount].uiSize))
|
|
{
|
|
Log(fn, SEV2, TEXT("Private data %s, Received %s expected %s"),
|
|
aPrivateDataTable[uiCount].tszName,
|
|
(PTSTR)pvBuffer,
|
|
(PTSTR)aPrivateDataTable[uiCount].pvBuffer);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to use a smaller buffer - should get an error code
|
|
//
|
|
uiSize--;
|
|
dwErrorCode = OCManagerRoutines.GetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
NULL,
|
|
aPrivateDataTable[uiCount].tszName,
|
|
pvBuffer,
|
|
&uiSize,
|
|
&uiType);
|
|
|
|
if (dwErrorCode != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
Log(fn, SEV2, TEXT("GetPrivateData returned %s when called ")
|
|
TEXT("with small buffer size for %s"),
|
|
ErrorMsg(dwErrorCode, tszError),
|
|
aPrivateDataTable[uiCount].tszName);
|
|
continue;
|
|
}
|
|
__Free(&pvBuffer);
|
|
}
|
|
|
|
if (pvBuffer) __Free(&pvBuffer);
|
|
|
|
} // CheckPrivateValues //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: SetAValue (1.1)
|
|
|
|
Sets the value of a variable from the private data. The variable
|
|
that will be changed is randomly selected.
|
|
|
|
Arguments:
|
|
|
|
OCManagerRoutines: the helper routines (SetPrivateData is a member
|
|
of this structure)
|
|
|
|
uiIndex: the index of the variable to change
|
|
|
|
Return Value:
|
|
|
|
BOOL: TRUE if value is set, FALSE if not
|
|
|
|
--*/
|
|
BOOL SetAValue(IN OCMANAGER_ROUTINES OCManagerRoutines,
|
|
IN UINT uiIndex,
|
|
IN OUT PRIVATE_DATA *aPrivateDataTable)
|
|
{
|
|
double fn = 1.1;
|
|
|
|
UINT uiAuxIndex;
|
|
UINT uiOffset;
|
|
DWORD dwRandomValue;
|
|
PTCHAR tszBuffer;
|
|
TCHAR tszMsg[MAX_MSG_LEN];
|
|
|
|
switch (aPrivateDataTable[uiIndex].uiType)
|
|
{
|
|
case REG_DWORD:
|
|
|
|
aPrivateDataTable[uiIndex].uiSize = sizeof(DWORD);
|
|
|
|
aPrivateDataTable[uiIndex].pvBuffer =
|
|
(PVOID)malloc(aPrivateDataTable[uiIndex].uiSize);
|
|
|
|
//
|
|
// Fill in the buffer
|
|
//
|
|
dwRandomValue = (DWORD)rand();
|
|
memcpy(aPrivateDataTable[uiIndex].pvBuffer,
|
|
&dwRandomValue,
|
|
aPrivateDataTable[uiIndex].uiSize);
|
|
|
|
//
|
|
// Set the private data "with" the OC Manager
|
|
//
|
|
OCManagerRoutines.SetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
aPrivateDataTable[uiIndex].tszName,
|
|
aPrivateDataTable[uiIndex].pvBuffer,
|
|
aPrivateDataTable[uiIndex].uiSize,
|
|
aPrivateDataTable[uiIndex].uiType);
|
|
break;
|
|
|
|
case REG_BINARY:
|
|
|
|
aPrivateDataTable[uiIndex].uiSize =
|
|
(UINT)(rand() % MAX_PRIVATE_DATA_SIZE) + 1;
|
|
|
|
aPrivateDataTable[uiIndex].pbBuffer =
|
|
(PVOID)malloc(aPrivateDataTable[uiIndex].uiSize);
|
|
|
|
//
|
|
// Fill in the buffer
|
|
//
|
|
for (uiAuxIndex = 0;
|
|
uiAuxIndex < aPrivateDataTable[uiIndex].uiSize;
|
|
uiAuxIndex++)
|
|
{
|
|
aPrivateDataTable[uiIndex].pbBuffer[uiAuxIndex] = (BYTE)rand();
|
|
}
|
|
|
|
//
|
|
// Set the private data
|
|
//
|
|
OCManagerRoutines.SetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
aPrivateDataTable[uiIndex].tszName,
|
|
aPrivateDataTable[uiIndex].pbBuffer,
|
|
aPrivateDataTable[uiIndex].uiSize,
|
|
aPrivateDataTable[uiIndex].uiType);
|
|
break;
|
|
|
|
case REG_SZ:
|
|
|
|
uiAuxIndex = (UINT)(rand() % MAX_STRINGS_FOR_PRIVATE_DATA);
|
|
|
|
aPrivateDataTable[uiIndex].uiSize =
|
|
(_tcslen(g_atszStringValues[uiAuxIndex]) + 1) * sizeof(TCHAR);
|
|
|
|
aPrivateDataTable[uiIndex].pvBuffer =
|
|
(PVOID)malloc(aPrivateDataTable[uiIndex].uiSize);
|
|
|
|
//
|
|
// Fill in the buffer
|
|
//
|
|
_tcscpy((PTSTR)aPrivateDataTable[uiIndex].pvBuffer,
|
|
g_atszStringValues[uiAuxIndex]);
|
|
|
|
//
|
|
// Set the private data
|
|
//
|
|
OCManagerRoutines.SetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
aPrivateDataTable[uiIndex].tszName,
|
|
aPrivateDataTable[uiIndex].pvBuffer,
|
|
aPrivateDataTable[uiIndex].uiSize,
|
|
aPrivateDataTable[uiIndex].uiType);
|
|
break;
|
|
|
|
case REG_MULTI_SZ:
|
|
|
|
uiAuxIndex = (UINT)(rand() % MAX_MULTI_STRINGS_FOR_PRIVATE_DATA);
|
|
|
|
aPrivateDataTable[uiIndex].uiSize =
|
|
MultiStringSize(g_atszMultiStringValues[uiAuxIndex]);
|
|
|
|
aPrivateDataTable[uiIndex].pvBuffer =
|
|
(PVOID)malloc(aPrivateDataTable[uiIndex].uiSize);
|
|
|
|
//
|
|
// Fill in the buffer
|
|
//
|
|
CopyMultiString((PTSTR)aPrivateDataTable[uiIndex].pvBuffer,
|
|
g_atszMultiStringValues[uiAuxIndex]);
|
|
|
|
//
|
|
// Set the private data
|
|
//
|
|
OCManagerRoutines.SetPrivateData(
|
|
OCManagerRoutines.OcManagerContext,
|
|
aPrivateDataTable[uiIndex].tszName,
|
|
aPrivateDataTable[uiIndex].pvBuffer,
|
|
aPrivateDataTable[uiIndex].uiSize,
|
|
aPrivateDataTable[uiIndex].uiType);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // SetAValue //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ChooseSubcomponentInitialState (1.31)
|
|
|
|
"Wrapper" routine for the dialog box procedure ChooseSuncomponentDlgProc.
|
|
|
|
Arguments:
|
|
|
|
lpcvComponentId: supplies the id for the component.
|
|
lpcvSubcomponentId: supplies the id for the subcomponent.
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
DWORD ChooseSubcomponentInitialState(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId)
|
|
{
|
|
TCHAR tszDlgBoxMessage[MAX_MSG_LEN];
|
|
|
|
//
|
|
// We will display a dialog box so the user can choose the
|
|
// initial state he/she wants
|
|
//
|
|
_stprintf(tszDlgBoxMessage, TEXT("%s, %s"),
|
|
lpcvComponentId, lpcvSubcomponentId);
|
|
|
|
return DialogBoxParam(g_hDllInstance,
|
|
MAKEINTRESOURCE(IDD_DIALOG3),
|
|
NULL,
|
|
ChooseSubcomponentDlgProc,
|
|
(LPARAM)tszDlgBoxMessage);
|
|
|
|
} // ChooseSubcomponentInitialState //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: AddNewComponent (1.32)
|
|
|
|
Add a new component to the list
|
|
|
|
Arguments:
|
|
|
|
tszComponentId: supplies id of component to be added to the list.
|
|
|
|
Return Value:
|
|
|
|
Pointer to new per-component data structure or NULL if no memory.
|
|
The structure will be zeroed out except for the ComponentId field.
|
|
|
|
--*/
|
|
PCOMPONENT_DATA AddNewComponent(IN LPCTSTR tszComponentId)
|
|
{
|
|
PCOMPONENT_DATA pcdAux;
|
|
|
|
if (__Malloc(&pcdAux, sizeof(COMPONENT_DATA)))
|
|
{
|
|
__Malloc(&(PTCHAR)(pcdAux->tszComponentId),
|
|
(_tcslen(tszComponentId) + 1) * sizeof(TCHAR));
|
|
|
|
if (pcdAux->tszComponentId)
|
|
{
|
|
_tcscpy((PTSTR)pcdAux->tszComponentId, tszComponentId);
|
|
|
|
//
|
|
// Prepend at the begining
|
|
//
|
|
pcdAux->Next = g_pcdComponents;
|
|
g_pcdComponents = pcdAux;
|
|
}
|
|
}
|
|
|
|
return pcdAux;
|
|
|
|
} // AddNewComponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: LocateComponent (1.33)
|
|
|
|
Locate a component by name from the list of components
|
|
that this dll has been assigned to handle via
|
|
OC_INIT_COMPONENT.
|
|
|
|
Arguments:
|
|
|
|
tszComponentId: supplies the id for the component to look up.
|
|
|
|
Return Value:
|
|
|
|
Pointer to component data or NULL if not found.
|
|
|
|
--*/
|
|
PCOMPONENT_DATA LocateComponent(IN LPCTSTR tszComponentId)
|
|
{
|
|
PCOMPONENT_DATA pcdAux;
|
|
|
|
for (pcdAux = g_pcdComponents; pcdAux; pcdAux = pcdAux->Next)
|
|
{
|
|
if (!(_tcscmp(pcdAux->tszComponentId, tszComponentId)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return pcdAux;
|
|
|
|
} // LocateComponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: RemoveComponent (1.34)
|
|
|
|
Locate a component by name from the list of components and
|
|
then remove it from the list of components.
|
|
|
|
Arguments:
|
|
|
|
tszComponentId: supplies the id for the component to remove.
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID RemoveComponent(IN LPCTSTR tszComponentId)
|
|
{
|
|
PCOMPONENT_DATA pcdAux, pcdPrev;
|
|
|
|
for (pcdPrev = NULL, pcdAux = g_pcdComponents;
|
|
pcdAux;
|
|
pcdPrev = pcdAux, pcdAux = pcdAux->Next)
|
|
{
|
|
if (!(_tcscmp(pcdAux->tszComponentId, tszComponentId)))
|
|
{
|
|
__Free(&(PTCHAR)(pcdAux->tszComponentId));
|
|
if (pcdPrev)
|
|
{
|
|
pcdPrev->Next = pcdAux->Next;
|
|
}
|
|
else
|
|
{
|
|
g_pcdComponents = pcdAux->Next;
|
|
}
|
|
__Free(&pcdAux);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
|
|
} // RemoveComponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CleanUpTest (1.35)
|
|
|
|
Frees globally allocated memory before the test exits
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CleanUpTest()
|
|
{
|
|
USHORT i;
|
|
PCOMPONENT_DATA pcdAux = g_pcdComponents, pcdNext;
|
|
|
|
while (pcdAux)
|
|
{
|
|
pcdNext = pcdAux->Next;
|
|
|
|
__Free(&(PTCHAR)(pcdAux->tszComponentId));
|
|
__Free(&pcdAux);
|
|
|
|
pcdAux = pcdNext;
|
|
}
|
|
|
|
FreeSubcomponentInformationList();
|
|
|
|
return;
|
|
|
|
} // CleanUpTest //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CreateSubcomponentInformationList (1.23)
|
|
|
|
Creates a linked list of every subcomponent. For each subcomponent,
|
|
tells the parent of the subcomponent and whether or not the
|
|
subcomponent has any children.
|
|
|
|
Arguments:
|
|
|
|
hinf: handle to inf file
|
|
|
|
Return Value:
|
|
|
|
BOOL: TRUE if function succeeds, FALSE if it fails
|
|
|
|
--*/
|
|
BOOL CreateSubcomponentInformationList(IN HINF hinf)
|
|
{
|
|
double fn = 1.23;
|
|
|
|
int i, j;
|
|
USHORT usIdLen;
|
|
USHORT usParentIndex;
|
|
LONG lLine, lLineCount;
|
|
DWORD dwSize;
|
|
BOOL bRetval;
|
|
BOOL bFound;
|
|
TCHAR tszSubcomponent[MAX_PATH];
|
|
TCHAR tszParent[MAX_PATH];
|
|
TCHAR tszError[MAX_ERROR_LEN];
|
|
TCHAR tszNeeds[MAX_PATH];
|
|
TCHAR tszExclude[MAX_PATH];
|
|
INFCONTEXT infContext;
|
|
PSUBCOMP pscSubcomponent, pscTemp, pscParent, pscChild;
|
|
PCOMPLIST pclNeeds, pclExclude, pclChild, pclTemp;
|
|
|
|
lLineCount = SetupGetLineCount(hinf, TEXT("Optional Components"));
|
|
|
|
if (lLineCount < 0)
|
|
{
|
|
Log(fn, SEV2, TEXT("Could not get number of lines in Optional ")
|
|
TEXT("Components section of inf file: %s"),
|
|
ErrorMsg(GetLastError(), tszError));
|
|
return FALSE;
|
|
}
|
|
|
|
for (lLine = 0; lLine < lLineCount; lLine++)
|
|
{
|
|
bRetval = SetupGetLineByIndex(hinf,
|
|
TEXT("Optional Components"),
|
|
lLine,
|
|
&infContext);
|
|
|
|
if (!bRetval)
|
|
{
|
|
Log(fn, SEV2, TEXT("Could not get line %d from Optional ")
|
|
TEXT("Components section of inf file: %s"),
|
|
lLine, ErrorMsg(GetLastError(), tszError));
|
|
return FALSE;
|
|
}
|
|
|
|
bRetval = SetupGetLineText(&infContext,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
tszSubcomponent,
|
|
MAX_PATH,
|
|
&dwSize);
|
|
|
|
if (!bRetval)
|
|
{
|
|
Log(fn, SEV2, TEXT("Could not get text of line %d from ")
|
|
TEXT("Optional Components section of inf file: %s"),
|
|
lLine, ErrorMsg(GetLastError(), tszError));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate a new subcomponent structure
|
|
//
|
|
if (!__Malloc(&pscSubcomponent, sizeof(SUBCOMP)))
|
|
{
|
|
Log(fn, SEV2, TEXT("Could not allocate space for ")
|
|
TEXT("pscSubcomponent"));
|
|
return FALSE;
|
|
}
|
|
|
|
pscSubcomponent->pclNeeds = NULL;
|
|
pscSubcomponent->pclExclude = NULL;
|
|
pscSubcomponent->pclChildren = NULL;
|
|
pscSubcomponent->Next = NULL;
|
|
|
|
//
|
|
// Find out the subcomponent id's length
|
|
//
|
|
usIdLen = (USHORT) _tcslen(tszSubcomponent);
|
|
|
|
//
|
|
// Copy the ComponentId. All of the test inf's use a special
|
|
// SubcomponentId naming format, so that the subcomponent is a
|
|
// superset of the ComponentId. For example, if the component
|
|
// name is "component" the subcomponet names will be
|
|
// "component_1", "component_2", "component_1_2", etc.
|
|
//
|
|
for (i = 0; i < usIdLen; i++)
|
|
{
|
|
if (tszSubcomponent[i] == TEXT('_'))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pscSubcomponent->tszComponentId[i] = tszSubcomponent[i];
|
|
}
|
|
}
|
|
pscSubcomponent->tszComponentId[i] = TEXT('\0');
|
|
|
|
|
|
//
|
|
// if the subcomponent has a parent, get the name of the parent, store
|
|
// it, and then search for this parent amongst the subcomponents
|
|
// we've already processed. If the parent is found, mark the parent
|
|
// so we know that the parent has children.
|
|
//
|
|
|
|
//
|
|
// Record the name of the parent.
|
|
//
|
|
if (SetupFindFirstLine(hinf,
|
|
tszSubcomponent,
|
|
TEXT("Parent"),
|
|
&infContext))
|
|
{
|
|
bRetval = SetupGetStringField(&infContext,
|
|
1,
|
|
tszParent,
|
|
MAX_PATH,
|
|
NULL);
|
|
if (!bRetval)
|
|
{
|
|
//
|
|
// Parent name is empty. This is an invalid INF, but
|
|
// we'll go with it.
|
|
//
|
|
ZeroMemory(tszParent, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Search through the subcomponent list for this parent
|
|
//
|
|
for (pscParent = g_pscHead;
|
|
pscParent != NULL;
|
|
pscParent = pscParent->Next)
|
|
{
|
|
if (_tcscmp(tszParent, pscParent->tszSubcomponentId) == 0)
|
|
{
|
|
//
|
|
// Found the parent subcomponent node. Add the current
|
|
// subcomponent to the parent node's children list,
|
|
// if it isn't there already
|
|
//
|
|
bFound = FALSE;
|
|
for (pclTemp = pscParent->pclChildren;
|
|
pclTemp != NULL;
|
|
pclTemp = pclTemp->Next)
|
|
{
|
|
if (_tcscmp(pclTemp->tszSubcomponentId,
|
|
tszSubcomponent) == 0)
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
if (!__Malloc(&pclChild, sizeof(COMPLIST)))
|
|
{
|
|
Log(fn, SEV2, TEXT("Out of memory"));
|
|
break;
|
|
}
|
|
|
|
_tcscpy(pclChild->tszSubcomponentId, tszSubcomponent);
|
|
pclChild->Next = pscParent->pclChildren;
|
|
pscParent->pclChildren = pclChild;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This component has no parent. Assume this is the top-level
|
|
// component and assign it's parent's name as itself
|
|
//
|
|
_tcscpy(tszParent, tszSubcomponent);
|
|
}
|
|
|
|
_tcscpy(pscSubcomponent->tszParentId, tszParent);
|
|
|
|
//
|
|
// Now search through the list to see if any of the subcomponents
|
|
// in the list are children of this new subcomponent
|
|
//
|
|
for (pscChild = g_pscHead; pscChild != NULL; pscChild = pscChild->Next)
|
|
{
|
|
if (_tcscmp(tszSubcomponent, pscChild->tszParentId) == 0)
|
|
{
|
|
//
|
|
// Found a node that is the child of the current
|
|
// node. Add this child to the current node's
|
|
// child list, if it isn't there already
|
|
//
|
|
bFound = FALSE;
|
|
for (pclTemp = pscSubcomponent->pclChildren;
|
|
pclTemp != NULL;
|
|
pclTemp = pclTemp->Next)
|
|
{
|
|
if (_tcscmp(pclTemp->tszSubcomponentId,
|
|
pscChild->tszSubcomponentId) == 0)
|
|
{
|
|
bFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
if (!__Malloc(&pclChild, sizeof(COMPLIST)))
|
|
{
|
|
Log(fn, SEV2, TEXT("Out of memory"));
|
|
break;
|
|
}
|
|
|
|
_tcscpy(pclChild->tszSubcomponentId,
|
|
pscChild->tszSubcomponentId);
|
|
pclChild->Next = pscSubcomponent->pclChildren;
|
|
pscSubcomponent->pclChildren = pclChild;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill in the rest of the data for the new node
|
|
//
|
|
_tcscpy(pscSubcomponent->tszSubcomponentId, tszSubcomponent);
|
|
|
|
//
|
|
// See if this node has any needs relationships. If it does,
|
|
// record them.
|
|
//
|
|
if (SetupFindFirstLine(hinf,
|
|
tszSubcomponent,
|
|
TEXT("Needs"),
|
|
&infContext))
|
|
{
|
|
for (i = 1, bRetval = TRUE; bRetval; i++)
|
|
{
|
|
bRetval = SetupGetStringField(&infContext,
|
|
i,
|
|
tszNeeds,
|
|
MAX_PATH,
|
|
NULL);
|
|
|
|
if (bRetval)
|
|
{
|
|
if (!__Malloc(&pclNeeds, sizeof(COMPLIST)))
|
|
{
|
|
Log(fn, SEV2, TEXT("Out of memory"));
|
|
break;
|
|
}
|
|
|
|
_tcscpy(pclNeeds->tszSubcomponentId, tszNeeds);
|
|
pclNeeds->Next = pscSubcomponent->pclNeeds;
|
|
pscSubcomponent->pclNeeds = pclNeeds;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if this node has any exclude relationships. If it does,
|
|
// record them.
|
|
//
|
|
if (SetupFindFirstLine(hinf,
|
|
tszSubcomponent,
|
|
TEXT("Exclude"),
|
|
&infContext))
|
|
{
|
|
for (i = 1, bRetval = TRUE; bRetval; i++)
|
|
{
|
|
bRetval = SetupGetStringField(&infContext,
|
|
i,
|
|
tszExclude,
|
|
MAX_PATH,
|
|
NULL);
|
|
|
|
if (bRetval)
|
|
{
|
|
if (!__Malloc(&pclExclude, sizeof(COMPLIST)))
|
|
{
|
|
Log(fn, SEV2, TEXT("Out of memory"));
|
|
break;
|
|
}
|
|
|
|
_tcscpy(pclExclude->tszSubcomponentId, tszExclude);
|
|
pclExclude->Next = pscSubcomponent->pclExclude;
|
|
pscSubcomponent->pclExclude = pclExclude;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new component to the beginning of the linked list
|
|
//
|
|
pscSubcomponent->Next = g_pscHead;
|
|
g_pscHead = pscSubcomponent;
|
|
|
|
} // for (lLine...
|
|
|
|
return TRUE;
|
|
|
|
} // CreateSubcomponentInformationList //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: FreeSubcomponentInformationList (1.36)
|
|
|
|
Frees the global linked list of subcomponent information.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID FreeSubcomponentInformationList()
|
|
{
|
|
PSUBCOMP pscTemp = g_pscHead;
|
|
PSUBCOMP pscNext;
|
|
PCOMPLIST pclTemp, pclNext;
|
|
|
|
//
|
|
// Delete all the SUBCOMP nodes
|
|
//
|
|
while (pscTemp)
|
|
{
|
|
pscNext = pscTemp->Next;
|
|
|
|
//
|
|
// Delete all the COMPLIST pclNeeds nodes
|
|
//
|
|
pclTemp = pscTemp->pclNeeds;
|
|
while (pclTemp)
|
|
{
|
|
pclNext = pclTemp->Next;
|
|
|
|
__Free(&pclTemp);
|
|
|
|
pclTemp = pclNext;
|
|
}
|
|
|
|
//
|
|
// Delete all the COMPLIST pcdExclude nodes
|
|
//
|
|
pclTemp = pscTemp->pclExclude;
|
|
while (pclTemp)
|
|
{
|
|
pclNext = pclTemp->Next;
|
|
|
|
__Free(&pclTemp);
|
|
|
|
pclTemp = pclNext;
|
|
}
|
|
|
|
//
|
|
// Delete all the COMPLIST pclChildren nodes
|
|
//
|
|
pclTemp = pscTemp->pclChildren;
|
|
while (pclTemp)
|
|
{
|
|
pclNext = pclTemp->Next;
|
|
|
|
__Free(&pclTemp);
|
|
|
|
pclTemp = pclNext;
|
|
}
|
|
|
|
__Free(&pscTemp);
|
|
|
|
pscTemp = pscNext;
|
|
}
|
|
|
|
g_pscHead = NULL;
|
|
|
|
} // FreeSubcomponentInformationList //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ClearSubcomponentInformationMarks (1.37)
|
|
|
|
Clears the marks on each of the subcomponent information nodes
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID ClearSubcomponentInformationMarks()
|
|
{
|
|
PSUBCOMP pscTemp;
|
|
|
|
for (pscTemp = g_pscHead; pscTemp != NULL; pscTemp = pscTemp->Next)
|
|
{
|
|
pscTemp->bMarked = FALSE;
|
|
}
|
|
|
|
} // ClearSubcomponentInformationMarks //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckSubcomponentInformationMarks (1.38)
|
|
|
|
Clears the marks on each of the subcomponent information nodes
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CheckSubcomponentInformationMarks()
|
|
{
|
|
double fn = 1.38;
|
|
|
|
PSUBCOMP pscTemp;
|
|
|
|
for (pscTemp = g_pscHead; pscTemp != NULL; pscTemp = pscTemp->Next)
|
|
{
|
|
if (!(pscTemp->pclChildren) && !(pscTemp->bMarked))
|
|
{
|
|
Log(fn, SEV2, TEXT("%s.%s was not processed"),
|
|
pscTemp->tszComponentId,
|
|
pscTemp->tszSubcomponentId);
|
|
}
|
|
}
|
|
|
|
} // CheckSubcomponentInformationMarks //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: FindSubcomponentInformationNode (1.39)
|
|
|
|
Tries to find a node with matching ComponentId and SubcomponentId
|
|
|
|
Arguments:
|
|
|
|
tszComponentId: name of the component
|
|
tszSubcomponentId: name of the subcomponent
|
|
|
|
Return Value:
|
|
|
|
PSUBCOMP: if node is found, returns pointer to node.
|
|
if node is not found, returns NULL
|
|
|
|
--*/
|
|
PSUBCOMP FindSubcomponentInformationNode(IN PTCHAR tszComponentId,
|
|
IN PTCHAR tszSubcomponentId)
|
|
{
|
|
PSUBCOMP pscTemp;
|
|
TCHAR tszSubcomp[MAX_PATH];
|
|
|
|
__ASSERT(tszComponentId != NULL);
|
|
|
|
//
|
|
// If subcomponent is null, this is probably the master component.
|
|
// In this case, subcomponent name should be same as component name.
|
|
//
|
|
if (tszSubcomponentId == NULL ||
|
|
_tcscmp(tszSubcomponentId, TEXT("(null)")) == 0 ||
|
|
tszSubcomponentId[0] == TEXT('\0'))
|
|
{
|
|
_tcscpy(tszSubcomp, tszComponentId);
|
|
}
|
|
else
|
|
{
|
|
_tcscpy(tszSubcomp, tszSubcomponentId);
|
|
}
|
|
|
|
//
|
|
// Look for the node
|
|
//
|
|
for (pscTemp = g_pscHead; pscTemp != NULL; pscTemp = pscTemp->Next)
|
|
{
|
|
if (_tcscmp(tszComponentId, pscTemp->tszComponentId) == 0 &&
|
|
_tcscmp(tszSubcomp, pscTemp->tszSubcomponentId) == 0)
|
|
{
|
|
return pscTemp;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} // FindSubcomponentInformationNode //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckNeedsDependencies (1.41)
|
|
|
|
Checks the selection status of every component and subcomponent to
|
|
make sure all needs relationships are being upheld.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CheckNeedsDependencies()
|
|
{
|
|
PSUBCOMP pscSubcomponent;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
TCHAR tszNodesVisited[NODES_VISITED_LENGTH];
|
|
|
|
ZeroMemory(tszNodesVisited, NODES_VISITED_LENGTH);
|
|
|
|
//
|
|
// Go through each subcomponent, check its selection state
|
|
// and the selection state of any subcomponents that it needs
|
|
//
|
|
for (pscSubcomponent = g_pscHead;
|
|
pscSubcomponent != NULL;
|
|
pscSubcomponent = pscSubcomponent->Next)
|
|
{
|
|
if (pcdComponentData = LocateComponent(pscSubcomponent->tszComponentId))
|
|
{
|
|
//
|
|
// If this component is selected, check out its needs
|
|
// dependencies
|
|
//
|
|
if (pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pscSubcomponent->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT))
|
|
{
|
|
CheckNeedsDependenciesOfSubcomponent(
|
|
pcdComponentData->ocrHelperRoutines,
|
|
pscSubcomponent,
|
|
pscSubcomponent,
|
|
tszNodesVisited);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // CheckNeedsDependencies //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckNeedsDependenciesOfSubcomponent (1.42)
|
|
|
|
Receives a subcomponent ID. Checks to see if this subcomponent is
|
|
checked, and if it is, recurses to check all the subcomponents
|
|
that are needed by this subcomponent (if any)
|
|
|
|
Arguments:
|
|
|
|
ocrHelper: helper routines
|
|
pscSubcomponent: contains data about subcomponent being checked
|
|
pscWhoNeedsMe: tells who needs this subcomponent
|
|
|
|
Return Value:
|
|
|
|
BOOL: TRUE if all needs dependencies check out, FALSE if not
|
|
|
|
--*/
|
|
BOOL CheckNeedsDependenciesOfSubcomponent(IN OCMANAGER_ROUTINES ocrHelper,
|
|
IN PSUBCOMP pscSubcomponent,
|
|
IN PSUBCOMP pscWhoNeedsMe,
|
|
IN OUT PTCHAR tszNodesVisited)
|
|
{
|
|
double fn = 1.42;
|
|
|
|
PCOMPLIST pclNeeds;
|
|
PSUBCOMP pscNeeds;
|
|
UINT uiRemoteResult;
|
|
CHECK_NEEDS cnCheckNeeds;
|
|
TCHAR tsz[MAX_PATH];
|
|
ULONG ulError;
|
|
|
|
if (ocrHelper.QuerySelectionState(ocrHelper.OcManagerContext,
|
|
pscSubcomponent->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT))
|
|
{
|
|
//
|
|
// Check to see if we've already checked out this node
|
|
//
|
|
if (!AlreadyVisitedNode(pscSubcomponent->tszSubcomponentId,
|
|
tszNodesVisited))
|
|
{
|
|
//
|
|
// Add this node to the list of nodes we've already checked
|
|
//
|
|
_tcscat(tszNodesVisited, pscSubcomponent->tszSubcomponentId);
|
|
_tcscat(tszNodesVisited, TEXT(" "));
|
|
|
|
//
|
|
// Go through each subcomponent that is needed by this subcomponent
|
|
//
|
|
for (pclNeeds = pscSubcomponent->pclNeeds;
|
|
pclNeeds != NULL;
|
|
pclNeeds = pclNeeds->Next)
|
|
{
|
|
//
|
|
// Check to see if this needed subcomponent belongs to the
|
|
// current component. If it does, just check here.
|
|
// If it doesn't, call private function of the component
|
|
// that it does belong to. This private function will
|
|
// do the checking and return the result
|
|
//
|
|
if (_tcsncmp(pscSubcomponent->tszSubcomponentId,
|
|
pclNeeds->tszSubcomponentId,
|
|
_tcslen(pscSubcomponent->tszComponentId)) == 0)
|
|
{
|
|
if (!CheckLocalNeedsDependencies(ocrHelper,
|
|
pscSubcomponent,
|
|
pclNeeds,
|
|
tszNodesVisited))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cnCheckNeeds.pclNeeds = pclNeeds;
|
|
cnCheckNeeds.tszNodesVisited = tszNodesVisited;
|
|
|
|
ulError = ocrHelper.CallPrivateFunction(
|
|
ocrHelper.OcManagerContext,
|
|
GetComponent(pclNeeds->tszSubcomponentId, tsz),
|
|
pclNeeds->tszSubcomponentId,
|
|
OCP_CHECK_NEEDS,
|
|
(UINT)pscSubcomponent,
|
|
&cnCheckNeeds,
|
|
(PUINT)&cnCheckNeeds);
|
|
|
|
if (ulError != NO_ERROR)
|
|
{
|
|
Log(fn, SEV2, TEXT("CallPrivateFunction failed for ")
|
|
TEXT("%s called from %s: %lu"),
|
|
pclNeeds->tszSubcomponentId,
|
|
pscSubcomponent->tszComponentId,
|
|
ulError);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!cnCheckNeeds.bResult) return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// All the needs dependencies checked out
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// This component is not selected, return FALSE
|
|
//
|
|
Log(fn, SEV2, TEXT("%s needs %s. %s is selected, ")
|
|
TEXT("but %s is not."),
|
|
pscWhoNeedsMe->tszSubcomponentId,
|
|
pscSubcomponent->tszComponentId,
|
|
pscWhoNeedsMe->tszSubcomponentId,
|
|
pscSubcomponent->tszComponentId);
|
|
return FALSE;
|
|
|
|
} // CheckNeedsDependenciesOfSubcomponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckLocalNeedsDependencies (1.43)
|
|
|
|
Receives a subcomponent ID. Checks to see if this subcomponent is
|
|
checked, and if it is, recurses to check all the subcomponents
|
|
that are needed by this subcomponent (if any)
|
|
|
|
Arguments:
|
|
|
|
ocrHelper: helper routines
|
|
pscSubcomponent: contains data about subcomponent being checked
|
|
pclNeeds: tells who this subcomponent needs
|
|
|
|
Return Value:
|
|
|
|
BOOL: TRUE if all needs dependencies check out, FALSE if not
|
|
|
|
--*/
|
|
BOOL CheckLocalNeedsDependencies(IN OCMANAGER_ROUTINES ocrHelper,
|
|
IN PSUBCOMP pscSubcomponent,
|
|
IN PCOMPLIST pclNeeds,
|
|
IN OUT PTCHAR tszNodesVisited)
|
|
{
|
|
PSUBCOMP pscNeeds;
|
|
|
|
//
|
|
// Find the PSUBCOMP node for this subcomponent
|
|
//
|
|
for (pscNeeds = g_pscHead;
|
|
pscNeeds != NULL;
|
|
pscNeeds = pscNeeds->Next)
|
|
{
|
|
if (_tcscmp(pscNeeds->tszSubcomponentId,
|
|
pclNeeds->tszSubcomponentId) == 0)
|
|
{
|
|
if (!CheckNeedsDependenciesOfSubcomponent(ocrHelper,
|
|
pscNeeds,
|
|
pscSubcomponent,
|
|
tszNodesVisited))
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
} // CheckLocalNeedsDependencies //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckExcludeDependencies (1.46)
|
|
|
|
Checks the selection status of every component and subcomponent to
|
|
make sure all exclude relationships are being upheld.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CheckExcludeDependencies()
|
|
{
|
|
double fn = 1.46;
|
|
|
|
PSUBCOMP pscSubcomponent;
|
|
PCOMPLIST pclExclude;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
//
|
|
// Go through each subcomponent, check its selection state
|
|
// and the selection state of any subcomponents that it excludes
|
|
//
|
|
for (pscSubcomponent = g_pscHead;
|
|
pscSubcomponent != NULL;
|
|
pscSubcomponent = pscSubcomponent->Next)
|
|
{
|
|
if (pcdComponentData = LocateComponent(pscSubcomponent->tszComponentId))
|
|
{
|
|
//
|
|
// If this component is selected, check out its exclude
|
|
// dependencies
|
|
//
|
|
if (pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pscSubcomponent->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT))
|
|
{
|
|
//
|
|
// Go through each subcomponent that is
|
|
// excluded by this subcomponent
|
|
//
|
|
for (pclExclude = pscSubcomponent->pclExclude;
|
|
pclExclude != NULL;
|
|
pclExclude = pclExclude->Next)
|
|
{
|
|
if (pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pclExclude->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT))
|
|
{
|
|
Log(fn, SEV2, TEXT("%s excludes %s. Both are selected"),
|
|
pscSubcomponent->tszSubcomponentId,
|
|
pclExclude->tszSubcomponentId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // CheckExcludeDependencies //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CheckParentDependencies (1.47)
|
|
|
|
Checks the selection status of every component and subcomponent to
|
|
make sure all parent relationships are being upheld.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
void
|
|
|
|
--*/
|
|
VOID CheckParentDependencies()
|
|
{
|
|
double fn = 1.47;
|
|
|
|
PSUBCOMP pscSubcomponent;
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
BOOL bState;
|
|
PCOMPLIST pclChildren;
|
|
|
|
PCOMPONENT_DATA pcdSubComponentData;
|
|
|
|
BOOL bParentState;
|
|
BOOL bAllCleared;
|
|
|
|
PSUBCOMP pscParent;
|
|
|
|
TCHAR tszMsg[256];
|
|
|
|
static BOOL bInformed1 = FALSE;
|
|
static BOOL bInformed2 = FALSE;
|
|
|
|
// QuerySelectionState returns TRUE when the component's state
|
|
// does not equal SELSTATE_NO
|
|
// This means it returns TRUE when the component is selected
|
|
// or partially selected
|
|
|
|
//
|
|
// Go through each subcomponent, check its selection state
|
|
// and the selection state of its parent
|
|
//
|
|
|
|
for (pscSubcomponent = g_pscHead;
|
|
pscSubcomponent != NULL;
|
|
pscSubcomponent = pscSubcomponent->Next)
|
|
{
|
|
bState = TRUE;
|
|
if (pcdComponentData = LocateComponent(pscSubcomponent->tszComponentId))
|
|
{
|
|
//
|
|
// Check to see if this subcomponent is selected
|
|
//
|
|
bState = pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pscSubcomponent->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT);
|
|
|
|
// Let pass a NULL pointer to the helper routine
|
|
//pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
// NULL, NULL, OCSELSTATETYPE_CURRENT);
|
|
|
|
if (bState == TRUE) {
|
|
|
|
// The component is selected
|
|
|
|
//if (GetLastError() == ERROR_INVALID_NAME) {
|
|
// MessageBox(NULL, TEXT("There is an error when calling QuerySelectionState"), TEXT("CheckParentDependencies"), MB_OK);
|
|
// break;
|
|
//}
|
|
|
|
//
|
|
// Check to see if its parent is selected
|
|
//
|
|
bParentState = pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pscSubcomponent->tszParentId,
|
|
OCSELSTATETYPE_CURRENT);
|
|
|
|
// If the component is selected, its parent should
|
|
// be selected or partially selected, thus bParentState
|
|
// should be TRUE
|
|
|
|
if (!bParentState)
|
|
{
|
|
Log(fn, SEV2, TEXT("%s is selected but its parent, %s, ")
|
|
TEXT("is not"),
|
|
pscSubcomponent->tszSubcomponentId,
|
|
pscSubcomponent->tszParentId);
|
|
}
|
|
}
|
|
|
|
else if (bState == FALSE) {
|
|
//
|
|
// The child is not selected, this means none of its children
|
|
// should be selected, and its parent should be greyed or
|
|
// unselected
|
|
//
|
|
// This will check its siblings to determine whether they
|
|
// are selected or not
|
|
// if none of its siblings are selected, the parent should be
|
|
// cleared.
|
|
|
|
// First find its parent in the list
|
|
|
|
if (_tcscmp(pscSubcomponent->tszSubcomponentId, pscSubcomponent->tszParentId) == 0) {
|
|
// This is a top level component
|
|
// we will skip the following test
|
|
continue;
|
|
}
|
|
for (pscParent = g_pscHead; pscParent != NULL; pscParent = pscParent->Next) {
|
|
if (_tcscmp(pscParent->tszSubcomponentId, pscSubcomponent->tszParentId) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pclChildren = pscParent->pclChildren;
|
|
|
|
bAllCleared = TRUE;
|
|
|
|
for (pclChildren = pscParent->pclChildren; pclChildren != NULL; pclChildren = pclChildren->Next) {
|
|
// Locate the child component
|
|
//pcdSubComponentData = LocateComponent(pclChildren->tszSubcomponentId);
|
|
//if (!pcdSubComponentData) {
|
|
// MessageBox(NULL, TEXT("Error locating subcomponent that is in the list"), TEXT("CheckParentDependencies"), MB_OK);
|
|
// break;
|
|
//}
|
|
// Now query the state of this subcomponent
|
|
if (pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pclChildren->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT)){
|
|
bAllCleared = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//pcdSubComponentData = LocateComponent(pscParent->tszComponentId);
|
|
//if (!pcdSubComponentData) {
|
|
// MessageBox(NULL, TEXT("Error locating subcomponent that is in the list"), TEXT("CheckParentDependencies"), MB_OK);
|
|
// break;
|
|
//}
|
|
|
|
bParentState = pcdComponentData->ocrHelperRoutines.QuerySelectionState(
|
|
pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
pscParent->tszSubcomponentId,
|
|
OCSELSTATETYPE_CURRENT);
|
|
|
|
if (bAllCleared) {
|
|
// None of the subcomponent is selected
|
|
// Check the state of the parent component
|
|
if (bParentState != FALSE) {
|
|
Log(fn, SEV2, TEXT("%s.%s is (partially) selected, but none")
|
|
TEXT(" of its subcomponent is selected"),
|
|
pscParent->tszParentId,
|
|
pscParent->tszComponentId);
|
|
if (!bInformed1) {
|
|
_stprintf(tszMsg, TEXT("%s is (partially) selected, but none of child is selected"), pscParent->tszSubcomponentId);
|
|
MessageBox(NULL,tszMsg, TEXT("CheckParentDependencies"), MB_OK);
|
|
bInformed1 = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
else{
|
|
// At least one of the subcomponent is selected
|
|
// Parent should be (partially) selected
|
|
if (bParentState == FALSE) {
|
|
Log(fn, SEV2, TEXT("%s.%s is not selected, but one")
|
|
TEXT(" of its subcomponent is selected"),
|
|
pscParent->tszParentId,
|
|
pscParent->tszComponentId);
|
|
if (!bInformed2) {
|
|
_stprintf(tszMsg, TEXT("%s is not selected, but at least one of child is selected"), pscParent->tszSubcomponentId);
|
|
MessageBox(NULL,tszMsg, TEXT("CheckParentDependencies"), MB_OK);
|
|
bInformed2 = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
} // CheckParentDependencies //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: AlreadyVisitedNode (1.44)
|
|
|
|
Receives a subcomponent ID and a list of subcomponents that
|
|
have already been checked. Looks in the list to see if this
|
|
subcomponent has already been checked.
|
|
|
|
Arguments:
|
|
|
|
tszSubcomponentId: the new subcomponent
|
|
tszNodesVisited: list of what's already been checked
|
|
|
|
Return Value:
|
|
|
|
BOOL: TRUE if this subcomponent has already been checked, FALSE if not
|
|
|
|
--*/
|
|
BOOL AlreadyVisitedNode(IN PTCHAR tszSubcomponentId,
|
|
IN PTCHAR tszNodesVisited)
|
|
{
|
|
PTCHAR tszMarker;
|
|
TCHAR tszName[MAX_PATH];
|
|
USHORT usCount, i;
|
|
|
|
tszMarker = tszNodesVisited;
|
|
|
|
for (usCount = 0; usCount < _tcslen(tszNodesVisited);)
|
|
{
|
|
for (i = 0; i < _tcslen(tszMarker); i++)
|
|
{
|
|
if (tszMarker[i] == TEXT(' ')) break;
|
|
tszName[i] = tszMarker[i];
|
|
}
|
|
tszName[i] = TEXT('\0');
|
|
|
|
if (_tcscmp(tszName, tszSubcomponentId) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
usCount += _tcslen(tszName) + 1;
|
|
|
|
tszMarker += _tcslen(tszName) + 1;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // AlreadyVisitedNode //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: GetComponent (1.45)
|
|
|
|
Receives a subcomponent ID and returns the ID of the master component
|
|
that owns this subcomponent
|
|
|
|
Arguments:
|
|
|
|
tszSubcomponentId: the subcomponent
|
|
tszComponentId: returns component ID using this string.
|
|
must be a valid buffer
|
|
|
|
Return Value:
|
|
|
|
PTCHAR: returns component ID
|
|
|
|
--*/
|
|
PTCHAR GetComponent(IN PTCHAR tszSubcomponentId,
|
|
IN OUT PTCHAR tszComponentId)
|
|
{
|
|
USHORT i;
|
|
|
|
__ASSERT(tszComponentId != NULL);
|
|
|
|
for (i = 0; i < _tcslen(tszSubcomponentId); i++)
|
|
{
|
|
if (tszSubcomponentId[i] == TEXT('_'))
|
|
{
|
|
break;
|
|
}
|
|
|
|
tszComponentId[i] = tszSubcomponentId[i];
|
|
}
|
|
|
|
tszComponentId[i] = TEXT('\0');
|
|
|
|
return tszComponentId;
|
|
|
|
} // GetComponent //
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: ParseCommandLine (1.47)
|
|
|
|
Checks the command line to see if there are any arguments that
|
|
pertain to the component DLLs
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
VOID ParseCommandLine()
|
|
{
|
|
USHORT i;
|
|
USHORT usMarker;
|
|
//TCHAR usMarker;
|
|
BOOL bCheckArgs = FALSE;
|
|
PTCHAR tszCommandLine;
|
|
PTCHAR tszMarker;
|
|
TCHAR tszArg[MAX_PATH];
|
|
|
|
TCHAR tszDlgMessage[256];
|
|
|
|
tszCommandLine = GetCommandLine();
|
|
tszMarker = tszCommandLine;
|
|
usMarker = (USHORT)tszMarker;
|
|
|
|
while ((USHORT)((USHORT)tszMarker - usMarker) < (USHORT)_tcslen(tszCommandLine) * sizeof(TCHAR))
|
|
{
|
|
for (i = 0; i < _tcslen(tszMarker); i++)
|
|
{
|
|
if (tszMarker[i] == TEXT(' ') ||
|
|
tszMarker[i] == TEXT('\0'))
|
|
{
|
|
break;
|
|
}
|
|
tszArg[i] = tszMarker[i];
|
|
}
|
|
tszArg[i] = TEXT('\0');
|
|
|
|
tszMarker += _tcslen(tszArg) + 1;
|
|
|
|
while (tszMarker[0] == TEXT(' ')) tszMarker++;
|
|
|
|
if (bCheckArgs)
|
|
{
|
|
//
|
|
// Check the value of this argument
|
|
//
|
|
if (_tcscmp(tszArg, TEXT("/av")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/AV")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-av")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-AV")) == 0)
|
|
{
|
|
g_bAccessViolation = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check the value of this argument
|
|
//
|
|
if (_tcscmp(tszArg, TEXT("/e")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/E")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-e")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-E")) == 0)
|
|
{
|
|
g_bTestExtended = TRUE;
|
|
}
|
|
|
|
//
|
|
// negstep make the return value of OC_QUERY_STEP_COUNT negative one
|
|
//
|
|
if (_tcscmp(tszArg, TEXT("/negstep")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/NEGSTEP")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-negstep")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-NEGSTEP")) == 0)
|
|
{
|
|
nStepsFinal = -1;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/nowiz")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/NOWIZ")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-nowiz")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-NOWIZ")) == 0)
|
|
{
|
|
g_bNoWizPage = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/crashunicode")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/CRASHUNICODE")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-crashunicode")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-CRASHUNICODE")) == 0)
|
|
{
|
|
g_bCrashUnicode = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/invalidbitmap")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/INVALIDBITMAP")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-invalidbitmap")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-INVALIDBITMAP")) == 0)
|
|
{
|
|
g_bInvalidBitmap = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/closeinf")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/CLOSEINF")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-closeinf")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-CLOSEINF")) == 0)
|
|
{
|
|
g_bCloseInf = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/hugesize")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/HUGESIZE")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-hugesize")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-HUGESIZE")) == 0)
|
|
{
|
|
g_bHugeSize = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/noneedmedia")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/NONEEDMEDIA")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-noneedmedia")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-NONEEDMEDIA")) == 0)
|
|
{
|
|
g_bNoNeedMedia = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/reboot")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/reboot")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-reboot")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-reboot")) == 0)
|
|
{
|
|
g_bReboot = TRUE;
|
|
}
|
|
|
|
|
|
if (_tcscmp(tszArg, TEXT("/cleanreg")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/CLEANREG")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-cleanreg")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-CLEANREG")) == 0)
|
|
{
|
|
g_bCleanReg = TRUE;
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/nolang")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/NOLANG")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-nolang")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("-NOLANG")) == 0)
|
|
{
|
|
g_bNoLangSupport = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (_tcscmp(tszArg, TEXT("/z")) == 0 ||
|
|
_tcscmp(tszArg, TEXT("/Z")) == 0)
|
|
{
|
|
bCheckArgs = TRUE;
|
|
}
|
|
}
|
|
|
|
} // ParseCommandLine //
|
|
|
|
/*++
|
|
|
|
Routine Description: testAV (1.0)
|
|
|
|
Procedure to generate an access violation
|
|
|
|
Argument:
|
|
|
|
If true, an access violation is generated
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
VOID testAV(BOOL bDoIt){
|
|
|
|
/* The Following variables are used for access violation test */
|
|
COMPONENT_DATA *g_pcdAccessViolation;
|
|
|
|
if (bDoIt){
|
|
g_pcdAccessViolation = NULL;
|
|
g_pcdAccessViolation->hinfMyInfHandle = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: TestReturnValueAndAV (1.0)
|
|
|
|
Procdefure to give the user control of what to return and when to cause an access violation
|
|
|
|
Argument:
|
|
|
|
Arguments to ComponentSetupProc plus and bOverride
|
|
|
|
Return Value:
|
|
|
|
The return value that user gives.
|
|
|
|
--*/
|
|
BOOL TestReturnValueAndAV(IN LPCVOID lpcvComponentId,
|
|
IN LPCVOID lpcvSubcomponentId,
|
|
IN UINT uiFunction,
|
|
IN UINT uiParam1,
|
|
IN PVOID pvParam2,
|
|
IN OUT PReturnOrAV praValue)
|
|
{
|
|
int returnValue;
|
|
|
|
if (!BeginTest()){
|
|
praValue->bOverride = FALSE;
|
|
return ((DWORD)0);
|
|
}
|
|
|
|
//ChooseAccessViolationEx();
|
|
|
|
//Now fill in the fields of raValue
|
|
praValue->tszComponent = (PTCHAR)lpcvComponentId;
|
|
praValue->tszSubComponent = (PTCHAR)lpcvSubcomponentId;
|
|
|
|
switch(uiFunction){
|
|
case OC_PREINITIALIZE:
|
|
praValue->tszSubComponent[0]=TEXT('\0');
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_PREINITIALIZE"));
|
|
break;
|
|
|
|
case OC_INIT_COMPONENT:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_INIT_COMPONENT"));
|
|
break;
|
|
|
|
case OC_QUERY_STATE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_QUERY_STATE"));
|
|
break;
|
|
|
|
case OC_SET_LANGUAGE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_SET_LANGUAGE"));
|
|
break;
|
|
|
|
case OC_QUERY_IMAGE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_QUERY_IMAGE"));
|
|
break;
|
|
|
|
case OC_REQUEST_PAGES:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_REQUEST_PAGES"));
|
|
break;
|
|
|
|
case OC_QUERY_CHANGE_SEL_STATE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_QUERY_CHANGE_SEL_STATE"));
|
|
break;
|
|
|
|
case OC_CALC_DISK_SPACE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_CALC_DISK_SPACE"));
|
|
break;
|
|
|
|
case OC_QUEUE_FILE_OPS:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_QUEUE_FILE_OPS"));
|
|
break;
|
|
|
|
case OC_NEED_MEDIA:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_NEED_MEDIA"));
|
|
break;
|
|
|
|
case OC_QUERY_STEP_COUNT:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_QUERY_STEP_COUNT"));
|
|
break;
|
|
|
|
case OC_COMPLETE_INSTALLATION:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_COMPLETE_INSTALLATION"));
|
|
break;
|
|
|
|
case OC_CLEANUP:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_CLEANUP"));
|
|
break;
|
|
|
|
case OCP_TEST_PRIVATE_BASE:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_TEST_PRIVATE_BASE"));
|
|
break;
|
|
|
|
case OCP_CHECK_NEEDS:
|
|
_tcscpy(praValue->tszAPICall, TEXT("OC_CHECK_NEEDS"));
|
|
break;
|
|
|
|
default:
|
|
_tcscpy(praValue->tszAPICall, TEXT("Unknown call"));
|
|
break;
|
|
}
|
|
|
|
//Now everything is ready, let's make the call
|
|
returnValue = DialogBoxParam(g_hDllInstance,
|
|
MAKEINTRESOURCE(IDD_CHOOSERETURNANDAV),
|
|
NULL,
|
|
ChooseReturnOrAVDlgProc,
|
|
(LPARAM)praValue);
|
|
|
|
praValue = (PReturnOrAV)returnValue;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description: BeginTest (1.0)
|
|
|
|
Let the user decide whether to test the return values of each API
|
|
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Whether to do extended test
|
|
--*/
|
|
BOOL BeginTest(){
|
|
static BOOL bStart = FALSE;
|
|
static BOOL bFirstTime = TRUE;
|
|
static int iMsgReturn;
|
|
|
|
TCHAR tszDlgMessage[256];
|
|
TCHAR tszDlgTitle[256];
|
|
|
|
if (bFirstTime){
|
|
bFirstTime = FALSE;
|
|
#ifdef UNICODE
|
|
_stprintf(tszDlgMessage, TEXT("Do you want to test return values and/or access violations of each API call in the UNICODE DLL? It may take a long long time"));
|
|
_stprintf(tszDlgTitle, TEXT("Begin Test For UNICODE?"));
|
|
#else
|
|
_stprintf(tszDlgMessage, TEXT("Do you want to test return values and/or access violations of each API call in the ANSI DLL? It may take a long long time"));
|
|
_stprintf(tszDlgTitle, TEXT("Begin Test For ANSI?"));
|
|
#endif
|
|
iMsgReturn = MessageBox(NULL, tszDlgMessage, tszDlgTitle, MB_YESNO|MB_ICONQUESTION);
|
|
|
|
if (iMsgReturn == IDNO){
|
|
bStart = FALSE;
|
|
return (FALSE);
|
|
}
|
|
else{
|
|
bStart = TRUE;
|
|
return (TRUE);
|
|
}
|
|
}
|
|
else{
|
|
return bStart;
|
|
}
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description: ChooseReturnOrAVDlgProc (1.27)
|
|
|
|
Dialog procedure that allows the user to select a different
|
|
return value of an API call, and/or to cause a access violation
|
|
|
|
Arguments:
|
|
|
|
Standard dialog procedure parameters
|
|
|
|
Return Value:
|
|
|
|
Standard dialog procedure return value
|
|
|
|
--*/
|
|
BOOL CALLBACK ChooseReturnOrAVDlgProc(IN HWND hwnd,
|
|
IN UINT uiMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
|
|
BOOL bSuccess = FALSE;
|
|
PReturnOrAV praValue = NULL;
|
|
static HWND hOldWnd = NULL;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
hOldWnd = hwnd;
|
|
CheckRadioButton(hwnd, IDC_USE_OLDVALUE, IDC_USE_NEWVALUE, IDC_USE_OLDVALUE);
|
|
CheckDlgButton(hwnd, IDC_CAUSEAV, 0);
|
|
|
|
praValue = (PReturnOrAV)lParam;
|
|
if (praValue){
|
|
if (praValue->tszComponent){
|
|
SetDlgItemText(hwnd, IDC_STATIC_COMPONENT, praValue->tszComponent);
|
|
}
|
|
else{
|
|
SetDlgItemText(hwnd, IDC_STATIC_COMPONENT, TEXT("null"));
|
|
}
|
|
if (praValue->tszSubComponent && praValue->tszSubComponent[0]!=TEXT('\0')){
|
|
SetDlgItemText(hwnd, IDC_STATIC_SUBCOMPONENT, praValue->tszSubComponent);
|
|
}
|
|
else{
|
|
SetDlgItemText(hwnd, IDC_STATIC_SUBCOMPONENT, TEXT("null"));
|
|
}
|
|
SetDlgItemText(hwnd, IDC_STATIC_APICALL, praValue->tszAPICall);
|
|
}
|
|
|
|
return TRUE;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
|
|
//
|
|
// Retrieve the current selection
|
|
//
|
|
if (QueryButtonCheck(hwnd, IDC_USE_NEWVALUE))
|
|
{
|
|
praValue->iReturnValue = GetDlgItemInt(hwnd, IDC_NEWVALUE, &bSuccess, TRUE);
|
|
if (bSuccess){
|
|
praValue->bOverride = TRUE;
|
|
}
|
|
else{
|
|
praValue->bOverride = FALSE;
|
|
praValue->iReturnValue = 0;
|
|
}
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_USE_OLDVALUE))
|
|
{
|
|
praValue->bOverride = FALSE;
|
|
praValue->iReturnValue = 0;
|
|
}
|
|
|
|
if (QueryButtonCheck(hwnd, IDC_CAUSEAV))
|
|
{
|
|
praValue->bOverride = FALSE;
|
|
praValue->iReturnValue = 0;
|
|
testAV(TRUE);
|
|
}
|
|
|
|
EndDialog(hOldWnd, (int)praValue);
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
|
|
praValue->bOverride = FALSE;
|
|
EndDialog(hOldWnd, 0);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
|
|
} // ChooseReturnOrAVDlgProc //
|
|
|
|
/*++
|
|
Routine: causeAV
|
|
|
|
Description: pops up a dialog box and ask the user where to av
|
|
|
|
Argument: Function that the DLL receives from ComponentSetupProc
|
|
|
|
--*/
|
|
|
|
void causeAV(IN UINT uiFunction){
|
|
static BOOL bFirstTime = TRUE;
|
|
static UINT uiFunctionToAV = 0;
|
|
|
|
if (bFirstTime) {
|
|
// Display dialog box, asks the user where to av
|
|
bFirstTime = FALSE;
|
|
|
|
uiFunctionToAV = DialogBoxParam(g_hDllInstance,
|
|
MAKEINTRESOURCE(IDD_DIALOG4),
|
|
NULL,
|
|
CauseAVDlgProc,
|
|
(LPARAM)NULL);
|
|
}
|
|
if (uiFunction == uiFunctionToAV) {
|
|
testAV(TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description: CauseAVDlgProc (1.26)
|
|
|
|
Dialog Procedure to allow the user to choose where to cause an access violation
|
|
|
|
Arguments:
|
|
|
|
Standard dialog procedure parameters
|
|
|
|
Return Value:
|
|
|
|
Standard dialog procedure return value
|
|
|
|
--*/
|
|
BOOL CALLBACK CauseAVDlgProc(IN HWND hwnd,
|
|
IN UINT uiMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
UINT uiFunction;
|
|
TCHAR tszFunctionName[256];
|
|
BOOL bSuccess;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
|
|
//
|
|
// Retrieve the current text in the edit box
|
|
//
|
|
GetDlgItemText(hwnd, IDC_FUNCTION, tszFunctionName, 255);
|
|
if (*tszFunctionName) {
|
|
uiFunction = GetOCFunctionName(tszFunctionName);
|
|
}
|
|
|
|
//
|
|
// Send the version chosen back to ChooseVersionEx
|
|
//
|
|
EndDialog(hwnd, uiFunction);
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hwnd, -1);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
|
|
} // CauseAVDlgProc //
|
|
|
|
UINT GetOCFunctionName(IN PTCHAR tszFunctionName){
|
|
|
|
// Now tszFunctionName should contains the function name that user wants to cause an AV
|
|
if (!_tcsicmp(tszFunctionName, TEXT("OC_PREINITIALIZE"))) {
|
|
return(OC_PREINITIALIZE);
|
|
}
|
|
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_INIT_COMPONENT"))) {
|
|
return(OC_INIT_COMPONENT);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUERY_STATE"))) {
|
|
return(OC_QUERY_STATE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_SET_LANGUAGE"))) {
|
|
return(OC_SET_LANGUAGE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUERY_IMAGE"))) {
|
|
return(OC_QUERY_IMAGE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_REQUEST_PAGES"))) {
|
|
return(OC_REQUEST_PAGES);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUERY_SKIP_PAGE"))) {
|
|
return(OC_QUERY_SKIP_PAGE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUERY_CHANGE_SEL_STATE"))) {
|
|
return(OC_QUERY_CHANGE_SEL_STATE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_CALC_DISK_SPACE"))) {
|
|
return(OC_CALC_DISK_SPACE);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUEUE_FILE_OPS"))) {
|
|
return(OC_QUEUE_FILE_OPS);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_NEED_MEDIA"))) {
|
|
return(OC_NEED_MEDIA);
|
|
}
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_QUERY_STEP_COUNT"))) {
|
|
return(OC_QUERY_STEP_COUNT);
|
|
}
|
|
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_ABOUT_TO_COMMIT_QUEUE"))) {
|
|
return(OC_ABOUT_TO_COMMIT_QUEUE);
|
|
}
|
|
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_COMPLETE_INSTALLATION"))) {
|
|
return(OC_COMPLETE_INSTALLATION);
|
|
}
|
|
|
|
else if (!_tcsicmp(tszFunctionName, TEXT("OC_CLEANUP"))) {
|
|
return(OC_CLEANUP);
|
|
}
|
|
else{
|
|
MessageBox(NULL, TEXT("Unknown Function"), TEXT("Test Routine"), MB_OK);
|
|
return(0);
|
|
}
|
|
|
|
}
|
|
|
|
void SetGlobalsFromINF(HINF hinfHandle){
|
|
PTCHAR tszOCTestSection = TEXT("OCTest");
|
|
PTCHAR tszAccessViolation = TEXT("AccessViolation");
|
|
PTCHAR tszNoWizard = TEXT("NoWizardPage");
|
|
TCHAR tszFunctionName[256];
|
|
int nRequiredBufferSize;
|
|
|
|
INFCONTEXT infContext;
|
|
|
|
BOOL bSuccess = TRUE;
|
|
|
|
TCHAR tszMsg[256];
|
|
|
|
int nError;
|
|
|
|
/*
|
|
bSuccess = SetupFindFirstLine(hinfHandle, tszOCTestSection, tszAccessViolation, &infContext);
|
|
|
|
if (bSuccess) {
|
|
#ifdef DEBUG
|
|
MessageBox(NULL, TEXT("AccessViolation Found in INF File"), TEXT("AccessViolation"), MB_OK);
|
|
#endif
|
|
g_bAccessViolation = TRUE;
|
|
bSuccess = SetupGetStringField(&infContext, 1, tszFunctionName, 255, &nRequiredBufferSize);
|
|
if (bSuccess) {
|
|
g_uiFunctionToAV = GetOCFunctionName(tszFunctionName);
|
|
}
|
|
}
|
|
*/
|
|
bSuccess = SetupFindFirstLine(hinfHandle, TEXT("OCTest"), TEXT("NoWizardPage"), &infContext);
|
|
|
|
if (bSuccess) {
|
|
#ifdef DEBUG
|
|
MessageBox(NULL, TEXT("NoWizard Found in INF File"), TEXT("NoWizard"), MB_OK);
|
|
#endif
|
|
g_bNoWizPage = TRUE;
|
|
}
|
|
else{
|
|
#ifdef DEBUG
|
|
nError = GetLastError();
|
|
MessageBox(NULL, TEXT("NoWizard NOT Found in INF File"), TEXT("NoWizard"), MB_OK);
|
|
_stprintf(tszMsg, TEXT("The Last Error value for SetupFIndFirstLine is %d"), nError);
|
|
MessageBox(NULL, tszMsg, TEXT("GetLastError"), MB_OK);
|
|
#endif
|
|
}
|
|
|
|
bSuccess = SetupFindFirstLine(hinfHandle, TEXT("OCTest"), TEXT("Reboot"), &infContext);
|
|
if (bSuccess) {
|
|
g_bReboot = TRUE;
|
|
}
|
|
}
|
|
|
|
void causeAVPerComponent(IN UINT uiFunction, IN LPCVOID lpcvComponentId){
|
|
|
|
PCOMPONENT_DATA pcdComponentData;
|
|
|
|
TCHAR tszMsg[256];
|
|
|
|
if (uiFunction != OC_PREINITIALIZE && uiFunction != OC_INIT_COMPONENT) {
|
|
pcdComponentData = LocateComponent(lpcvComponentId);
|
|
//MessageBox(NULL, TEXT("Component Found"), TEXT("Fount"), MB_OK);
|
|
if (pcdComponentData->bAccessViolation) {
|
|
//MessageBox(NULL, TEXT("It allows use to cause AV"), TEXT("Cause AV"), MB_OK);
|
|
if (pcdComponentData->uiFunctionToAV == uiFunction) {
|
|
//MessageBox(NULL, TEXT("Start to cause access violation"), TEXT("Starting"), MB_OK);
|
|
testAV(TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetDefaultMode(PCOMPONENT_DATA pcdComponentData){
|
|
BOOL bSuccess;
|
|
INFCONTEXT infContext;
|
|
TCHAR tszMode[256];
|
|
|
|
bSuccess = SetupFindFirstLine(pcdComponentData->hinfMyInfHandle,
|
|
TEXT("OCTest"),
|
|
TEXT("DefaultMode"),
|
|
&infContext);
|
|
if (bSuccess) {
|
|
//MessageBox(NULL, TEXT("DefaultMode= found in OCTest section"), TEXT("DefaultMode"), MB_OK);
|
|
bSuccess = SetupGetStringField(&infContext, 1, tszMode, 255, NULL);
|
|
if (bSuccess) {
|
|
//MessageBox(NULL, TEXT("The default Mode should be in the title"), tszMode, MB_OK);
|
|
if (!_tcscmp(tszMode, TEXT("TYPICAL"))) {
|
|
pcdComponentData->ocrHelperRoutines.SetSetupMode(pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
SETUPMODE_TYPICAL);
|
|
}
|
|
else if (!_tcscmp(tszMode, TEXT("MINIMAL"))) {
|
|
pcdComponentData->ocrHelperRoutines.SetSetupMode(pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
SETUPMODE_MINIMAL);
|
|
}
|
|
else if (!_tcscmp(tszMode, TEXT("LAPTOP"))) {
|
|
pcdComponentData->ocrHelperRoutines.SetSetupMode(pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
SETUPMODE_LAPTOP);
|
|
}
|
|
else if (!_tcscmp(tszMode, TEXT("CUSTOM"))) {
|
|
pcdComponentData->ocrHelperRoutines.SetSetupMode(pcdComponentData->ocrHelperRoutines.OcManagerContext,
|
|
SETUPMODE_CUSTOM);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*++
|
|
Routine description:
|
|
|
|
Go through the list of component list, determine
|
|
whether the initial states are valid for each of them
|
|
|
|
Argument:
|
|
|
|
None
|
|
|
|
Return value:
|
|
|
|
None (error will be logged)
|
|
|
|
--*/
|
|
|
|
void CheckInitialState()
|
|
{
|
|
double fn = 1.0;
|
|
|
|
UINT uiCurrentMode; // Current Mode of the setup
|
|
static BOOL bFirstTime = TRUE; // we only need to fill the above array once
|
|
|
|
PSUBCOMP pscSubcomponent = NULL;
|
|
|
|
PCOMPONENT_DATA pcdComponentData = NULL;
|
|
|
|
OCMANAGER_ROUTINES ocHelper;
|
|
|
|
int nLoop = 0;
|
|
|
|
INFCONTEXT infContext;
|
|
|
|
HINF hinfHandle;
|
|
|
|
TCHAR tszMsg[256];
|
|
|
|
BOOL bInitState;
|
|
BOOL bInitStateShouldBe;
|
|
|
|
// Get a handle to a component
|
|
// so that we can use the OC Manager
|
|
// helper routines
|
|
|
|
if (!g_pscHead) {
|
|
MessageBox(NULL, TEXT("The component list is empty"), TEXT("CheckInitialState"), MB_OK);
|
|
return;
|
|
}
|
|
|
|
pcdComponentData = LocateComponent(g_pscHead->tszComponentId);
|
|
|
|
if (!pcdComponentData) {
|
|
MessageBox(NULL, TEXT("Can not locate component"), TEXT("CheckInitialState"), MB_OK);
|
|
return;
|
|
}
|
|
|
|
ocHelper = pcdComponentData->ocrHelperRoutines;
|
|
|
|
// Get the current mode
|
|
|
|
uiCurrentMode = ocHelper.GetSetupMode(ocHelper.OcManagerContext);
|
|
|
|
|
|
// Now we will loop through each component
|
|
// and its initial state
|
|
|
|
|
|
for (pscSubcomponent = g_pscHead;
|
|
pscSubcomponent != NULL;
|
|
pscSubcomponent = pscSubcomponent->Next) {
|
|
|
|
// If this is the first time that this function is called
|
|
// array uiModeToBeOn[] should be filled in
|
|
|
|
if (bFirstTime) {
|
|
bFirstTime = FALSE;
|
|
|
|
for (nLoop = 0; nLoop < 4; nLoop++) {
|
|
pscSubcomponent->uiModeToBeOn[nLoop] = (UINT)(-1);
|
|
}
|
|
|
|
// Get the INF file handle
|
|
pcdComponentData = LocateComponent(pscSubcomponent->tszComponentId);
|
|
|
|
if (!pcdComponentData) {
|
|
MessageBox(NULL, TEXT("Can't locate a component"), TEXT("CheckInitialState"), MB_OK);
|
|
return;
|
|
}
|
|
|
|
hinfHandle = pcdComponentData->hinfMyInfHandle;
|
|
|
|
SetupFindFirstLine(hinfHandle, pscSubcomponent->tszSubcomponentId, TEXT("Modes"), &infContext);
|
|
|
|
pscSubcomponent->nNumMode = SetupGetFieldCount(&infContext);
|
|
|
|
for (nLoop = 1; nLoop < pscSubcomponent->nNumMode; nLoop++){
|
|
SetupGetIntField(&infContext, nLoop, &(pscSubcomponent->uiModeToBeOn[nLoop - 1]));
|
|
}
|
|
}
|
|
|
|
// Now get the initial state of this component
|
|
bInitState = ocHelper.QuerySelectionState(ocHelper.OcManagerContext,
|
|
pscSubcomponent->tszSubcomponentId,
|
|
OCSELSTATETYPE_ORIGINAL);
|
|
|
|
// Now determine what initial state this component should have
|
|
bInitStateShouldBe = FALSE;
|
|
for (nLoop = 0; nLoop < pscSubcomponent->nNumMode; nLoop++) {
|
|
if (pscSubcomponent->uiModeToBeOn[nLoop] == uiCurrentMode) {
|
|
// This component should be on
|
|
bInitStateShouldBe = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (bInitStateShouldBe != bInitState && bInitStateShouldBe){
|
|
// We got a problem here
|
|
Log(fn, SEV2, TEXT("%s has incorrect initial state"),
|
|
pscSubcomponent->tszSubcomponentId);
|
|
|
|
_stprintf(tszMsg, TEXT("%s should be on, but it is not"),
|
|
pscSubcomponent->tszSubcomponentId);
|
|
MessageBox(NULL, tszMsg, TEXT("CheckInitialState"), MB_OK);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Some security Stuff
|
|
// From NT Security FAQ
|
|
/*
|
|
BOOLEAN __stdcall InitializeChangeNotify(){
|
|
DWORD wrote;
|
|
fh = CreateFile("C:\\tmp\\pwdchange.out", GENERIC_WRITE,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH, 0);
|
|
WriteFile(fh, "InitializeChangeNotify started\n", 31, &wrote, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
LONG __stdcall PasswordChangeNotify(struct UNI_STRING *user, ULONG rid, struct UNI_STRING *passwd){
|
|
DWORD wrote;
|
|
WCHAR wbuf[200];
|
|
char buf[512];
|
|
char bufl[200];
|
|
DWORD len;
|
|
|
|
memcpy(wbuf, user->buff, user->len);
|
|
len = user->len / sizeof(WCHAR);
|
|
wbuf[len] = 0;
|
|
wcstombs(bufl, wbuf, 199);
|
|
sprintf(buf, "User = %s : ", bufl);
|
|
WriteFile(fh, buf, strlen(buf), &wrote, 0);
|
|
|
|
memcpy(wbuf, passwd->buff, passwd->len);
|
|
len = passwd->len / sizeof(WCHAR);
|
|
wbuf[len] = 0;
|
|
wcstombs(bufl, wbuf, 199);
|
|
sprintf(buf, "Password = %s : ", bufl);
|
|
WriteFile(fh, buf, strlen(buf), &wrote, 0);
|
|
|
|
sprintf(buf, "RID = %x \n", rid);
|
|
WriteFile(fh, buf, strlen(buf), &wrote, 0);
|
|
|
|
return 0L;
|
|
}
|
|
|
|
|
|
|
|
// End of security stuff
|
|
*/
|
|
|
|
// File number = 1
|
|
// Last function number = 47
|