/*++ 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