// // MODULE: StateInfo.cpp // // PURPOSE: Contains sniffing, network and node information. Also is used // by the Launch module to start the container application. // // Basically, this is how the Launch Server packages up info for the // Local TShoot OCX, launches either IE or HTML Help System to a page // containing the Local TShoot OCX, and handshakes with the Local TShoot OCX // to pass that information // // Note that CSMStateInfo::GetShooterStates() is called by the // Local TShoot OCX to pick up the CItem object which contains // the packaged-up info. // // PROJECT: Local Troubleshooter Launcher for the Device Manager // // COMPANY: Saltmine Creative, Inc. (206)-633-4743 support@saltmine.com // // AUTHOR: Richard Meadows // COMMENTS BY: Joe Mabel // // ORIGINAL DATE: 2-26-98 // // // Version Date By Comments //-------------------------------------------------------------------- // V0.1 - RM Original /////////////////////// #include "stdafx.h" #include "atlbase.h" #include "StateInfo.h" #include "TSLError.h" #include "ComGlobals.h" #include "Registry.h" #include #include #include //#include #include //////////////////////////////////////////////////////// // CItem : // Data structure for pseudo HTTP "get" in launching Local Troubleshooters // CItem::CItem() { // initializing this is exactly the same as reinitializing. ReInit(); } void CItem::ReInit() { memset(m_aszCmds, NULL, SYM_LEN * NODE_COUNT); memset(m_aszVals, NULL, SYM_LEN * NODE_COUNT); m_cNodesSet = 0; _tcscpy(m_szProblemDef, _T("TShootProblem")); _tcscpy(m_szTypeDef, _T("type")); m_szPNPDeviceID[0] = NULL; m_szGuidClass[0] = NULL; m_szContainerPathName[0] = NULL; m_szWebPage[0] = NULL; m_szSniffScriptFile[0] = NULL; m_eLaunchRegime = launchIndefinite; m_szMachineID[0] = NULL; m_szDeviceInstanceID[0] = NULL; #ifdef _DEBUG // There are some other things you need to comment out in GetShooterStates // to allow debugging this service from a tshoot.ocx debug sesstion. /* _tcscpy(m_aszCmds[0], m_szTypeDef); _tcscpy(m_aszVals[0], _T("ras")); _tcscpy(m_aszCmds[1], m_szProblemDef); _tcscpy(m_aszVals[1], _T("CnntCnnctAftrDlngWthRS")); _tcscpy(m_aszCmds[2], _T("SoftwareCompression")); _tcscpy(m_aszVals[2], _T("0")); m_cNodesSet = 1; */ #endif return; } void CItem::Clear() { memset(m_aszCmds, NULL, SYM_LEN * NODE_COUNT); memset(m_aszVals, NULL, SYM_LEN * NODE_COUNT); m_cNodesSet = 0; _tcscpy(m_szProblemDef, _T("TShootProblem")); _tcscpy(m_szTypeDef, _T("type")); m_szPNPDeviceID[0] = NULL; m_szGuidClass[0] = NULL; m_szContainerPathName[0] = NULL; m_szWebPage[0] = NULL; m_szSniffScriptFile[0] = NULL; m_eLaunchRegime = launchIndefinite; return; } // ----------- Routines to build command/value pairs ------------------ // see documentation of m_aszCmds, m_aszVals for further explanation void CItem::SetNetwork(LPCTSTR szNetwork) { if (NULL != szNetwork && NULL != szNetwork[0]) { _tcscpy(m_aszCmds[0], m_szTypeDef); _tcsncpy(m_aszVals[0], szNetwork, SYM_LEN); } else { m_aszCmds[0][0] = NULL; m_aszVals[0][0] = NULL; } return; } void CItem::SetProblem(LPCTSTR szProblem) { if (NULL != szProblem && NULL != szProblem[0]) { _tcscpy(m_aszCmds[1], m_szProblemDef); _tcsncpy(m_aszVals[1], szProblem, SYM_LEN); } else { m_aszCmds[1][0] = NULL; m_aszVals[1][0] = NULL; } return; } void CItem::SetNode(LPCTSTR szNode, LPCTSTR szState) { if (NULL != szNode && NULL != szNode[0] && NULL != szState && NULL != szState[0]) { _tcsncpy(m_aszCmds[m_cNodesSet + 2], szNode, SYM_LEN); _tcsncpy(m_aszVals[m_cNodesSet + 2], szState, SYM_LEN); m_cNodesSet++; } return; } // ----------- Routines to query command/value pairs ------------------ // See documentation of m_aszCmds, m_aszVals for further explanation // returns true if network has been set // On success, OUTPUT *pszCmd is "type", *pszVal is network name bool CItem::GetNetwork(LPTSTR *pszCmd, LPTSTR *pszVal) { *pszCmd = m_szTypeDef; *pszVal = m_aszVals[0]; return *m_aszVals[0] != NULL; } // returns true if problem node has been set // On success, OUTPUT *pszCmd is "TShootProblem", *pszVal is problem node's symbolic name bool CItem::GetProblem(LPTSTR *pszCmd, LPTSTR *pszVal) { *pszCmd = m_szProblemDef; *pszVal = m_aszVals[1]; return *m_aszVals[1] != NULL;; } // output the iNodeC-th non-problem node for which a state has been set. // On success, OUTPUT *pszCmd is symbolic node name, *pszVal is state // returns true if at least iNodeC non-problem nodes have been set bool CItem::GetNodeState(int iNodeC, LPTSTR *pszCmd, LPTSTR *pszVal) { if (iNodeC >= m_cNodesSet) return false; *pszCmd = m_aszCmds[iNodeC + 2]; *pszVal = m_aszVals[iNodeC + 2]; return true; } // ----------- Routines to query whether we know a network ------------ // ----------- & problem node to launch to ---------------------------- // See documentation of m_aszCmds, m_aszVals for further explanation // NetworkSet returns true if we know which troubleshooter to launch. bool CItem::NetworkSet() { return NULL != m_aszVals[0][0]; } // ProblemSet returns true if we know which problem to choose. bool CItem::ProblemSet() { return NULL != m_aszVals[1][0]; } // --------- Interface to other member variables recponsible for launching ----------- void CItem::SetLaunchRegime(ELaunchRegime eLaunchRegime) { m_eLaunchRegime = eLaunchRegime; } void CItem::SetContainerPathName(TCHAR szContainerPathName[MAX_PATH]) { if (NULL != szContainerPathName && NULL != szContainerPathName[0]) _tcscpy(m_szContainerPathName, szContainerPathName); else m_szContainerPathName[0] = NULL; return; } void CItem::SetWebPage(TCHAR szWebPage[MAX_PATH]) { if (NULL != szWebPage && NULL != szWebPage[0]) _tcscpy(m_szWebPage, szWebPage); else m_szWebPage[0] = NULL; return; } void CItem::SetSniffScriptFile(TCHAR szSniffScriptFile[MAX_PATH]) { if (NULL != szSniffScriptFile && NULL != szSniffScriptFile[0]) _tcscpy(m_szSniffScriptFile, szSniffScriptFile); else m_szSniffScriptFile[0] = NULL; return; } void CItem::SetSniffStandardFile(TCHAR szSniffStandardFile[MAX_PATH]) { if (NULL != szSniffStandardFile && NULL != szSniffStandardFile[0]) _tcscpy(m_szSniffStandardFile, szSniffStandardFile); else m_szSniffStandardFile[0] = NULL; return; } ELaunchRegime CItem::GetLaunchRegime() { return m_eLaunchRegime; } inline TCHAR* CItem::GetContainerPathName() { return m_szContainerPathName; } inline TCHAR* CItem::GetWebPage() { return m_szWebPage; } inline TCHAR* CItem::GetSniffScriptFile() { return m_szSniffScriptFile; } inline TCHAR* CItem::GetSniffStandardFile() { return m_szSniffStandardFile; } //////////////////////////////////////////////////////// // CSMStateInfo : // State information on MSBN Troubleshooters // CSMStateInfo::CSMStateInfo() { m_csGlobalMemory.Init(); m_csSingleLaunch.Init(); return; } CSMStateInfo::~CSMStateInfo() { m_csGlobalMemory.Term(); m_csSingleLaunch.Term(); return; } // TestPut: Simply copies item to m_Item. void CSMStateInfo::TestPut(CItem &item) { m_csGlobalMemory.Lock(); m_Item = item; m_csGlobalMemory.Unlock(); return; } // TestGet: Simply copies m_Item to item. void CSMStateInfo::TestGet(CItem &item) { m_csGlobalMemory.Lock(); item = m_Item; m_csGlobalMemory.Unlock(); return; } // Copy the item to the global memory and launch a process based on the command. // Copying the item to global memory is here because the item is what tells the // launched local troubleshooter what belief network etc. it is being launched to. // Once we unlock global memory, the Local Troubleshooter OCX can read that item // and act on it. BOOL CSMStateInfo::CreateContainer(CItem &item, LPTSTR szCommand) { BOOL bOk = TRUE; HRESULT hRes = S_OK; STARTUPINFO startup; PROCESS_INFORMATION process; memset(&startup, NULL, sizeof(STARTUPINFO)); startup.cb = sizeof(STARTUPINFO); startup.wShowWindow = SW_SHOWNORMAL; m_csGlobalMemory.Lock(); m_Item = item; bOk = CreateProcess(NULL, szCommand, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &process); CloseHandle(process.hThread); CloseHandle(process.hProcess); m_csGlobalMemory.Unlock(); return bOk; } // // Copy network_sniff.htm to tssniffAsk.htm if the former exists // Create (modify) tssniffAsk.htm to be a sniffing stub otherwise // BOOL CSMStateInfo::CopySniffScriptFile(CItem &item) { TCHAR* szSniffScriptFile = item.GetSniffScriptFile(); TCHAR* szSniffStandardFile = item.GetSniffStandardFile(); if (!*szSniffScriptFile) // no network specific sniff file { // szSniffScriptFile contains tssniffAsk.htm // it means that we have to form this file as an empty stub ostrstream fileSniffScript; HANDLE hFile = ::CreateFile(szSniffStandardFile, GENERIC_WRITE, 0, NULL, // no security attributes CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL // handle to template file ); if (hFile != INVALID_HANDLE_VALUE) { // form html file - part preceding script fileSniffScript << "" << endl; fileSniffScript << "" << endl; fileSniffScript << "GTS LOCAL" << endl; fileSniffScript << "" << endl; fileSniffScript << "" << endl; fileSniffScript << "" << endl; fileSniffScript << "" << endl; fileSniffScript << "" << endl; fileSniffScript << ends; char* str = fileSniffScript.str(); DWORD read; if (!::WriteFile(hFile, str, strlen(str), &read, NULL)) { ::CloseHandle(hFile); fileSniffScript.rdbuf()->freeze(0); return false; } ::CloseHandle(hFile); fileSniffScript.rdbuf()->freeze(0); return true; } else { return false; } } else { return ::CopyFile(szSniffScriptFile, szSniffStandardFile, false); } } // Find the container (HTML Help System or IE) and starting web page, launch, wait to // see if launch succeeded bool CSMStateInfo::GoGo(DWORD dwTimeOut, CItem &item, DWORD *pdwResult) { bool bResult = true; HANDLE hLaunchedEvent = NULL; TCHAR szProcess[MAX_PATH]; TCHAR szWebPage[MAX_PATH]; LPTSTR pszCommand = NULL; int CommandLen; DWORD dwError; int Count = 34; if (item.GetLaunchRegime() == launchIndefinite || !item.GetContainerPathName()[0] || !item.GetWebPage()[0] ) { *pdwResult = TSL_ERROR_ASSERTION; return false; } do { _stprintf(item.m_szEventName, _T("TSL_SHOOTER_Event_%ld"), Count); if (NULL == (hLaunchedEvent = CreateEvent (NULL, FALSE, FALSE, item.m_szEventName))) { dwError = GetLastError(); if (ERROR_ALREADY_EXISTS != dwError) { *pdwResult = dwError; return false; } } } while (NULL == hLaunchedEvent); // Get the path to internet explorer (or HTML Help System). _tcscpy(szProcess, item.GetContainerPathName()); // Need to know the location and name of the // page that asks the service for the CItem // information. _tcscpy(szWebPage, item.GetWebPage()); CommandLen = _tcslen(szProcess) + 1 + _tcslen(szWebPage) + 2; pszCommand = new TCHAR[CommandLen]; if (NULL == pszCommand) { *pdwResult = TSL_ERROR_OUT_OF_MEMORY; return false; } _tcscpy(pszCommand, szProcess); _tcscat(pszCommand, _T(" ")); _tcscat(pszCommand, szWebPage); m_csSingleLaunch.Lock(); // copy to or create tssniffAsk.htm if (!CopySniffScriptFile(item)) { *pdwResult = TSL_E_COPY_SNIFF_SCRIPT; return false; } // CreateContainer copies the item to the global memory and // launches the command. if (!CreateContainer(item, pszCommand)) { *pdwResult = TSL_E_CREATE_PROC; bResult = false; } else { if (WAIT_OBJECT_0 == WaitForSingleObject(hLaunchedEvent, dwTimeOut)) { // The container has the information. *pdwResult = TSL_OK; } else { // Wait timed out. Don't know if the operation will work or not work. *pdwResult = TSL_W_CONTAINER_WAIT_TIMED_OUT; } } m_csSingleLaunch.Unlock(); delete [] pszCommand; CloseHandle(hLaunchedEvent); return bResult; } // Find the container (HTML Help System or IE) and start it up to a URL which is _not_ // expected to contain Local Troubleshooter, just an arbitrary web page. This should // only be used when the launch as such can't work, and we are just trying to give them // somewhere to start troubleshooting, typically the home page which lists all // trobleshooting belief networks. bool CSMStateInfo::GoURL(CItem &item, DWORD *pdwResult) { bool bResult = true; TCHAR szProcess[MAX_PATH]; TCHAR szWebPage[MAX_PATH]; LPTSTR pszCommand = NULL; int CommandLen; if (item.GetLaunchRegime() != launchDefaultWebPage || !item.GetContainerPathName()[0] || !item.GetWebPage()[0] ) { *pdwResult = TSL_ERROR_ASSERTION; return false; } // Get the path to internet explorer (or HTML Help System). _tcscpy(szProcess, item.GetContainerPathName()); // Need to know the location and name of the // page that asks the service for the CItem // information. _tcscpy(szWebPage, item.GetWebPage()); CommandLen = _tcslen(szProcess) + 1 + _tcslen(szWebPage) + 2; pszCommand = new TCHAR[CommandLen]; if (NULL == pszCommand) { *pdwResult = TSL_ERROR_OUT_OF_MEMORY; return false; } _tcscpy(pszCommand, szProcess); _tcscat(pszCommand, _T(" ")); _tcscat(pszCommand, szWebPage); // CreateContainer is overkill here, but perfectly OK. if (!CreateContainer(item, pszCommand)) { *pdwResult = TSL_E_CREATE_PROC; bResult = false; } delete [] pszCommand; return bResult; } // This function is used by the Local Troubleshooter OCX, not by the Launcher. // This is how the Local Troubleshooter knows what troubleshooting network to launch // to, as well as any nodes whose states are set. // GetShooterStates returns the commands and the number of commands for // the Tshoot.ocx. // refLaunchState is a member of this instance of the LaunchTS interface. // HRESULT CSMStateInfo::GetShooterStates(CItem &refLaunchState, DWORD *pdwResult) { HANDLE hHaveItemEvent; // Get a copy of the launch info state stored in this instance. // Synchronize with the process that launched the service. m_csGlobalMemory.Lock(); if (NULL == (hHaveItemEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, m_Item.m_szEventName))) { *pdwResult = GetLastError(); m_csGlobalMemory.Unlock(); return TSL_E_FAIL; } // Get a copy of the state before unlocking the global memory. refLaunchState = m_Item; // Let the other process continue running. SetEvent(hHaveItemEvent); m_csGlobalMemory.Unlock(); CloseHandle(hHaveItemEvent); *pdwResult = 0; return S_OK; }