/****************************************************************************** * * * Tut_Mngr.cpp : definition of the low level functions of the * * TUT_CTutorialManager class * * * * This class can take the control of all windows of the application * * to create a tutorial or an automatic test * * * * Author : Alexis Vaisse * * * ******************************************************************************/ //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_csGetTreeCtrlItemText // Get the text of one item of a tree ctrl //----------------------------------------------------------------------------- CString TUT_CTutorialManager::m_fn_csGetTreeCtrlItemText (HWND _hTreeCtrl , HTREEITEM _hItem) { char szBuffer [256]; * szBuffer = 0; TV_ITEM Item; Item . mask = TVIF_TEXT; Item . hItem = _hItem; Item . pszText = szBuffer; Item . cchTextMax = 255; TreeView_GetItem (_hTreeCtrl , & Item); return szBuffer; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_uiGetTreeCtrlState // Get the state of one item of a tree ctrl //----------------------------------------------------------------------------- UINT TUT_CTutorialManager::m_fn_uiGetTreeCtrlState (HWND _hTreeCtrl , HTREEITEM _hItem , UINT _uiFlag) { TV_ITEM Item; Item . mask = TVIF_STATE; Item . hItem = _hItem; Item . stateMask = _uiFlag; TreeView_GetItem (_hTreeCtrl , & Item); return Item . state; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_hFindStringInTree // Recursiv function to find a string into a tree //----------------------------------------------------------------------------- HTREEITEM TUT_CTutorialManager::m_fn_hFindStringInTree (HWND _hTreeCtrl , HTREEITEM _hItem , CString _csText) { while (_hItem) { // Is it the good item ? if (m_fn_csGetTreeCtrlItemText (_hTreeCtrl , _hItem) == _csText) return _hItem; // Get the first child and recursiv call HTREEITEM _hChildItem = TreeView_GetChild (_hTreeCtrl , _hItem); if (_hChildItem) { HTREEITEM hResultItem = m_fn_hFindStringInTree (_hTreeCtrl , _hChildItem , _csText); if (hResultItem) return hResultItem; } // Get the next brother _hItem = TreeView_GetNextItem (_hTreeCtrl , _hItem , TVGN_NEXT); } return NULL; // Not found } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bIsItemVIsibleInTree // Return TRUE if an item is visible in a tree //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bIsItemVisibleInTree (HWND _hTreeCtrl , HTREEITEM _hItemToFind) { HTREEITEM hItem = TreeView_GetFirstVisible (_hTreeCtrl); while (hItem) { if (hItem == _hItemToFind) return TRUE; hItem = TreeView_GetNextVisible (_hTreeCtrl , hItem); } return FALSE; // Not found } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bSearchWndDefinition // Search a window name into the list //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bSearchWndDefinition (const CString _csName , int *_p_iIndex /* = NULL */) { int iMin = -1; int iMax = m_oArrayOfWnd . GetSize (); int iMiddle = (iMin + iMax) >> 1; int iComp; BOOL bFound = FALSE; TUT_tdstWndDefinition * p_stWndDefinition; while (iMax != iMin + 1) { p_stWndDefinition = m_oArrayOfWnd [iMiddle]; iComp = p_stWndDefinition -> csName . CompareNoCase (_csName); if (iComp == 0) // Found { if (_p_iIndex) * _p_iIndex = iMiddle; return TRUE; } else if (iComp == -1) { iMin = iMiddle; iMiddle = (iMin + iMax) >> 1; } else { iMax = iMiddle; iMiddle = (iMin + iMax) >> 1; } } // Not found : we set the position where to insert the new window if (_p_iIndex) * _p_iIndex = iMin; return FALSE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bSearchWndDefinition // Search a window name into the list //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bSearchWndDefinition (HWND _hWnd , int * _p_iIndex /*=NULL*/ ) { int iMin = 0; int iMax = m_oArrayOfWnd . GetSize (); int iIndex; TUT_tdstWndDefinition * p_stWndDefinition; for (iIndex = iMin ; iIndex < iMax ; iIndex ++) { p_stWndDefinition = m_oArrayOfWnd [iIndex]; if (p_stWndDefinition -> hWnd == _hWnd) // Found { if (_p_iIndex) * _p_iIndex = iIndex; return TRUE; } } // Not found : we set the position where to insert the new window if (_p_iIndex) * _p_iIndex = -1; return FALSE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fnp_stFindWndDefinition // Search a window name into the list //----------------------------------------------------------------------------- TUT_tdstWndDefinition * TUT_CTutorialManager::m_fnp_stFindWndDefinition (const CString _csName) { int iIndex; return m_fn_bSearchWndDefinition (_csName , & iIndex) ? m_oArrayOfWnd [iIndex] : NULL; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fnp_stFindWndDefinition // Search a window handle into the list //----------------------------------------------------------------------------- TUT_tdstWndDefinition * TUT_CTutorialManager::m_fnp_stFindWndDefinition (HWND _hWnd) { int iIndex; return m_fn_bSearchWndDefinition (_hWnd , & iIndex) ? m_oArrayOfWnd [iIndex] : NULL; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fnp_stFindLabel // Search a label name into the list //----------------------------------------------------------------------------- TUT_tdstLabelDefinition * TUT_CTutorialManager::m_fnp_stFindLabel (char * _szName) { int iCurrentContextNumber = m_oListOfContext . GetCount (); POSITION Pos = m_oListOfLabel . GetHeadPosition (); while (Pos) { TUT_tdstLabelDefinition * p_stLabelDef = m_oListOfLabel . GetNext (Pos); if (p_stLabelDef -> csName . CompareNoCase (_szName) == 0 && p_stLabelDef -> iContextNumber == iCurrentContextNumber) return p_stLabelDef; } return NULL; // Not found } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fnp_stFindVariable // Search a variable name into the list //----------------------------------------------------------------------------- TUT_tdstVariableDefinition * TUT_CTutorialManager::m_fnp_stFindVariable (char * _szName) { BOOL bDeclareVariable; if (* _szName == TUT_C_cDeclarationOfVariable) { bDeclareVariable = TRUE; _szName ++; } else bDeclareVariable = FALSE; int iCurrentContextNumber = m_oListOfContext . GetCount (); POSITION Pos = m_oListOfVariable . GetHeadPosition (); TUT_tdstVariableDefinition * p_stGlobalVariableDef = NULL; while (Pos) { TUT_tdstVariableDefinition * p_stVariableDef = m_oListOfVariable . GetNext (Pos); if (p_stVariableDef -> csName . CompareNoCase (_szName) == 0) // We have found a variable { if (p_stVariableDef -> iContextNumber == iCurrentContextNumber) // Is this variable a local variable ? { if (bDeclareVariable) return NULL; // Declaration of a already existing variable -> error else return p_stVariableDef; // Ok } else if (p_stVariableDef -> iContextNumber == 0) // Is this variable a global variable ? { p_stGlobalVariableDef = p_stVariableDef; } } } // Here, we have not found a local variable if (bDeclareVariable) { TUT_tdstVariableDefinition * p_stVariableDef = new TUT_tdstVariableDefinition; m_oListOfVariable . AddTail (p_stVariableDef); p_stVariableDef -> csName = _szName; p_stVariableDef -> csValue = ""; p_stVariableDef -> iContextNumber = iCurrentContextNumber; return p_stVariableDef; } else { if (p_stGlobalVariableDef) return p_stGlobalVariableDef; else return NULL; // Not found } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fnp_stFindOrCreateVariable // Search a variable name into the list. If it does not exist, create it //----------------------------------------------------------------------------- TUT_tdstVariableDefinition * TUT_CTutorialManager::m_fnp_stFindOrCreateVariable (char * _szName) { TUT_tdstVariableDefinition * p_stVariableDef = m_fnp_stFindVariable (_szName); if (p_stVariableDef == NULL) { p_stVariableDef = new TUT_tdstVariableDefinition; m_oListOfVariable . AddTail (p_stVariableDef); p_stVariableDef -> csName = _szName; p_stVariableDef -> csValue = ""; p_stVariableDef -> iContextNumber = m_oListOfContext . GetCount (); } return p_stVariableDef; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSetValueToVariable // Set a value to a variable //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSetValueToVariable (TUT_tdstVariableDefinition * _p_stVariableDef , long _lValue) { _p_stVariableDef -> csValue . Format ("%d" , _lValue); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSetGetLastError // Put an error number into the GetLastError' global variable //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSetGetLastError (long _lErrorNumber) { // Fill the GetLastError variable TUT_tdstVariableDefinition * p_stVariableDef = m_fnp_stFindOrCreateVariable (TUT_C_szGetLastError); m_fn_vSetValueToVariable (p_stVariableDef , _lErrorNumber); // Fill the GetLastErrorMessage variable char * szMessage; switch (_lErrorNumber) { case TUT_C_iNoError : szMessage = "No error"; break; case TUT_C_iError_ListBoxItemNotFound : szMessage = "Item not found in list box"; break; case TUT_C_iError_ComboBoxItemNotFound : szMessage = "Item not found in combo box"; break; case TUT_C_iError_ListCtrlItemNotFound : szMessage = "Item not found in list control"; break; case TUT_C_iError_ListBoxInvalidLine : szMessage = "Invalid line number in list box"; break; case TUT_C_iError_ComboBoxInvalidLine : szMessage = "Invalid line number in combo box"; break; case TUT_C_iError_ListCtrlInvalidLine : szMessage = "Invalid line number in list control"; break; case TUT_C_iError_TreeCtrlItemNotFound : szMessage = "Item not found in tree control"; break; case TUT_C_iError_SoundError : szMessage = "Wav file not found or sound error"; break; case TUT_C_iError_UnregisteredWindow : szMessage = "Unregistered window"; break; default : szMessage = NULL; break; } p_stVariableDef = m_fnp_stFindOrCreateVariable (TUT_C_szGetLastErrorMessage); if (szMessage) p_stVariableDef -> csValue = szMessage; else p_stVariableDef -> csValue . Format ("Unknown error code (%d)" , _lErrorNumber); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_iConvertToInt // Convert a string into an integer. Return TUT_C_iErrorNotANumber if error //----------------------------------------------------------------------------- int TUT_CTutorialManager::m_fn_iConvertToInt (char * _szString) { char * szEndOfNumber; long lValue = strtol (_szString , & szEndOfNumber , 10); if (* szEndOfNumber != 0) return TUT_C_iErrorNotANumber; return (int) lValue; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_iConvertToDouble // Convert a string into a double. Return TUT_C_dErrorNotANumber if error //----------------------------------------------------------------------------- double TUT_CTutorialManager::m_fn_dConvertToDouble (char * _szString) { char * szEndOfNumber; double dValue = strtod (_szString , & szEndOfNumber); if (* szEndOfNumber != 0) return TUT_C_dErrorNotANumber; return dValue; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bAreParametersEqual // Return TRUE if the two parameters are equal (can be integer, float or string) //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bAreParametersEqual (char * _szParameter1 , char * _szParameter2) { double dParameter1 = m_fn_dConvertToDouble (_szParameter1); BOOL bIsDouble1 = dParameter1 != TUT_C_dErrorNotANumber; double dParameter2 = m_fn_dConvertToDouble (_szParameter2); BOOL bIsDouble2 = dParameter2 != TUT_C_dErrorNotANumber; if (bIsDouble1 && bIsDouble2) return dParameter1 == dParameter2; else return stricmp (_szParameter1 , _szParameter2) == 0; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bIsParameter1LessThanParameter2 // Return TRUE if the first parameter is less than the seoncd parameter (can be integer, float or string) //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bIsParameter1LessThanParameter2 (char * _szParameter1 , char * _szParameter2) { double dParameter1 = m_fn_dConvertToDouble (_szParameter1); BOOL bIsDouble1 = dParameter1 != TUT_C_dErrorNotANumber; double dParameter2 = m_fn_dConvertToDouble (_szParameter2); BOOL bIsDouble2 = dParameter2 != TUT_C_dErrorNotANumber; if (bIsDouble1 && bIsDouble2) return dParameter1 < dParameter2; else return stricmp (_szParameter1 , _szParameter2) < 0; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bIsParameterTrue // Return if a parameter is TRUE or FALSE //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bIsParameterTrue (char * _szParameter , int * _p_iReturnValue) { * _p_iReturnValue = TUT_C_iNoError; if (stricmp (_szParameter , TUT_C_szTrue ) == 0) return TRUE; if (stricmp (_szParameter , TUT_C_szFalse) == 0) return FALSE; * _p_iReturnValue = TUT_C_iError_BooleanValueRequired; return FALSE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bIsTestVerified // Execute a test and return the result of this test //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bIsTestVerified (char * _szTestOperator , char * _szParameter1 , char * _szParameter2 , int * _p_iReturnValue) { BOOL bTestVerified; * _p_iReturnValue = TUT_C_iNoError; if (stricmp (_szTestOperator , "=") == 0 || stricmp (_szTestOperator , "==") == 0) bTestVerified = m_fn_bAreParametersEqual (_szParameter1 , _szParameter2); else if (stricmp (_szTestOperator , "<>") == 0 || stricmp (_szTestOperator , "!=") == 0) bTestVerified = ! m_fn_bAreParametersEqual (_szParameter1 , _szParameter2); else if (stricmp (_szTestOperator , "<") == 0) bTestVerified = m_fn_bIsParameter1LessThanParameter2 (_szParameter1 , _szParameter2); else if (stricmp (_szTestOperator , "<=") == 0) bTestVerified = ! m_fn_bIsParameter1LessThanParameter2 (_szParameter2 , _szParameter1); else if (stricmp (_szTestOperator , ">") == 0) bTestVerified = m_fn_bIsParameter1LessThanParameter2 (_szParameter2 , _szParameter1); else if (stricmp (_szTestOperator , ">=") == 0) bTestVerified = ! m_fn_bIsParameter1LessThanParameter2 (_szParameter1 , _szParameter2); else { bTestVerified = FALSE; * _p_iReturnValue = TUT_C_iError_TestOperatorRequired; } return bTestVerified; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bMustActionBeExecuted // Return if the current action must be executed //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bMustActionBeExecuted () { // Not inside a test -> no problem if (m_oListOfTest . GetCount () == 0) return TRUE; TUT_tdstTestDefinition * p_stTestDef = m_oListOfTest . GetHead (); // Return TRUE if test verified XOR we are in the else block return p_stTestDef -> bTestVerified ^ p_stTestDef -> ePositionInTest == TUT_eAfterElse; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vAddAnActionForTheTest // Called each time an action is executed //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vAddAnActionForTheTest () { // Not inside a test -> nothing to do if (m_oListOfTest . GetCount () == 0) return; TUT_tdstTestDefinition * p_stTestDef = m_oListOfTest . GetHead (); if (p_stTestDef -> ePositionInTest == TUT_eAfterIf) p_stTestDef -> ePositionInTest = TUT_eBeforeElse; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vATestRightButtonDoubleClicAndPosition // These five flags must be set to FALSE after one action //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vTestRightButtonDoubleClicAndPosition () { static BOOL sbPreviousValueUseRightButton = FALSE; static BOOL sbPreviousValueUseDoubleClic = FALSE; static BOOL sbPreviousValueUsePosition = FALSE; static BOOL sbPreviousValueUseDrag = FALSE; static BOOL sbPreviousValueUseDrop = FALSE; if (sbPreviousValueUseRightButton) m_bUseRightButton = FALSE; if (sbPreviousValueUseDoubleClic ) m_bUseDoubleClic = FALSE; if (sbPreviousValueUsePosition ) m_bUsePosition = FALSE; if (sbPreviousValueUseDrag ) m_bUseDrag = FALSE; if (sbPreviousValueUseDrop ) m_bUseDrop = FALSE; sbPreviousValueUseRightButton = m_bUseRightButton; sbPreviousValueUseDoubleClic = m_bUseDoubleClic; sbPreviousValueUsePosition = m_bUsePosition; sbPreviousValueUseDrag = m_bUseDrag; sbPreviousValueUseDrop = m_bUseDrop; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vClearAllList // Clear the list used by the class //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vClearAllList (BOOL _bUnregisterControl) { if (_bUnregisterControl) { for (int iIndex = m_oArrayOfWnd . GetSize() - 1 ; iIndex >= 0 ; iIndex --) delete m_oArrayOfWnd [iIndex]; m_oArrayOfWnd . RemoveAll (); } int iNumber; iNumber = 0; while (m_oListOfVariable . GetCount ()) { TUT_tdstVariableDefinition *p_stVarDef = m_oListOfVariable . RemoveHead (); delete p_stVarDef; iNumber ++; } iNumber = 0; while (m_oListOfLoop . GetCount ()) { TUT_tdstLoopDefinition *p_stLoopDef = m_oListOfLoop . RemoveHead (); delete p_stLoopDef; iNumber ++; } iNumber = 0; while (m_oListOfTest . GetCount ()) { TUT_tdstTestDefinition *p_stTestDef = m_oListOfTest . RemoveHead (); iNumber ++; delete p_stTestDef; } iNumber = 0; while (m_oListOfLabel . GetCount ()) { TUT_tdstLabelDefinition *p_stLabelDef = m_oListOfLabel . RemoveHead (); delete p_stLabelDef; iNumber ++; } // Reset the variables m_iNumberOfParameter = 0; m_iNumberOfResult = 0; m_bInsideAGoto = FALSE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vPreprocessString // Remove spaces, tab and quotes at the beginning and the end of the string // Remplace variable name by its value. Return FALSE if error //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_vPreprocessString (char * & _szString) { if (_szString == NULL || * _szString == 0) return TRUE;; // Remove spaces and tab at the beginning of the string while (* _szString == ' ' || * _szString == '\t') _szString ++; // Remove spaces and tab at the end of the string char * p = _szString + strlen (_szString) - 1; // Points to the last character of the string while (* _szString != 0 && (* p == ' ' || * p == '\t')) * (p--) = 0; // Check if it is a variable name int iNbVariable = 0; while (* _szString == TUT_C_cBeginningOfVariable) { _szString ++; iNbVariable ++; } if (iNbVariable) { while (iNbVariable --) { TUT_tdstVariableDefinition * p_stVariableDef = m_fnp_stFindVariable (_szString); if (p_stVariableDef) _szString = (char *) (LPCTSTR) p_stVariableDef -> csValue; else return FALSE; // Use of an unknown variable -> error } return TRUE; } // Remove quote at the beginning of the string if (* _szString == '"') _szString ++; // Remove quote at the end of the string if (* _szString != 0 && * p == '"') * p = 0; return TRUE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_szStrtok // same as strtok but don't stop at delimiter inside quote //----------------------------------------------------------------------------- char * TUT_CTutorialManager::m_fn_szStrtok (char * _szString , char _cDelimiter) { static char * p = NULL; if (_szString != NULL) p = _szString; // in both cases, else { if (p == NULL) return NULL; else p ++; // p points to the first character } char * szReturnValue = p; if (* szReturnValue == 0) return NULL; // end of the string -> return NULL BOOL bInsideQuote = FALSE; while (* p != 0 && (* p != _cDelimiter || bInsideQuote)) // Find delimiter or end of string { if (* p == '\"') bInsideQuote = ! bInsideQuote; p ++; } if (* p != 0) * p = 0; // Put 0 instead of a delimiter else p = NULL; // Eof of the string return szReturnValue; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_iGetParameters // Split a string into a variable number of parameters. Return 0 if no error //----------------------------------------------------------------------------- int TUT_CTutorialManager::m_fn_iGetParameters (char * _szString , int _iMinNumberOfParameter , int _iMaxNumberOfParameter , int * _p_iNumberOfParameter , ...) { va_list Marker; va_start (Marker, _p_iNumberOfParameter); // Initialize variable arguments * _p_iNumberOfParameter = 0; char * szParameter = m_fn_szStrtok (_szString , ','); while (szParameter != NULL) { (* _p_iNumberOfParameter) ++; if (* _p_iNumberOfParameter > _iMaxNumberOfParameter) return TUT_C_iError_TooManyParameters; char * * p_szParameter = va_arg (Marker , char * *); // Get the next argument if (! m_fn_vPreprocessString (szParameter)) return TUT_C_iError_UnknownVariable; * p_szParameter = m_fn_szHandleQuote (szParameter); szParameter = m_fn_szStrtok (NULL , ','); } va_end (Marker); if (* _p_iNumberOfParameter < _iMinNumberOfParameter) return TUT_C_iError_ParameterRequired; return TUT_C_iNoError; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vPumpMessage // Dispatch messages //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vPumpMessage () { MSG Msg; while (PeekMessage (& Msg , NULL , 0 , 0 , PM_REMOVE)) DispatchMessage (& Msg); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSleep // Wait for the given duration (in millisecond) //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSleep (int _iDuration) { BOOL bLeftKeyPressed = (GetAsyncKeyState (VK_LSHIFT) & 0x8000) && (GetAsyncKeyState (VK_LCONTROL) & 0x8000); m_fn_vPumpMessage (); while (_iDuration > 0) { int iDelta = min (50 , _iDuration); _iDuration -= iDelta; // Are the control and shift keys pressed ? if ((GetAsyncKeyState (VK_RCONTROL) & 0x8000) && (GetAsyncKeyState (VK_RSHIFT) & 0x8000)) return; // Is the 'Escape' key pressed ? if ((GetAsyncKeyState (VK_ESCAPE) & 0x8000)) return; if (bLeftKeyPressed) { if ((GetAsyncKeyState (VK_LSHIFT) & 0x8000) == 0 && (GetAsyncKeyState (VK_LCONTROL) & 0x8000) == 0) bLeftKeyPressed = FALSE; } else { if ((GetAsyncKeyState (VK_LSHIFT) & 0x8000) && (GetAsyncKeyState (VK_LCONTROL) & 0x8000)) return; } Sleep (iDelta); m_fn_vPumpMessage (); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vActivateWindow // Activate a window and its parent (recursiv call) //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vActivateWindow (HWND _hWnd) { SetForegroundWindow (_hWnd); UpdateWindow (_hWnd); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_hOpenUserWindow // Open one user window (a rich edit control inside a frame) and return its handle //----------------------------------------------------------------------------- HWND TUT_CTutorialManager::m_fn_hOpenUserWindow (char * _szWindowName , int _iLeft , int _iTop , int _iRight , int _iBottom) { // Compute the size of the frame to create CRect ScreenPos; GetWindowRect (GetDesktopWindow () , & ScreenPos); CRect WindowPos; WindowPos . left = ScreenPos . right * _iLeft / 100; WindowPos . right = ScreenPos . right * _iRight / 100; WindowPos . top = ScreenPos . bottom * _iTop / 100; WindowPos . bottom = ScreenPos . bottom * _iBottom / 100; // Create a new class for the frame LPCTSTR lpszSmartClass = AfxRegisterWndClass (CS_HREDRAW | CS_VREDRAW , LoadCursor (NULL, IDC_ARROW) , (HBRUSH) (COLOR_WINDOW + 1)); // Create the frame window HWND hWnd = CreateWindowEx (WS_EX_TOPMOST | WS_EX_TOOLWINDOW , lpszSmartClass , _szWindowName , WS_POPUP | WS_BORDER | WS_CAPTION | WS_VISIBLE , WindowPos . left , WindowPos . top , WindowPos . Width () , WindowPos . Height () , NULL /* No parent to avoid problem */ , NULL , AfxGetInstanceHandle () , NULL); if (hWnd == NULL) { DWORD dwError = GetLastError (); ASSERT (0); } // Create a text view CRect ClientRect; GetClientRect (hWnd , & ClientRect); HWND hEditView = CreateWindowEx (WS_EX_LEFT , "RichEdit" , "" , WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE , ClientRect . left , ClientRect . top , ClientRect . Width () , ClientRect . Height () , hWnd , NULL , AfxGetInstanceHandle () , NULL); if (hEditView == NULL) { DWORD dwError = GetLastError (); ASSERT (0); } SendMessage (hEditView , EM_SETREADONLY , TRUE , 0); return hEditView; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vCloseUserWindow // Close one user window //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vCloseUserWindow (int _iIndex) { TUT_tdstWndDefinition * p_stWndDefinition = m_oArrayOfWnd [_iIndex]; HWND hWindow = p_stWndDefinition -> hWnd; HWND hParent = GetParent (hWindow); ASSERT (hParent); DestroyWindow (hWindow); DestroyWindow (hParent); m_oArrayOfWnd . RemoveAt (_iIndex); delete p_stWndDefinition; if (m_p_stCurrentUserWindow == p_stWndDefinition) m_p_stCurrentUserWindow = NULL; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vCloseAllUserWindow // Close all open user windows //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vCloseAllUserWindow () { for (int iIndex = m_oArrayOfWnd . GetSize () - 1 ; iIndex >= 0 ; iIndex --) { TUT_tdstWndDefinition * p_stWndDefinition = m_oArrayOfWnd [iIndex]; if (p_stWndDefinition -> eType == TUT_eUserWindow) m_fn_vCloseUserWindow (iIndex); } if (m_hDebugWnd) { DestroyWindow (m_hDebugWnd); m_hDebugWnd = NULL; } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vDeleteLocalLabelAndVariable // Delete all local labels and variables //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vDeleteLocalLabelAndVariable () { int iCurrentContextNumber = m_oListOfContext . GetCount (); POSITION Pos = m_oListOfVariable . GetHeadPosition (); while (Pos) { POSITION SavePos = Pos; TUT_tdstVariableDefinition * p_stVariableDef = m_oListOfVariable . GetNext (Pos); if (p_stVariableDef -> iContextNumber == iCurrentContextNumber) { m_oListOfVariable . RemoveAt (SavePos); delete p_stVariableDef; } } Pos = m_oListOfLabel . GetHeadPosition (); while (Pos) { POSITION SavePos = Pos; TUT_tdstLabelDefinition * p_stLabelDef = m_oListOfLabel . GetNext (Pos); if (p_stLabelDef -> iContextNumber == iCurrentContextNumber) { m_oListOfLabel . RemoveAt (SavePos); delete p_stLabelDef; } } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vCloseLogFile // Close the given log file if it is open //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vCloseLogFile (TUT_tdstLogFileDefinition * _p_stLogFile) { if (_p_stLogFile -> bOpen) { fclose (_p_stLogFile -> pFile); _p_stLogFile -> bOpen = FALSE; _p_stLogFile -> csName = ""; _p_stLogFile -> pFile = NULL; } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vCloseAllLogFiles // Close the given log file if it is open //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vCloseAllLogFiles () { m_fn_vCloseLogFile (& m_stLogFile); m_fn_vCloseLogFile (& m_stDebugLogFile); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bFindColor // Find RGB code of the given color name. Return FALSE if not found //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bFindColor (char * _szColorName , COLORREF * _p_xColor) { const TUT_tdstColorDefinition * p = g_a_stColorDefinition; while (p -> szColorName) { if (stricmp (p -> szColorName , _szColorName) == 0) { * _p_xColor = p -> xColor; return TRUE; } p ++; } return FALSE; // Not found } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_iFindVirtualKeyCode // Find a virtual key code with the given name. Return 0 if not found //----------------------------------------------------------------------------- int TUT_CTutorialManager::m_fn_iFindVirtualKeyCode (char * _szVirtualKeyCode) { if (strlen (_szVirtualKeyCode) == 1) { char cChar = (char) toupper (* _szVirtualKeyCode); if (cChar >= 'A' && cChar <= 'Z') return cChar; } int i = -1; char * szKeyName; do { szKeyName = TUT_cgs_a_stKeyConversionTable [++ i] . szKeyName; if (szKeyName == NULL) return 0; // End of the list : not found -> return 0; } while (stricmp (szKeyName , _szVirtualKeyCode) != 0); return TUT_cgs_a_stKeyConversionTable [i] . iVirtualKeyCode; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_iFindIdForMessageMox // Find RGB code of the given color name. Return FALSE if not found //----------------------------------------------------------------------------- int TUT_CTutorialManager::m_fn_iFindIdForMessageBox (char * _szControlName) { if (stricmp (_szControlName , TUT_C_szOk ) == 0) return IDOK; if (stricmp (_szControlName , TUT_C_szCancel) == 0) return IDCANCEL; if (stricmp (_szControlName , TUT_C_szAbort ) == 0) return IDABORT; if (stricmp (_szControlName , TUT_C_szRetry ) == 0) return IDRETRY; if (stricmp (_szControlName , TUT_C_szIgnore) == 0) return IDIGNORE; if (stricmp (_szControlName , TUT_C_szYes ) == 0) return IDYES; if (stricmp (_szControlName , TUT_C_szNo ) == 0) return IDNO; return 0; // Not found } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_szGetWndNameType // Return the name of the given window type //----------------------------------------------------------------------------- char * TUT_CTutorialManager::m_fn_szGetWndNameType (TUT_tdeWndType _eType) { switch (_eType) { case TUT_eWindow : return "Window"; case TUT_eMdiWindow : return "Mdi window"; case TUT_eButton : return "Button"; case TUT_eTextEdit : return "Text edit"; case TUT_eListBox : return "List box"; case TUT_eComboBox : return "Combo box"; case TUT_eTreeCtrl : return "Tree control"; case TUT_eListCtrl : return "List control"; case TUT_eSpin : return "Spin"; case TUT_eSlider : return "Slider"; case TUT_eScrollBar : return "Scrollbar"; case TUT_eUserWindow : return "User window"; case TUT_e3DView : return "3DView"; default : ASSERT (0); return NULL; } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vShowError // Open a message box with a message associated to the given error code //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vShowError (int _iErrorCode , const CString _csFileName , int _iLineNumber , char * _szLine) { CString csMessage; if (_iErrorCode == TUT_C_iError_FileNotFound) csMessage . Format ("File not found : %s" , _csFileName); else { CString csText; switch (_iErrorCode) { case TUT_C_iError_UnknownCommand : csText = "Unknown command"; break; case TUT_C_iError_TooManyParameters : csText = "Too many parameters"; break; case TUT_C_iError_ParameterRequired : csText = "More parameters are required"; break; case TUT_C_iError_UnknownButton : csText = "Unknown button name"; break; case TUT_C_iError_ButtonRequired : csText = "The control is not a button"; break; case TUT_C_iError_InvalidCoordinates : csText = "Coordinates are not valid"; break; case TUT_C_iError_NoWindowToWriteText : csText = "No open window to write text"; break; case TUT_C_iError_InvalidNumber : csText = "Invalid number"; break; case TUT_C_iError_UnknownTextEdit : csText = "Unknown text edit name"; break; case TUT_C_iError_TextEditRequired : csText = "The control is not a text edit"; break; case TUT_C_iError_UnknownWindow : csText = "Unknown window name"; break; case TUT_C_iError_UnknownComboBox : csText = "Unknown combo box name"; break; case TUT_C_iError_ListOrComboRequired : csText = "The control must be a combo box, a list box or a list control"; break; case TUT_C_iError_UnknownMdiWindow : csText = "Unknown mdi window name"; break; case TUT_C_iError_MdiWindowRequired : csText = "The control is not a mdi window"; break; case TUT_C_iError_UnknownColor : csText = "Unknown color name"; break; case TUT_C_iError_UnknownControl : csText = "Unknown control name"; break; case TUT_C_iError_SelectCtrlRequired : csText = "The control is not a control with selection"; break; case TUT_C_iError_InvalidTextAlignment : csText = "Invalid text alignment"; break; case TUT_C_iError_UnknownTreeBox : csText = "Unknown tree box name"; break; case TUT_C_iError_TreeBoxRequired : csText = "The control is not a tree box"; break; case TUT_C_iError_FunctionNotCompiled : csText = "Not compiled function"; break; case TUT_C_iError_Unknown3dObject : csText = "Unknown 3d object"; break; case TUT_C_iError_NoMenuAvailable : csText = "No menu available"; break; case TUT_C_iError_UnknownMenuName : csText = "Unknown menu name"; break; case TUT_C_iError_NotASubMenu : csText = "Not a sub menu"; break; case TUT_C_iError_EndLoopWithoutLoop : csText = "'EndLoop' without a 'Loop'"; break; case TUT_C_iError_TestOperatorRequired : csText = "A test operator is required"; break; case TUT_C_iError_OrIfWithoutAnIf : csText = "'OrIf' without an 'If'"; break; case TUT_C_iError_ElseWithoutAnIf : csText = "'Else' without an 'If'"; break; case TUT_C_iError_ElseInTheWrongPlace : csText = "Incorrect 'Else'"; break; case TUT_C_iError_EndIfWithoutAnIf : csText = "'EndIf' without an 'If'"; break; case TUT_C_iError_DebugWndAlreadyOpen : csText = "The debug window is already open"; break; case TUT_C_iError_DebugWndNotOpen : csText = "The debug window is not open"; break; case TUT_C_iError_InvalidMdiHandle : csText = "Invalid handle to a MDI window"; break; case TUT_C_iError_InvalidParentMdiHandle : csText = "Invalid handle to a parent of a MDI window"; break; case TUT_C_iError_InvalidListBoxHandle : csText = "Invalid handle to a list box"; break; case TUT_C_iError_InvalidComboBoxHandle : csText = "Invalid handle to a combo box"; break; case TUT_C_iError_InvalidTreeBoxHandle : csText = "Invalid handle to a tree box"; break; case TUT_C_iError_InvalidMenuHandle : csText = "Invalid menu handle"; break; case TUT_C_iError_InvalidMenuWndHandle : csText = "Invalid handle to a menu owner"; break; case TUT_C_iError_InvalidButtonHandle : csText = "Invalid handle to a button"; break; case TUT_C_iError_InvalidTextEditHandle : csText = "Invalid handle to a text edit"; break; case TUT_C_iError_WindowOrMdiRequired : csText = "The control is not a window or a MDI window"; break; case TUT_C_iError_InvalidWndOrMdiHandle : csText = "Invalid handle to a window or a MDI window"; break; case TUT_C_iError_CtrlWithTextRequired : csText = "This type of control has no text"; break; case TUT_C_iError_InvalidHandle : csText = "Invalid handle"; break; case TUT_C_iError_BooleanValueRequired : csText = "A boolean value is required"; break; case TUT_C_iError_ItemNotFoundInTree : csText = "The item was not found in the tree"; break; case TUT_C_iError_ItemHasNoChild : csText = "The item has no child"; break; case TUT_C_iError_InvalidChildNumber : csText = "Invalid child number"; break; case TUT_C_iError_NotANumericVariable : csText = "A numeric variable is required"; break; case TUT_C_iError_DivisionByZero : csText = "Division by zero"; break; case TUT_C_iError_EmptyVariable : csText = "A not-empty variable is required"; break; case TUT_C_iError_LogFileAlreadyOpen : csText = "A log file is already open"; break; case TUT_C_iError_UnableToOpenLogFile : csText = "Unable to open the log file"; break; case TUT_C_iError_LogFileNotOpen : csText = "The log file is not open"; break; case TUT_C_iError_InvalidXBorder : csText = "'Left' or 'Right' is required"; break; case TUT_C_iError_InvalidYBorder : csText = "'Top' or 'Bottom' is required"; break; case TUT_C_iError_InvalidNumberOrPercent : csText = "Invalid number or percentage"; break; case TUT_C_iError_InvalidListCtrlHandle : csText = "Invalid handle to a list control"; break; case TUT_C_iError_LabelsWithSameName : csText = "This name is already used by another label"; break; case TUT_C_iError_LabelNotFound : csText = "Label not found"; break; case TUT_C_iError_ModelNotFound : csText = "Model not found"; break; case TUT_C_iError_DragAtTheWrongPlace : csText = "'Drag' at the wrong place"; break; case TUT_C_iError_DropAtTheWrongPlace : csText = "'Drop' at the wrong place"; break; case TUT_C_iError_InvisibleControl : csText = "Use of an invisible control"; break; case TUT_C_iError_DisabledControl : csText = "Use of a disabled control"; break; case TUT_C_iError_NoMultipleSelection : csText = "The list is not a multiple selection list"; break; case TUT_C_iError_UnknownListBox : csText = "Unknown list box name"; break; case TUT_C_iError_ListBoxRequired : csText = "The control is not a list box"; break; case TUT_C_iError_UnknownObject : csText = "Unknown object name"; break; case TUT_C_iError_UnknownVariable : csText = "Unknown variable name or variable already declared";break; case TUT_C_iError_CountCtrlRequired : csText = "A list box, list control or combo box is required"; break; case TUT_C_iError_UnknownMessageBoxCtrl : csText = "Unknown message box control name"; break; case TUT_C_iError_MessageBoxCtrlNotFound : csText = "Message box control not found"; break; case TUT_C_iError_NoReturnValue : csText = "There is no return value"; break; case TUT_C_iError_UnknownKey : csText = "Unknown key name"; break; case TUT_C_iError_MultiLineRequired : csText = "The text edit is not multi-line"; break; case TUT_C_iError_InvalidLineNumber : csText = "Invalid line number"; break; case TUT_C_iError_LocalVariableExist : csText = "A local variable with the same name already exists";break; case TUT_C_iError_GlobalVariableExist : csText = "A global variable with the same name already exists";break; case TUT_C_iError_ListViewRequired : csText = "A List View control is required"; break; case TUT_C_iError_UncoherentSelectionLimits : csText = "Limits of selection are incoherent"; break; default : csText . Format ("Unknown error : code = %d" , _iErrorCode); break; } if (_iErrorCode == TUT_C_iError_LabelNotFound) csMessage . Format ("Error n° %d in file '%s' : %s (%s)" , _iErrorCode , _csFileName , csText , m_csLabelToFind); else csMessage . Format ("Error n° %d in file '%s' : %s (line %d : '%s')" , _iErrorCode , _csFileName , csText , _iLineNumber , _szLine); } // Give the focus to the tutorial thread if (m_p_stCurrentUserWindow) SetForegroundWindow (m_p_stCurrentUserWindow -> hWnd); MessageBox (NULL , csMessage , "Tutorial manager" , MB_OK + MB_ICONSTOP + MB_TASKMODAL); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vMoveMouseCursor // Move the mouse cursor to the destination point // Duration is in millisecond, speed in pixel/second and acceleration in pixel/secondē //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vMoveMouseCursor (CPoint _stDestination, HWND _hWnd /*=NULL*/) { long lMaxDuration = m_lCurrentMaxDuration; long lMinSpeed = m_lCurrentMinSpeed; long lAcceleration = m_lCurrentAcceleration; CPoint stCurrentMousePos; GetCursorPos (& stCurrentMousePos); CPoint stDelta = _stDestination - stCurrentMousePos; long lCurrentDistance = (long) sqrt ((double) (stDelta . x * stDelta . x + stDelta . y * stDelta . y)); long lOptimumSpeed = lCurrentDistance * 1000 / lMaxDuration; if (lOptimumSpeed < lMinSpeed) lOptimumSpeed = lMinSpeed; long lCurrentSpeed = 0; const long lDeltaT = m_bUseDrop ? 30 : 10; // one move every 10 milliseconds long lTime = 0; while (stCurrentMousePos != _stDestination && lTime < lMaxDuration) { long lDistanceToStop = lCurrentSpeed * lCurrentSpeed / 2 / lAcceleration; long lCurrentAcceleration; // breake ? if (lCurrentDistance <= lDistanceToStop * 1100 / 1000) lCurrentAcceleration = - lAcceleration; else // accelerate ? if (lCurrentSpeed < lOptimumSpeed * 1300 / 1000) lCurrentAcceleration = lAcceleration; else lCurrentAcceleration = 0; lCurrentSpeed += lCurrentAcceleration * lDeltaT / 1000; POINT stTranslation; stTranslation . x = lDeltaT * lCurrentSpeed * stDelta . x / lCurrentDistance / 1000; stTranslation . y = lDeltaT * lCurrentSpeed * stDelta . y / lCurrentDistance / 1000; if (stTranslation . x == 0) { if (stCurrentMousePos . x < _stDestination . x) stTranslation . x = 1; else if (stCurrentMousePos . x > _stDestination . x) stTranslation . x = -1; } if (stTranslation . y == 0) { if (stCurrentMousePos . y < _stDestination . y) stTranslation . y = 1; else if (stCurrentMousePos . y > _stDestination . y) stTranslation . y = -1; } stCurrentMousePos . x += stTranslation . x; stCurrentMousePos . y += stTranslation . y; SetCursorPos (stCurrentMousePos .x , stCurrentMousePos . y); if (_hWnd) { CPoint stLocalMousePos = stCurrentMousePos; ScreenToClient (_hWnd , & stLocalMousePos); PostMessage (_hWnd , WM_MOUSEMOVE , 0 , MAKELPARAM (stLocalMousePos . x , stLocalMousePos . y) ); } m_fn_vSleep (lDeltaT); lTime += lDeltaT; GetCursorPos (& stCurrentMousePos); stDelta = _stDestination - stCurrentMousePos; lCurrentDistance = (long) sqrt ((double) (stDelta . x * stDelta . x + stDelta . y * stDelta . y)); } SetCursorPos (_stDestination . x , _stDestination . y); if (_hWnd) { CPoint stLocalMousePos = _stDestination; ScreenToClient (_hWnd , & stLocalMousePos); PostMessage (_hWnd , WM_MOUSEMOVE , 0 , MAKELPARAM (stLocalMousePos . x , stLocalMousePos . y) ); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vMoveMouseCursor // Move the mouse cursor to the center of the given window //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vMoveMouseCursor (HWND _hWnd) { CRect WindowPos; GetWindowRect (_hWnd , & WindowPos); m_fn_vMoveMouseCursor (WindowPos . CenterPoint ()); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vClickOnControl // Simulate a click on a control //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vClickOnControl (HWND _hControl) { // Get the center of the control CRect Rect; GetClientRect (_hControl , & Rect); LPARAM lParam = MAKELPARAM (Rect . CenterPoint () . x , Rect . CenterPoint () . y); UINT uiMsgDown; UINT uiMsgUp; UINT uiMsgDblClk; WPARAM wParam,wButton; if (m_bUseRightButton) { uiMsgDown = WM_RBUTTONDOWN; uiMsgUp = WM_RBUTTONUP; uiMsgDblClk = WM_RBUTTONDBLCLK; wButton = MK_RBUTTON; } else { uiMsgDown = WM_LBUTTONDOWN; uiMsgUp = WM_LBUTTONUP; uiMsgDblClk = WM_LBUTTONDBLCLK; wButton = MK_LBUTTON; } wParam = (m_bUseShift ? MK_SHIFT : 0) + (m_bUseControl ? MK_CONTROL : 0); m_fn_vSleep (60); PostMessage (_hControl , uiMsgDown , wParam | wButton, lParam); // Clic on the button m_fn_vSleep (60); if (m_bUseDoubleClic) { PostMessage (_hControl , uiMsgUp , wParam , lParam); m_fn_vSleep (60); PostMessage (_hControl , uiMsgDblClk , wParam | wButton, lParam); m_fn_vSleep (60); } PostMessage (_hControl , uiMsgUp , wParam , lParam); // Release the button m_fn_vSleep (60); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSetTextInEdit // Simulate an edition of text, //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSetTextInEdit (HWND _hTextEdit , const CString _csText) { HWND hParent = GetParent (_hTextEdit); for (int i = 1 ; i <= _csText . GetLength () ; i ++) { SetWindowText (_hTextEdit , _csText . Left (i)); SendMessage (_hTextEdit , EM_SETSEL , i , i); // Put the caret at the end of the line InvalidateRect (_hTextEdit , NULL , FALSE); UpdateWindow (_hTextEdit); SendMessage (_hTextEdit , EM_SETMODIFY , TRUE , 0); if (_csText [i - 1] != ' ') m_fn_vSleep (m_iDurationBetweenKeys); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSelectLineInComboBox // Simulate a selection into a combo box //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSelectLineInComboBox (HWND _hComboBox , int _iLineNumber) { m_fn_vSetGetLastError (TUT_C_iNoError); int iComboBoxGetCount = SendMessage (_hComboBox , CB_GETCOUNT , 0 , 0); if (_iLineNumber < 1 || _iLineNumber > iComboBoxGetCount) { m_fn_vSetGetLastError (TUT_C_iError_ComboBoxInvalidLine); return; } SendMessage (_hComboBox , CB_SHOWDROPDOWN , TRUE , 0); // To be sure the line will be visible CRect stListRect; SendMessage (_hComboBox , CB_GETDROPPEDCONTROLRECT , 0 , (LPARAM) & stListRect); int iTopIndex = SendMessage (_hComboBox , CB_GETTOPINDEX , 0 , 0); int iItemRect = SendMessage (_hComboBox , CB_GETITEMHEIGHT , 0 , 0); int iNumberOfVisibleItem = stListRect . Height () / iItemRect - 2; if (_iLineNumber - 1 < iTopIndex) SendMessage (_hComboBox , CB_SETTOPINDEX , _iLineNumber - 1 , 0); else if (_iLineNumber - 1 > iTopIndex + iNumberOfVisibleItem - 1) SendMessage (_hComboBox , CB_SETTOPINDEX , _iLineNumber - iNumberOfVisibleItem , 0); iTopIndex = SendMessage (_hComboBox , CB_GETTOPINDEX , 0 , 0); // Compute the position of the selected line to move the mouse to CRect ComboPos; GetWindowRect (_hComboBox , & ComboPos); CPoint Pos = ComboPos . CenterPoint (); Pos . y += ComboPos . Height () / 2 + iItemRect / 2 + iItemRect * (_iLineNumber - 1 - iTopIndex); m_fn_vMoveMouseCursor (Pos); SendMessage (_hComboBox , CB_SHOWDROPDOWN , FALSE , 0); if (m_bUseRightButton) { LPARAM lParam = MAKELPARAM (Pos . x , Pos . y); WPARAM wParam = (m_bUseShift ? MK_SHIFT : 0) | (m_bUseControl ? MK_CONTROL : 0);; ScreenToClient (_hComboBox , & Pos); PostMessage (_hComboBox , WM_RBUTTONDOWN , wParam + MK_RBUTTON , lParam); PostMessage (_hComboBox , WM_RBUTTONUP , wParam , lParam); } else { HWND hParentWnd = GetParent (_hComboBox); SendMessage (_hComboBox , CB_SETCURSEL , _iLineNumber - 1 , 0); PostMessage (hParentWnd , WM_COMMAND , (CBN_SELCHANGE << 16) + GetDlgCtrlID (_hComboBox) , (LPARAM) _hComboBox); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSelectLineInListBox // Simulate a selection into a list box //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSelectLineInListBox (HWND _hListBox , int _iLineNumber , BOOL _bAddToSelection /*=FALSE*/) { m_fn_vSetGetLastError (TUT_C_iNoError); int iListBoxGetCount = SendMessage (_hListBox , LB_GETCOUNT , 0 , 0); if (_iLineNumber < 1 || _iLineNumber > iListBoxGetCount) { m_fn_vSetGetLastError (TUT_C_iError_ListBoxInvalidLine); return; } // To be sure the line will be visible SendMessage(_hListBox , LVM_ENSUREVISIBLE , _iLineNumber - 1 , FALSE); // Compute the position of the selected line to move the mouse to CRect ListPos; GetWindowRect (_hListBox , & ListPos); CPoint Pos; int iTopIndex = SendMessage (_hListBox , LB_GETTOPINDEX , 0 , 0); int iItemHeight = SendMessage (_hListBox , LB_GETITEMHEIGHT , 0 , 0); if (m_bUsePosition) { Pos . y = ListPos . top + iItemHeight * (_iLineNumber - 1 - iTopIndex); if (m_bPercentForX) if (m_bRightBorder ) Pos . x = ListPos . right - ListPos . Width () * m_iXPosition / 100; else Pos . x = ListPos . left + ListPos . Width () * m_iXPosition / 100; else if (m_bRightBorder ) Pos . x = ListPos . right - m_iXPosition; else Pos . x = ListPos . left + m_iXPosition; if (m_bPercentForY) if (m_bBottomBorder) Pos . y += iItemHeight - iItemHeight * m_iYPosition / 100; else Pos . y += iItemHeight * m_iYPosition / 100; else if (m_bBottomBorder) Pos . y += iItemHeight - m_iYPosition; else Pos . y += m_iYPosition; } else { Pos . x = min (ListPos . CenterPoint () . x , ListPos . left + 4 * iItemHeight); Pos . y = ListPos . top + iItemHeight / 2 + iItemHeight * (_iLineNumber - 1 - iTopIndex); } m_fn_vMoveMouseCursor (Pos); if (m_bUseRightButton) { ScreenToClient (_hListBox , & Pos); LPARAM lParam = MAKELPARAM (Pos . x , Pos . y); WPARAM wParam = (m_bUseShift ? MK_SHIFT : 0) | (m_bUseControl ? MK_CONTROL : 0); PostMessage (_hListBox , WM_RBUTTONDOWN , wParam | MK_RBUTTON , lParam); PostMessage (_hListBox , WM_RBUTTONUP , wParam , lParam); } else if (m_bUseDoubleClic) { ScreenToClient (_hListBox , & Pos); LPARAM lParam = MAKELPARAM (Pos . x , Pos . y); WPARAM wParam = (m_bUseShift ? MK_SHIFT : 0) | (m_bUseControl ? MK_CONTROL : 0); PostMessage (_hListBox , WM_LBUTTONDOWN , wParam | MK_LBUTTON , lParam); PostMessage (_hListBox , WM_LBUTTONUP , wParam , lParam); PostMessage (_hListBox , WM_LBUTTONDBLCLK , wParam | MK_LBUTTON , lParam); PostMessage (_hListBox , WM_LBUTTONUP , wParam , lParam); } else if (m_bUsePosition) { ScreenToClient (_hListBox , & Pos); LPARAM lParam = MAKELPARAM (Pos . x , Pos . y); WPARAM wParam = (m_bUseShift ? MK_SHIFT : 0) | (m_bUseControl ? MK_CONTROL : 0); PostMessage (_hListBox , WM_LBUTTONDOWN , wParam | MK_LBUTTON , lParam); PostMessage (_hListBox , WM_LBUTTONUP , wParam , lParam); } else { HWND hParentWnd = GetParent (_hListBox); if (GetWindowLong (_hListBox , GWL_STYLE) & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) { // if not add, unselect all if (! _bAddToSelection) SendMessage (_hListBox , LB_SETSEL , FALSE , - 1); SendMessage (_hListBox , LB_SETSEL , TRUE , _iLineNumber - 1); } else SendMessage (_hListBox , LB_SETCURSEL , _iLineNumber - 1 , 0); PostMessage (hParentWnd , WM_COMMAND , (LBN_SELCHANGE << 16) + GetDlgCtrlID (_hListBox) , (LPARAM) _hListBox); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSelectLineInListCtrl // Simulate a selection into a list control //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSelectLineInListCtrl (HWND _hListCtrl , int _iLineNumber) { m_fn_vSetGetLastError (TUT_C_iNoError); int iListCtrlGetCount = ListView_GetItemCount (_hListCtrl); if (_iLineNumber < 1 || _iLineNumber > iListCtrlGetCount) { m_fn_vSetGetLastError (TUT_C_iError_ListCtrlInvalidLine); return; } // To be sure the line will be visible ListView_EnsureVisible (_hListCtrl , _iLineNumber - 1 , FALSE); // Compute the position of the selected line to move the mouse to CRect stItemRect; ListView_GetItemRect (_hListCtrl , _iLineNumber - 1 , & stItemRect , LVIR_BOUNDS); POINT stPos; stPos . x = min (stItemRect . CenterPoint () . x , stItemRect . left + 2 * stItemRect . Height ()); stPos . y = stItemRect . CenterPoint () . y; LPARAM lParam = MAKELPARAM (stPos . x , stPos . y); WPARAM wParam = (m_bUseShift ? MK_SHIFT : 0) | (m_bUseControl ? MK_CONTROL : 0); if (m_bUseRightButton) { ClientToScreen (_hListCtrl , & stPos); m_fn_vMoveMouseCursor (stPos); PostMessage (_hListCtrl , WM_RBUTTONDOWN , wParam + MK_RBUTTON , lParam); PostMessage (_hListCtrl , WM_RBUTTONUP , wParam , lParam); } else if (m_bUseDoubleClic) { ClientToScreen (_hListCtrl , & stPos); m_fn_vMoveMouseCursor (stPos); PostMessage (_hListCtrl , WM_LBUTTONDOWN , wParam + MK_LBUTTON , lParam); PostMessage (_hListCtrl , WM_LBUTTONUP , wParam , lParam); PostMessage (_hListCtrl , WM_LBUTTONDBLCLK , wParam + MK_LBUTTON , lParam); PostMessage (_hListCtrl , WM_LBUTTONUP , wParam , lParam); } else { if (m_bUsePosition) { if (m_bPercentForX) if (m_bRightBorder ) stPos . x = stItemRect . right - stItemRect . Width () * m_iXPosition / 100; else stPos . x = stItemRect . left + stItemRect . Width () * m_iXPosition / 100; else if (m_bRightBorder ) stPos . x = stItemRect . right - m_iXPosition; else stPos . x = stItemRect . left + m_iXPosition; if (m_bPercentForY) if (m_bBottomBorder) stPos . y = stItemRect . bottom - stItemRect . Height () * m_iYPosition / 100; else stPos . y = stItemRect . top + stItemRect . Height () * m_iYPosition / 100; else if (m_bBottomBorder) stPos . y = stItemRect . bottom - m_iYPosition; else stPos . y = stItemRect . top + m_iYPosition; lParam = MAKELPARAM (stPos . x , stPos . y); } ClientToScreen (_hListCtrl , & stPos); m_fn_vMoveMouseCursor (stPos); PostMessage (_hListCtrl , WM_LBUTTONDOWN , wParam + MK_LBUTTON , lParam); PostMessage (_hListCtrl , WM_LBUTTONUP , wParam , lParam); } } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vEnsureVisibleInTree // Make sure the given item of a tree is visible or invisible //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vEnsureVisibleInTree (HWND _hTreeCtrl , HTREEITEM _hItem , BOOL _bEnsureVisible /* = TRUE */) { // Get the parent item. If there is no parent, we show the item and we return HTREEITEM hParentItem = TreeView_GetParent (_hTreeCtrl , _hItem); if (! hParentItem) { TreeView_EnsureVisible (_hTreeCtrl , _hItem); return; } // If the parent is not visible, we make it visible (recursiv call) if (! m_fn_bIsItemVisibleInTree (_hTreeCtrl , hParentItem)) m_fn_vEnsureVisibleInTree (_hTreeCtrl , hParentItem); // Now that the parent is visible, we check if its children are visible if (m_fn_uiGetTreeCtrlState (_hTreeCtrl , hParentItem , TVIS_EXPANDED) != TVIS_EXPANDED) { CRect Rect; TreeView_GetItemRect (_hTreeCtrl , hParentItem , & Rect , FALSE); POINT Pos; Pos . x = Rect . left + Rect . Height () / 2; Pos . y = Rect . CenterPoint () . y; ClientToScreen (_hTreeCtrl , & Pos); m_fn_vMoveMouseCursor (Pos); TreeView_Expand (_hTreeCtrl , hParentItem , _bEnsureVisible ? TVE_EXPAND : TVE_COLLAPSE); } if (_bEnsureVisible) TreeView_EnsureVisible (_hTreeCtrl , _hItem); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_bSelectItemInTreeBox // Simulate a selection in a tree box // Return FALSE if there is no item with the given text //----------------------------------------------------------------------------- BOOL TUT_CTutorialManager::m_fn_bSelectItemInTreeBox (HWND _hTreeCtrl , CString _csTextToSelect) { HTREEITEM hRootItem = TreeView_GetRoot (_hTreeCtrl); HTREEITEM hItemToSelect = m_fn_hFindStringInTree (_hTreeCtrl , hRootItem , _csTextToSelect); if (! hItemToSelect) return FALSE; // Not found -> return FALSE m_fn_vEnsureVisibleInTree (_hTreeCtrl , hItemToSelect , TRUE); CRect Rect; TreeView_GetItemRect (_hTreeCtrl , hItemToSelect , & Rect , FALSE); POINT Pos; Pos . x = Rect . left + Rect . Height () * 4; Pos . y = Rect . CenterPoint () . y; ClientToScreen (_hTreeCtrl , & Pos); // Select the item m_fn_vMoveMouseCursor (Pos); TreeView_SelectItem (_hTreeCtrl , hItemToSelect); // Send a second notification to the parent, because the first one sent by TreeView_SelectItem did not have action = TVC_BYMOUSE NM_TREEVIEW stTreeView; stTreeView . hdr . hwndFrom = _hTreeCtrl; stTreeView . hdr . idFrom = GetDlgCtrlID (_hTreeCtrl); stTreeView . hdr . code = TVN_SELCHANGED; stTreeView . action = TVC_BYMOUSE; SendMessage (GetParent (_hTreeCtrl) , WM_NOTIFY , GetDlgCtrlID (_hTreeCtrl) , (LPARAM) & stTreeView); return TRUE; } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vWriteText // Write a line of text into a tutorial window //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vWriteText (HWND _hEditView , CString _csText) { ASSERT (IsWindow (_hEditView)); // The edit view must be correct HWND hPreviousWnd = GetForegroundWindow (); // Put the caret at the end of the text int iNumberOfChar = GetWindowTextLength (_hEditView); SendMessage (_hEditView , EM_SETSEL , iNumberOfChar , iNumberOfChar); // Change the format CHARFORMAT stCharFormat; stCharFormat . cbSize = sizeof (CHARFORMAT); stCharFormat . dwMask = CFM_COLOR | CFM_SIZE | CFM_FACE; stCharFormat . dwEffects &= ~ CFE_AUTOCOLOR; // Remove the flag "auto color" stCharFormat . crTextColor = m_xCurrentColor; stCharFormat . yHeight = m_lCurrentHeight * GetDeviceCaps (GetDC (_hEditView) , LOGPIXELSY) * 180 / 1000; strcpy (stCharFormat . szFaceName , "Arial"); SendMessage (_hEditView , EM_SETCHARFORMAT , SCF_SELECTION , (LPARAM) & stCharFormat); PARAFORMAT stParaFormat; stParaFormat . cbSize = sizeof (PARAFORMAT); stParaFormat . dwMask = PFM_ALIGNMENT; stParaFormat . wAlignment = (unsigned short) m_lCurrentAlignment; SendMessage (_hEditView ,EM_SETPARAFORMAT , 0 , (LPARAM) & stParaFormat); // Insert the new text if (_csText . Right (1) == "\\") _csText = _csText . Left (_csText . GetLength () - 1); // If the string ends with '\', no line feed else { _csText += (char)13; _csText += (char)10; } SendMessage (_hEditView , EM_REPLACESEL , FALSE /* No Undo */ , (LPARAM) (LPCTSTR) _csText); // Check if scroll is necessary RECT stEditViewRect; GetClientRect (_hEditView , & stEditViewRect); POINT stEndOfTextPos; BOOL bOk; int iCounter = 0; do { SendMessage (_hEditView , EM_POSFROMCHAR , (WPARAM) & stEndOfTextPos , GetWindowTextLength (_hEditView)); bOk = stEndOfTextPos . y <= stEditViewRect . bottom; if (! bOk) SendMessage (_hEditView , EM_LINESCROLL , 0 , 1); } while (bOk == FALSE && ++iCounter < 10); // To prevent from infinite loop InvalidateRect (_hEditView , NULL , FALSE); UpdateWindow (_hEditView); SetForegroundWindow (hPreviousWnd); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_vSendKey // Send a key //----------------------------------------------------------------------------- void TUT_CTutorialManager::m_fn_vSendKey (int _iVirtualKeyCode , BOOL _bKeyPressed) { keybd_event (_iVirtualKeyCode , _iVirtualKeyCode , _bKeyPressed ? 0 : KEYEVENTF_KEYUP , 0); Sleep (10); } //----------------------------------------------------------------------------- // class TUT_CTutorialManager - m_fn_szHandleQuote // replace two consecutive quotes by a double-quote //----------------------------------------------------------------------------- char *TUT_CTutorialManager::m_fn_szHandleQuote(char * _szString) { char *cBegin = _szString; char *cTarget = _szString; char *cSource = _szString; BOOL bPreviousQuote = FALSE; while (*cSource) { if (*cSource == '\'') { if (bPreviousQuote) { *cTarget++ = '\"'; bPreviousQuote = FALSE; } else { bPreviousQuote = TRUE; } } else { if (bPreviousQuote) { *cTarget++ = '\''; } *cTarget++ = *cSource; bPreviousQuote = FALSE; } cSource++; } if (bPreviousQuote) { *cTarget++ = '\''; } *cTarget = 0; return _szString; }