// ActionEngine.cpp: implementation of the CActionEngine class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ActionEngine.h" #include "NSMessages.h" #include ////////////////////////////////////////////////////////////////////// // CActionEngine // Starts with only this action HRESULT CActionEngine::Start(CAction* pFirstAction) { ASSERT(pFirstAction); clear(); pFirstAction->addref(); push_back(pFirstAction); return Start(); } /////////////////////////////////////////////////////////////////////// // Starts the Actual Processing HRESULT CActionEngine::Start() { HRESULT hr = S_OK; CAction* pAction = NULL; UINT nDone = 0; // Keep going while there are actions to process while(size()) { // Get current action pAction = at(0); ASSERT(pAction); try { // Do Action pAction->Do(this, m_hwndUpdates); } catch(CActionError& e) { if(m_hwndErrors) { // Send Error to Window NS_ERROR_DATA nsErr; nsErr.hRes = e.m_hRes; nsErr.szDesc = e.m_sDesc; nsErr.lParam = (LPARAM)pAction; ::SendMessage(m_hwndErrors, NSM_ERROR, NULL, (LPARAM)&nsErr); } hr = E_FAIL; } // Update the Window nDone++; if(m_hwndUpdates) { // Send Update Message NS_UPDATE_DATA nsUpd; nsUpd.lCur = nDone; nsUpd.lTot = nDone + size(); nsUpd.szMessage1 = NULL; nsUpd.szMessage2 = NULL; // If message returns false then cancel if(!::SendMessage(m_hwndUpdates, NSM_UPDATE, NULL, (LPARAM)&nsUpd)) { hr = E_ABORT; break; } } // Remove action from array and release it erase(begin()); pAction->release(); } return hr; } ///////////////////////////////////////////////////////////////////// // Starts the Engine in another thread HANDLE CActionEngine::StartThread() { DWORD dwThreadID = NULL; return (HANDLE)CreateThread(NULL, 0, ThreadProc, (LPVOID)this, 0, &dwThreadID); } DWORD CALLBACK CActionEngine::ThreadProc(LPVOID lpParam) { // Need to Initialize for this thread // BUG: This didn't work in Win95 (non-OSR2) because // only have CoInitialize // HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); HRESULT hr = CoInitialize(NULL); ASSERT(lpParam); CActionEngine* pEngine = (CActionEngine*)lpParam; HRESULT hRet = pEngine->Start(); if(SUCCEEDED(hr)) CoUninitialize(); // Return the result of the engine // as our thread exit code return hRet; } // Sets the pointers for the update windows void CActionEngine::SetUpdates(HWND hwndUpdates /*= NULL*/, HWND hwndErrors /*= NULL*/) { m_hwndUpdates = hwndUpdates; m_hwndErrors = hwndErrors; } /////////////////////////////////////////////////////////////// // Array Management Stuff UINT CActionEngine::Add(CAction* pAction) { ASSERT(pAction); pAction->addref(); push_back(pAction); return size(); } UINT CActionEngine::Insert(CAction* pAction, UINT nIndex) { ASSERT(pAction); ASSERT(nIndex < size()); pAction->addref(); insert(begin() + nIndex, pAction); return nIndex; } void CActionEngine::Remove(UINT nIndex) { ASSERT(nIndex < size()); CAction* pAction = at(nIndex); erase(begin() + nIndex); pAction->release(); } void CActionEngine::RemoveAll(CAction* pKeep /*= NULL*/) { if(pKeep) pKeep->addref(); while(size()) { CAction* pAction = at(0); pAction->release(); erase(begin()); } if(pKeep) { Add(pKeep); pKeep->release(); } } CAction* CActionEngine::At(UINT nIndex) { ASSERT(nIndex < size()); return at(nIndex); } //////////////////////////////////////////////////////////////////////// // CAction Helper Function //////////////////////////////////////////////////////////////////////// void CAction::Update(HWND hwndUpdates, LPCTSTR szDesc) { // Send a message with only the string valid NS_UPDATE_DATA nsUpd; nsUpd.lCur = -1; nsUpd.lTot = -1; nsUpd.szMessage1 = NULL; nsUpd.szMessage2 = szDesc; ::SendMessage(hwndUpdates, NSM_UPDATE, NULL, (LPARAM)&nsUpd); } void CAction::Update(HWND hwndUpdates, LPCTSTR szStatus, LPCTSTR szDesc) { // Send a message with only the string valid NS_UPDATE_DATA nsUpd; nsUpd.lCur = -1; nsUpd.lTot = -1; nsUpd.szMessage1 = szStatus; nsUpd.szMessage2 = szDesc; ::SendMessage(hwndUpdates, NSM_UPDATE, NULL, (LPARAM)&nsUpd); } ////////////////////////////////////////////////////////////////////// // CActionError Construction Helper Functions inline CActionError::CActionError(HRESULT hr, const string& sMessage, const file_path& path /*= file_path()*/) { Construct(hr, sMessage, path); } CActionError::CActionError(HRESULT hr, UINT nID, const file_path& path /*= file_path()*/) { string sTemp; sTemp.load_string(nID); Construct(hr, sTemp, path); } CActionError::CActionError(const string& sError, HRESULT hr, UINT nID, const file_path& path /*= file_path()*/) { string sTemp; sTemp.load_string(nID); Construct(sError, hr, sTemp, path); } inline CActionError::CActionError(const string& sError, HRESULT hr, const string& sMessage, const file_path& path /*= file_path()*/) { Construct(sError, hr, sMessage, path); } void CActionError::Construct(const string& sError, HRESULT hr, string sMessage, const file_path& path) { // Replace with custom message before passing on sMessage.replace(_T("%e"), sError); Construct(hr, sMessage, path); } void CActionError::Construct(HRESULT hr, string sMessage, const file_path& path) { m_hRes = hr; // If there's a need then replace if(sMessage.find(_T("%e")) != string::npos) sMessage.replace(_T("%e"), FormatHR(m_hRes)); // Same here if(path.valid()) { sMessage.replace(_T("%f"), path.file()); sMessage.replace(_T("%F"), path); } m_sDesc = sMessage; } void Lower(string& s) { s.make_lower(); }