// // MODULE: APGTSQRY.CPP // // PURPOSE: Implementation file for PTS Query Parser // // PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint // // // NOTES: // 1. Based on Print Troubleshooter DLL // // Version Date By Comments //-------------------------------------------------------------------- // V0.1 - RM Original // V0.2 6/4/97 RWM Local Version for Memphis // V0.3 04/09/98 JM/OK+ Local Version for NT5 // //#include "windows.h" #include "stdafx.h" #include "time.h" #include "apgts.h" #include "bnts.h" #include "BackupInfo.h" #include "cachegen.h" #include "apgtsinf.h" #include "apgtscmd.h" #include "apgtshtx.h" #include "apgtscls.h" #include "ErrorEnums.h" #include "BasicException.h" #include "HttpQueryException.h" #include "Functions.h" #include "BackupInfo.h" #include #include #include "LaunchServ.h" // // CHttpQuery::CHttpQuery() { m_pvarCmds = NULL; m_pvarVals = NULL; m_strCmd1 = _T(""); m_strVal1 = _T(""); m_CurrentUse = 0; m_Size = 0; m_bReverseStack = false; m_nStatesFromServ = 0; } // // CHttpQuery::~CHttpQuery() { } void CHttpQuery::ThrowBadParams(CString &str) { CHttpQueryException *pExc = new CHttpQueryException; #ifndef __DEBUG_HTTPQUERY_ pExc->m_strError = _T("Script Error"); #else pExc->m_strError = str; #endif throw pExc; return; } void CHttpQuery::Initialize(const VARIANT FAR& varCmds, const VARIANT FAR& varVals, short size) { #ifdef __DEBUG_HTTPQUERY_ AfxMessageBox(_T("Cmd Variant Types:\n\n") + DecodeVariantTypes(varCmds.vt), MB_ICONINFORMATION); AfxMessageBox(_T("Value Variant Types:\n\n") + DecodeVariantTypes(varVals.vt), MB_ICONINFORMATION); #endif const VARIANT FAR *pVarCmds; const VARIANT FAR *pVarVals; if (VT_BYREF == (VT_BYREF & varCmds.vt) && VT_VARIANT == (VT_VARIANT & varCmds.vt)) { if (VT_ARRAY == (VT_ARRAY & varCmds.vt)) pVarCmds = &varCmds; else pVarCmds = varCmds.pvarVal; } else { pVarCmds = NULL; CString str = _T("Cmd parameters from VB were not a variant or not by ref."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } if (VT_BYREF == (VT_BYREF & varVals.vt) && VT_VARIANT == (VT_VARIANT & varVals.vt)) { if (VT_ARRAY == (VT_ARRAY & varVals.vt)) pVarVals = &varVals; else pVarVals = varVals.pvarVal; } else { pVarVals = NULL; CString str = _T("Cmd parameters from VB were not a variant or not by ref."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } if (VT_BYREF != (VT_BYREF & pVarCmds->vt) || VT_ARRAY != (VT_ARRAY & pVarCmds->vt) || VT_VARIANT != (0xFFF & pVarCmds->vt)) { CString str = _T("Wrong Cmd parameters passed from VB."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } if (VT_BYREF != (VT_BYREF & pVarVals->vt) || VT_ARRAY != (VT_ARRAY & pVarVals->vt) || VT_VARIANT != (0xFFF & pVarVals->vt)) { CString str = _T("Wrong Cmd parameters passed from VB."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } #ifdef __DEBUG_HTTPQUERY_ AfxMessageBox(_T("Cmd Variant Types:\n\n") + DecodeVariantTypes(pVarCmds->vt), MB_ICONINFORMATION); AfxMessageBox(_T("Value Variant Types:\n\n") + DecodeVariantTypes(pVarVals->vt), MB_ICONINFORMATION); #endif SAFEARRAY *pArrCmds = *(pVarCmds->pparray); SAFEARRAY *pArrVals = *(pVarVals->pparray); #ifdef __DEBUG_HTTPQUERY_ CString strSafe; strSafe.Format("Cmd Safe Array\n\nDim: %d\nfeatures:\n%s\nSize of the Elements: %ld", pArrCmds->cDims, (LPCTSTR) DecodeSafeArray(pArrCmds->fFeatures), pArrCmds->cbElements); AfxMessageBox(strSafe, MB_ICONINFORMATION); strSafe.Format("Val Safe Array\n\nDim: %d\nfeatures:\n%s\nSize of the Elements: %ld", pArrVals->cDims, (LPCTSTR) DecodeSafeArray(pArrVals->fFeatures), pArrVals->cbElements); AfxMessageBox(strSafe, MB_ICONINFORMATION); #endif if (0 != pArrCmds->rgsabound[0].lLbound || 0 != pArrVals->rgsabound[0].lLbound) { CString str = _T("Wrong Cmd parameters passed from VB. Lower bounds are wrong."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } if (pArrCmds->rgsabound[0].cElements != pArrVals->rgsabound[0].cElements) { CString str = _T("Wrong Cmd parameters passed from VB. Cmds upperbound != Vals upperbound."); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } m_Size = size; #ifdef __DEBUG_HTTPQUERY_ CString str; str.Format("Size: %d", m_Size); AfxMessageBox(str, MB_ICONINFORMATION); #endif m_pvarCmds = (VARIANT *) pArrCmds->pvData; m_pvarVals = (VARIANT *) pArrVals->pvData; if (0 != m_Size) { if (m_pvarCmds->vt != VT_BSTR || m_pvarVals->vt != VT_BSTR) { CString str; str.Format(_T("Wrong Cmd parameters passed from VB. Array of unexpected type.\n\n") _T("Cmd Type: %s\nVal Type: %s"), (LPCTSTR) DecodeVariantTypes(m_pvarCmds->vt), (LPCTSTR) DecodeVariantTypes(m_pvarVals->vt)); ASSERT(FALSE); TRACE(_T("%s\n"), str); ThrowBadParams(str); } } CString strC = m_pvarCmds[0].bstrVal; CString strD = m_pvarVals[0].bstrVal; if (strC != m_strCmd1 || strD != m_strVal1) m_State.RemoveAll(); m_strCmd1 = strC; m_strVal1 = strD; return; } BOOL CHttpQuery::StrIsDigit(LPCTSTR pSz) { BOOL bRet = TRUE; while (*pSz) { if (!_istdigit(*pSz)) { bRet = FALSE; break; } pSz = _tcsinc(pSz); } return bRet; } void CHttpQuery::FinishInit(BCache *pApi, const VARIANT FAR& varCmds, const VARIANT FAR& varVals) { ASSERT(pApi); ASSERT(m_Size > 0); CNode node; CString str; if (!pApi) return; if (!pApi->BValidNet()) pApi->ReadModel(); m_bReverseStack = false; for (int x = 1; x < m_Size; x++) { // Read the command. str = m_pvarCmds[x].bstrVal; if (StrIsDigit((LPCTSTR) str)) node.cmd = _ttoi(str); else if (0 == _tcscmp(CHOOSE_TS_PROBLEM_NODE, (LPCTSTR) str)) node.cmd = pApi->CNode() + idhFirst; else if (0 == _tcscmp(TRY_TS_AT_MICROSOFT_SZ, (LPCTSTR) str)) node.cmd = TRY_TS_AT_MICROSOFT_ID; else { NID nid = pApi->INode((LPCTSTR) str); if (nid == -1) { // Invalid node name. This also throws suspicion on anything further // down the line. Just break out of the loop. break; } node.cmd = nid + idhFirst; } // Read the value. str = m_pvarVals[x].bstrVal; if (StrIsDigit((LPCTSTR) str)) node.val = _ttoi(str); else { NID nid = pApi->INode((LPCTSTR) str); if (nid == -1) { // Invalid node name. This also throws suspicion on anything further // down the line. Just break out of the loop. break; } node.val = nid + idhFirst; } m_State.Push(node); } return; } void CHttpQuery::PushNodesLastSniffed(const CArray& arr) { for (int i = 0; i < arr.GetSize(); i++) { CNode node; node.cmd = idhFirst + arr[i]; node.val = 0; node.sniffed = true; m_State.Push(node); } } void CHttpQuery::FinishInitFromServ(BCache *pApi, ILaunchTS *pLaunchTS) { ASSERT(pApi); CNode node; CString str; HRESULT hRes; HRESULT hResNode; HRESULT hResState; OLECHAR *poleProblem; OLECHAR *poleNode; OLECHAR *poleState; OLECHAR *poleMachine; OLECHAR *polePNPDevice; OLECHAR *poleGuidClass; OLECHAR *poleDeviceInstance; /////////////////////////////////////////////////////////// // obtaining Machine, PNPDevice, GuidClass, DeviceInstance // hRes = pLaunchTS->GetMachine(&poleMachine); if (S_FALSE == hRes || FAILED(hRes)) return; m_strMachineID = poleMachine; ::SysFreeString(poleMachine); hRes = pLaunchTS->GetPNPDevice(&polePNPDevice); if (S_FALSE == hRes || FAILED(hRes)) return; m_strPNPDeviceID = polePNPDevice; ::SysFreeString(polePNPDevice); hRes = pLaunchTS->GetGuidClass(&poleGuidClass); if (S_FALSE == hRes || FAILED(hRes)) return; m_strGuidClass = poleGuidClass; ::SysFreeString(poleGuidClass); hRes = pLaunchTS->GetDeviceInstance(&poleDeviceInstance); if (S_FALSE == hRes || FAILED(hRes)) return; m_strDeviceInstanceID = poleDeviceInstance; ::SysFreeString(poleDeviceInstance); // //////////////////////////////////////////////////////////// if (!pApi) return; if (!pApi->BValidNet()) pApi->ReadModel(); m_Size = 1; // I believe this accounts for the troubleshooting network name (JM 3/98) m_nStatesFromServ = 0; // The order that the nodes are set in the inference engine is important. // >>> I (JM 3/14/98) don't understand the rest of this comment: // Need the rest of the nodes inverted on the stack. // The buttons can not be inverted here. When they are the back button // stops working. hRes = pLaunchTS->GetProblem(&poleProblem); if (S_FALSE == hRes || FAILED(hRes)) return; str = poleProblem; SysFreeString(poleProblem); node.cmd = pApi->CNode() + idhFirst; // Sets the problem state. if (StrIsDigit((LPCTSTR) str)) node.val = _ttoi(str); else { NID nidProblem = pApi->INode((LPCTSTR) str); if (nidProblem == static_cast(-1)) { // The specified problem node doesn't exist. Ignore it and any other nodes // that follow. return; } pApi->SetRunWithKnownProblem(true); pApi->BNodeSetCurrent( nidProblem ); if (pApi->ELblNode() != ESTDLBL_problem ) { // The specified problem node exists, but it's not a problem node. // Ignore it and any other nodes that follow. return; } IDH idhProblem = nidProblem + idhFirst; node.val = idhProblem; } m_State.Push(node); m_Size++; m_aStatesFromServ[m_nStatesFromServ] = node; m_nStatesFromServ++; int iAnyNode = 0; do { hResNode = pLaunchTS->GetNode((short)iAnyNode, &poleNode); if (FAILED(hResNode) || S_FALSE == hResNode) break; str = poleNode; SysFreeString(poleNode); if (StrIsDigit((LPCTSTR) str)) node.cmd = _ttoi(str); else node.cmd = pApi->INode((LPCTSTR) str) + idhFirst; hResState = pLaunchTS->GetState((short)iAnyNode, &poleState); if (FAILED(hResState) || S_FALSE == hResState) break;; str = poleState; SysFreeString(poleNode); if (StrIsDigit((LPCTSTR) str)) node.val = _ttoi(str); else node.val = pApi->INode((LPCTSTR) str) + idhFirst; m_State.Push(node); m_Size++; m_aStatesFromServ[m_nStatesFromServ] = node; m_nStatesFromServ++; iAnyNode++; } while (true); return; } // Restore states to where CHttpQuery::FinishInitFromServ() left them void CHttpQuery::RestoreStatesFromServ() { UINT i; for (i=0; i < m_nStatesFromServ; i++) m_State.Push(m_aStatesFromServ[i]); } // // BOOL CHttpQuery::GetFirst(CString &strPut, CString &strValue) { BOOL bStatus = FALSE; if (0 < m_Size) { bStatus = TRUE; strPut = m_strCmd1; strValue = m_strVal1; m_CurrentUse = 0; } m_CurrentUse++; return bStatus; } void CHttpQuery::SetFirst(CString &strCmd, CString &strVal) { m_Size = 1; m_strCmd1 = strCmd; m_strVal1 = strVal; return; } // // BOOL CHttpQuery::GetNext(int &refedCmd, int &refedValue /*TCHAR *pCmd, TCHAR *pValue*/ ) { BOOL bStatus; CNode node; // The stack direction was made to be reversable // to support setting many nodes by an NT5 application using the TS Launcher. if (false == m_bReverseStack) bStatus = m_State.GetAt(m_CurrentUse, node); else bStatus = m_State.GetAt(m_Size - m_CurrentUse, node); refedCmd = node.cmd; refedValue = node.val; m_CurrentUse++; return bStatus; } void CHttpQuery::SetStackDirection() { if ((m_Size - m_CurrentUse) > 1) m_bReverseStack = true; else m_bReverseStack = false; } /* BOOL CHttpQuery::GetValue(int &Value, int index) { BOOL bRet = TRUE; CNode node; if (m_State.GetAt(index, node)) Value = node.val; else { Value = NULL; bRet = FALSE; } return bRet; } */ BOOL CHttpQuery::GetValue1(int &Value) { BOOL bRet = TRUE; CNode node; if (false == m_bReverseStack) { if (m_State.GetAt(1, node)) { Value = node.val; } else { Value = NULL; bRet = FALSE; } } else { if (m_State.GetAt(m_Size - 1, node)) { Value = node.val; } else { Value = NULL; bRet = FALSE; } } return bRet; } CString CHttpQuery::GetTroubleShooter() { CString str = m_pvarVals[0].bstrVal; return str; } CString CHttpQuery::GetFirstCmd() { CString str = m_pvarCmds[0].bstrVal; return str; } BOOL CHttpQuery::BackUp(BCache *pApi, APGTSContext *pCtx) { ASSERT(pApi); CNode node; BOOL bBack = FALSE; if (!m_State.Empty()) { bBack = TRUE; node = m_State.Pop(); if (!m_State.Empty()) { // Can not uninstantiate the problem page, it is not a real node. // Remove the node from the bnts network. if (node.val < 100) pApi->RemoveRecommendation(node.cmd - idhFirst); if (node.sniffed) // skip all sniffed nodes by recursive call of the function return BackUp(pApi, pCtx); pCtx->BackUp(node.cmd - idhFirst, node.val); } else { pApi->RemoveRecommendation(node.val - idhFirst); pCtx->BackUp(node.val - idhFirst, CBackupInfo::INVALID_BNTS_STATE); } } return bBack; } void CHttpQuery::RemoveNodes(BCache *pApi) { CNode node; while (!m_State.Empty()) { node = m_State.Pop(); if (!m_State.Empty()) { //VERIFY(pApi->BNodeSetCurrent(node.cmd - idhFirst)); //pApi->BNodeSet(-1, false); pApi->RemoveRecommendation(node.cmd - idhFirst); // we need remove all data assosiated with previous path } else { //VERIFY(pApi->BNodeSetCurrent(node.val - idhFirst)); //pApi->BNodeSet(-1, false); pApi->RemoveRecommendation(node.val - idhFirst); // we need remove all data assosiated with previous path } } pApi->RemoveStates(); return; } void CHttpQuery::AddNodes(BCache *pApi) { CNode node; RSStackstate; if (m_State.PeakFirst(node)) { do { state.Push(node); } while (m_State.PeakNext(node)); } if (!state.Empty()) { node = state.Pop(); VERIFY(pApi->GTSAPI::BNodeSetCurrent(node.val - idhFirst)); pApi->GTSAPI::BNodeSet(1, false); } while (!state.Empty()) { node = state.Pop(); if (node.val < 100) // We never instantiate the I don't know nodes. { VERIFY(pApi->GTSAPI::BNodeSetCurrent(node.cmd - idhFirst)); pApi->GTSAPI::BNodeSet(node.val, false); } } return; } CString CHttpQuery::GetSubmitString(BCache *pApi) { ASSERT(NULL != pApi); CNode node; RSStack stack; CString str; CString strGet = _T(""); if (m_State.PeakFirst(node)) { do { stack.Push(node); } while (m_State.PeakNext(node)); } if (!stack.Empty()) { node = stack.Pop(); if (pApi->BNodeSetCurrent(node.val - idhFirst)) { strGet += _T("&"); strGet += CHOOSE_TS_PROBLEM_NODE; strGet += _T("="); pApi->NodeSymName(); strGet += pApi->SzcResult(); } while (!stack.Empty()) { node = stack.Pop(); if (pApi->BNodeSetCurrent(node.cmd - idhFirst)) { strGet += _T("&"); pApi->NodeSymName(); strGet += pApi->SzcResult(); str.Format(_T("%d"), node.val); strGet += _T("=") + str; } } } return strGet; } void CHttpQuery::Debug() { CNode node; RSStackstate; CString str; if (m_State.PeakFirst(node)) { do { str.Format(_T("Cmd %d Val %d"), node.cmd, node.val); AfxMessageBox(str); } while (m_State.PeakNext(node)); } } CString& CHttpQuery::GetMachine() { return m_strMachineID; } CString& CHttpQuery::GetPNPDevice() { return m_strPNPDeviceID; } CString& CHttpQuery::GetDeviceInstance() { return m_strDeviceInstanceID; } CString& CHttpQuery::GetGuidClass() { return m_strGuidClass; }