WindowsXP-SP1/enduser/troubleshoot/tshoot/tshootctrl.cpp

977 lines
27 KiB
C++

//
// MODULE: TSHOOTCtrl.cpp
//
// PURPOSE: Implementation of CTSHOOTCtrl: Interface for the component
//
// PROJECT: Troubleshooter 99
//
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com
//
// AUTHOR: Oleg Kalosha
//
// ORIGINAL DATE: 12.23.98
//
// NOTES:
//
// Version Date By Comments
//--------------------------------------------------------------------
// V3.1 12/23/98 OK
#include "stdafx.h"
#include "TSHOOT.h"
#include "TSHOOTCtrl.h"
#include "LocalECB.h"
#include "apgts.h"
#include "apgtsinf.h"
#define APGTS_COUNTER_OWNER 1
#include "ApgtsCounters.h"
#include "apgtsinf.h"
#include "apgtspl.h"
#include "apgtscfg.h"
#include "apgtslog.h"
#include "event.h"
#include "apgtsinf.h"
#include "apgtscls.h"
#include "apgtsevt.h"
#include "VariantBuilder.h"
// Launcher integration
#include "LaunchServ.h"
#include "LaunchServ_i.c"
#include "CHMFileReader.h"
bool g_nLaunched = false;
extern HANDLE ghModule;
// Error codes for end user. Previously we gave verbose error messages. Microsoft
// decided 8/98 that they do not want to tell the end user about presumably internal problems.
// Hence these codes.
DWORD k_ServErrDuringInit = 1000; // Error(s) During Initialization: m_dwErr number follows
DWORD k_ServErrLimitedRequests = 1001; // The server has limited the number of requests
DWORD k_ServErrThreadTokenFail = 1002; // Failed to open thread token (impersonation token)
DWORD k_ServErrShuttingDown = 1003; // Server Shutting Down
DWORD k_ServErrOutOfMemory = 1005; // Out of memory (probably never will occur)
// Since VC++ v5.0 does not throw exceptions upon memory failure, we force the behavior.
_PNH APGST_New_Handler( size_t )
{
throw std::bad_alloc();
return( 0 );
}
/////////////////////////////////////////////////////////////////////////////
// CTSHOOTCtrl
CTSHOOTCtrl::CTSHOOTCtrl()
: m_bInitialized(false),
m_bFirstCall(true),
m_pThreadPool(NULL),
m_poolctl(NULL),
m_pConf(NULL),
m_pLog(NULL),
m_dwErr(0),
m_bShutdown(false),
m_dwRollover(0),
m_bStartedFromLauncher(false),
m_pVariantBuilder(NULL),
m_bRequestToSetLocale(false),
m_bCanRegisterGlobal(true)
{
// Set a new handler that throws bad_alloc exceptions (unlike VC++ v5.0).
m_SetNewHandlerPtr= _set_new_handler( (_PNH)APGST_New_Handler );
// Have malloc call the _set_new_handler upon failure to allocate memory.
m_SetNewMode= _set_new_mode( 1 );
if (RUNNING_APARTMENT_THREADED())
{
CoCreateInstance(CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
reinterpret_cast<void**>(&m_pGIT));
}
}
CTSHOOTCtrl::~CTSHOOTCtrl()
{
if (RUNNING_APARTMENT_THREADED())
{
for(vector<DWORD>::iterator it = m_vecCookies.begin(); it != m_vecCookies.end(); it++)
m_pGIT->RevokeInterfaceFromGlobal(*it);
m_pGIT->Release();
}
Destroy();
// Restore the initial set_new_handler and set_new_mode.
_set_new_handler( m_SetNewHandlerPtr );
// Restore the malloc handling as it was previously.
_set_new_mode( m_SetNewMode );
}
bool CTSHOOTCtrl::Init(HMODULE hModule)
{
try
{
//[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool after
// all new operations in this function.
m_poolctl= new CPoolQueue();
if(!m_poolctl)
throw bad_alloc();
if ((m_dwErr = m_poolctl->GetStatus()) != 0)
return false;
m_pThreadPool = new CThreadPool(m_poolctl, dynamic_cast<CSniffConnector*>(this));
if(!m_pThreadPool)
throw bad_alloc();
if ((m_dwErr = m_pThreadPool->GetStatus()) != 0)
return false;
// open log
m_pLog = new CHTMLLog( DEF_LOGFILEDIRECTORY );
if(!m_pLog)
throw bad_alloc();
if ((m_dwErr = m_pLog->GetStatus()) != 0)
return false;
m_pConf= new CDBLoadConfiguration(hModule, m_pThreadPool, m_strTopicName, m_pLog );
if(!m_pConf)
throw bad_alloc();
}
catch (bad_alloc&)
{
m_dwErr= EV_GTS_CANT_ALLOC;
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""), _T(""), m_dwErr );
return false;
}
return true;
}
void CTSHOOTCtrl::Destroy()
{
if (m_pThreadPool)
{
// >>>(ignore for V3.0) The following is not great encapsulation, but as of 9/22/98 we
// don't see a way around it. StartRequest falls naturally in APGTSExtension, so
// APGTSExtension ends up with responsibility to tell the pool threads to exit.
bool bAllSuccess = true;
// signal all working threads to quit
DWORD dwWorkingThreadCount = m_pThreadPool->GetWorkingThreadCount();
for (DWORD i = 0; i < dwWorkingThreadCount; i++)
if (StartRequest(NULL, NULL) != HSE_STATUS_PENDING)
bAllSuccess = false;
if (bAllSuccess == false)
{
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""),
_T(""),
EV_GTS_USER_BAD_THRD_REQ );
}
}
if (m_pConf)
delete m_pConf;
if (m_pThreadPool)
delete m_pThreadPool;
if (m_poolctl)
{
// [BC-022701] - Removed Unlock call here. Not matched with preceeding Lock() call.
// This never caused a problem until run on Debug build of WindowsXP. In this environment
// this Unlock call causes crash.
//m_poolctl->Unlock();
delete m_poolctl;
}
if (m_pLog)
delete m_pLog;
}
// coded on analogy with Online troubleshooter
DWORD CTSHOOTCtrl::HttpExtensionProc(CLocalECB* pECB)
{
bool fRet = false, bChange = false;
DWORD dwRet = HSE_STATUS_PENDING;
//HANDLE hImpersonationToken;
CString strTemp;
CLocalECB *pLocalECB = pECB;
if (m_dwErr)
{
strTemp.Format(_T("<P>Error %d:%d"), k_ServErrDuringInit, m_dwErr);
fRet = SendError( pLocalECB,
_T("500 Try again later"), // 500 is from HTTP spec
strTemp);
pLocalECB->SetHttpStatusCode(500);
return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
}
// Is the request queue (items requested by this fn to be serviced by working threads)
// too long? If so, tell the user to come back later
//
if ( m_poolctl->GetTotalQueueItems() + 1 > m_pConf->GetMaxWQItems() )
{
//
// Send a message back to client indicating we're too busy, they
// should try again later.
//
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""),
_T(""),
EV_GTS_SERVER_BUSY );
strTemp.Format(_T("<P>Error %d"), k_ServErrLimitedRequests);
fRet = SendError( pLocalECB,
_T("503 Try again later"),
strTemp );
pLocalECB->SetHttpStatusCode(503);
return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
}
//
// Capture the current impersonation token (IIS Security) so we can impersonate this
// user in the other thread. Limit permissions.
//
/*
if ( !::OpenThreadToken(::GetCurrentThread(),
TOKEN_QUERY | TOKEN_IMPERSONATE,
false, // Open in unimpersonated context
&hImpersonationToken ))
{
DWORD err = ::GetLastError();
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""),
_T(""),
EV_GTS_ERROR_THREAD_TOKEN );
strTemp.Format(_T("<P>Error %d"), k_ServErrThreadTokenFail);
fRet = SendError( pLocalECB,
_T("500 Try again later"),
strTemp );
pLocalECB->SetHttpStatusCode(500);
return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
}
*/
dwRet = StartRequest(pLocalECB, NULL/*hImpersonationToken*/);
return (dwRet);
}
// Thread-safe.
// NOTE TWO ROLES depending on INPUT pLocalECB.
// INPUT pLocalECB - NULL if shutting down
// Otherwise, EXTENSION_CONTROL_BLOCK is ISAPI's way of passing in the sort of
// stuff you'd get from CGI. We've abstracted from that.
// INPUT hImpersonationToken obtained via prior call to OpenThreadToken
// Not relevant if pLocalECB == NULL
// RETURNS HSE_STATUS_SUCCESS, HSE_STATUS_ERROR, HSE_STATUS_PENDING
// (or HSE_REQ_DONE_WITH_SESSION in single-threaded debugging version)
DWORD CTSHOOTCtrl::StartRequest(CLocalECB *pLocalECB, HANDLE hImpersonationToken)
{
WORK_QUEUE_ITEM * pwqi;
bool fRet = false;
CString strTemp;
//
// Take the queue lock, get a queue item and put it on the queue
//
if (pLocalECB && m_bShutdown)
{
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""),
_T(""),
EV_GTS_CANT_PROC_REQ_SS );
strTemp.Format(_T("<P>Error %d"), k_ServErrShuttingDown);
fRet = SendError( pLocalECB,
_T("500 Try again later"),
strTemp );
pLocalECB->SetHttpStatusCode(500);
::CloseHandle( hImpersonationToken );
return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
}
m_poolctl->Lock();
// 9/23/98 JM got rid of a constraint here which was too tight a constraint
// on size of queue
try
{
// bundle up pointers the worker thread will need
pwqi = new WORK_QUEUE_ITEM (
hImpersonationToken,
pLocalECB, // may be null as a signal
m_pConf,
m_pLog);
}
catch (bad_alloc&)
{
m_poolctl->Unlock();
if (pLocalECB)
{
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
_T(""),
_T(""),
EV_GTS_ERROR_WORK_ITEM );
strTemp.Format(_T("<P>Error %d"), k_ServErrOutOfMemory);
fRet = SendError( pLocalECB,
_T("500 Not enough memory"),
strTemp);
pLocalECB->SetHttpStatusCode(500);
::CloseHandle( hImpersonationToken );
}
return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
}
if (!pLocalECB)
m_bShutdown = true;
// Some data passed to thread just for statistical purposes
// Thread can pass this info back over web; we can't.
pwqi->GTSStat.dwRollover = m_dwRollover++;
// put it at the tail of the queue & signal the pool threads there is work to be done
m_poolctl->PushBack(pwqi);
m_poolctl->Unlock();
return HSE_STATUS_PENDING;
}
// Build an HTTP response in the case of an error.
// INPUT *pszStatus short status (e.g. "503 Server too busy").
// INPUT str - entire content of the page.
// RETURNS true on success
// NOTE that this actually uses no member variables.
/*static*/ bool CTSHOOTCtrl::SendSimpleHtmlPage( CLocalECB *pLocalECB,
LPCTSTR pszStatus,
const CString & str)
{
BOOL fRet;
DWORD cb;
TCHAR pszTemp[200]; // safely large to copy pszStatus. pLocalECB->ServerSupportFunction
// doesn't want pszStatus in a const array
_tcscpy(pszTemp, pszStatus);
// Send the headers
//
fRet = pLocalECB->ServerSupportFunction( HSE_REQ_SEND_RESPONSE_HEADER,
pszTemp,
NULL,
(LPDWORD) _T("Content-Type: text/html\r\n\r\n") );
//
// If that succeeded, send the message
//
if ( fRet )
{
cb = str.GetLength();
// (LPCTSTR) cast gives us the underlying text bytes.
// >>> $UNICODE Actually, this would screw up under Unicode compile, because for HTML,
// this must be SBCS. Should really be a conversion to LPCSTR, which is non-trivial
// in a Unicode compile. JM 1/7/99
fRet = pLocalECB->WriteClient((LPCTSTR)str, &cb);
}
return fRet ? true : false;
}
// Build an HTTP response in the case of an error.
// INPUT pLocalECB - EXTENSION_CONTROL_BLOCK is ISAPI's way of passing in the sort of
// stuff you'd get from CGI. We've abstracted from that. pLocalECB should never be null.
// INPUT *pszStatus short status (e.g. "503 Try again later").
// INPUT *pszMessage - typically just an error number, e.g. "1004" or
// "1000:123"
// RETURNS true on success
/*static*/ bool CTSHOOTCtrl::SendError( CDBLoadConfiguration *pConf,
CLocalECB *pLocalECB,
LPCTSTR pszStatus,
const CString & strMessage)
{
CString str;
pConf->CreateErrorPage(strMessage, str);
return SendSimpleHtmlPage( pLocalECB, pszStatus, str);
}
/*static*/ bool CTSHOOTCtrl::RemoveStartOverButton(CString& strWriteClient)
{
int left = 0, right = 0;
if (-1 != (left = strWriteClient.Find(SZ_INPUT_TAG_STARTOVER)))
{
right = left;
while (strWriteClient[++right] && strWriteClient[right] != _T('>'))
;
if (strWriteClient[right])
strWriteClient = strWriteClient.Left(left) + strWriteClient.Right(strWriteClient.GetLength() - right - 1);
else
return false;
return true;
}
return false;
}
/*static*/ bool CTSHOOTCtrl::RemoveBackButton(CString& strWriteClient)
{
int left = 0, right = 0;
if (-1 != (left = strWriteClient.Find(SZ_INPUT_TAG_BACK)))
{
right = left;
while (strWriteClient[++right] && strWriteClient[right] != _T('>'))
;
if (strWriteClient[right])
strWriteClient = strWriteClient.Left(left) + strWriteClient.Right(strWriteClient.GetLength() - right - 1);
else
return false;
return true;
}
return false;
}
bool CTSHOOTCtrl::SendError(CLocalECB *pLocalECB,
LPCTSTR pszStatus,
const CString & strMessage) const
{
return SendError(m_pConf, pLocalECB, pszStatus, strMessage);
}
bool CTSHOOTCtrl::ReadStaticPageFile(const CString& strTopicName, CString& strContent)
{
CString strPath;
if (!m_pConf->GetRegistryMonitor().GetStringInfo(CAPGTSRegConnector::eResourcePath, strPath))
return false;
CString strFullPath = strPath + strTopicName + LOCALTS_SUFFIX_RESULT + LOCALTS_EXTENSION_HTM;
CFileReader fileResult( CPhysicalFileReader::makeReader( strFullPath ) );
if (!fileResult.Read())
return false;
strContent = _T("");
fileResult.GetContent(strContent);
return true;
}
bool CTSHOOTCtrl::ExtractLauncherData(CString& error)
{
HRESULT hRes = S_OK;
DWORD dwResult = 0;
OLECHAR *poleShooter = NULL;
OLECHAR *poleProblem = NULL;
OLECHAR *poleNode = NULL;
OLECHAR *poleState = NULL;
OLECHAR *poleMachine = NULL;
OLECHAR *polePNPDevice = NULL;
OLECHAR *poleGuidClass = NULL;
OLECHAR *poleDeviceInstance = NULL;
short i = 0;
CNameValue name_value;
ILaunchTS *pILaunchTS = NULL;
CLSID clsidLaunchTS = CLSID_LaunchTS;
IID iidLaunchTS = IID_ILaunchTS;
// Get an interface on the launch server
hRes = ::CoCreateInstance(clsidLaunchTS, NULL,
CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER | CLSCTX_INPROC_SERVER,
iidLaunchTS, (void **) &pILaunchTS);
if (FAILED(hRes))
{
error = _T("LaunchServ interface not found.");
return false;
}
// Get all of the query values.
hRes = pILaunchTS->GetShooterStates(&dwResult);
if (S_FALSE == hRes || FAILED(hRes))
{
error.Format(_T("GetShooterStates Failed. %ld"), dwResult);
pILaunchTS->Release();
return false;
}
// clear container
m_arrNameValueFromLauncher.clear();
// get tshooter name
hRes = pILaunchTS->GetTroubleShooter(&poleShooter);
if (S_FALSE == hRes || FAILED(hRes))
{
error = _T("GetTroubleShooter Failed.");
pILaunchTS->Release();
return false;
}
name_value.strName = C_TOPIC;
name_value.strValue = poleShooter;
m_arrNameValueFromLauncher.push_back(name_value);
SysFreeString(poleShooter);
// get problem
hRes = pILaunchTS->GetProblem(&poleProblem);
if (S_FALSE != hRes && !FAILED(hRes))
{
name_value.strName = NODE_PROBLEM_ASK;
name_value.strValue = poleProblem;
m_arrNameValueFromLauncher.push_back(name_value);
SysFreeString(poleProblem);
// get name - value pairs for nodes set by the user
do
{
hRes = pILaunchTS->GetNode(i, &poleNode);
if (FAILED(hRes) || S_FALSE == hRes)
break;
name_value.strName = poleNode;
SysFreeString(poleNode);
hRes = pILaunchTS->GetState(i, &poleState);
if (FAILED(hRes) || S_FALSE == hRes)
break;
name_value.strValue = poleState;
SysFreeString(poleState);
m_arrNameValueFromLauncher.push_back(name_value);
i++;
}
while (true);
}
///////////////////////////////////////////////////////////
// obtaining Machine, PNPDevice, GuidClass, DeviceInstance
hRes = pILaunchTS->GetMachine(&poleMachine);
if (S_FALSE == hRes || FAILED(hRes))
{
error = _T("GetMachine Failed.");
pILaunchTS->Release();
return false;
}
m_strMachineID = poleMachine;
::SysFreeString(poleMachine);
hRes = pILaunchTS->GetPNPDevice(&polePNPDevice);
if (S_FALSE == hRes || FAILED(hRes))
{
error = _T("GetPNPDevice Failed.");
pILaunchTS->Release();
return false;
}
m_strPNPDeviceID = polePNPDevice;
::SysFreeString(polePNPDevice);
hRes = pILaunchTS->GetGuidClass(&poleGuidClass);
if (S_FALSE == hRes || FAILED(hRes))
{
error = _T("GetGuidClass Failed.");
pILaunchTS->Release();
return false;
}
m_strGuidClass = poleGuidClass;
::SysFreeString(poleGuidClass);
hRes = pILaunchTS->GetDeviceInstance(&poleDeviceInstance);
if (S_FALSE == hRes || FAILED(hRes))
{
error = _T("GetDeviceInstance Failed.");
pILaunchTS->Release();
return false;
}
m_strDeviceInstanceID = poleDeviceInstance;
::SysFreeString(poleDeviceInstance);
////////////////////////////////////////////////////////////
pILaunchTS->Release();
return true;
}
//
STDMETHODIMP CTSHOOTCtrl::RunQuery(VARIANT varCmds, VARIANT varVals, short size, BSTR *pbstrPage)
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
if (RUNNING_APARTMENT_THREADED())
{
if (m_bCanRegisterGlobal)
{
RegisterGlobal();
m_bCanRegisterGlobal = false;
}
}
//!!!!!!!!!!!!! Check for size < 1 !!!!!!!!!!!!!!!!!!!!!
if (size < 1)
{
*pbstrPage = T2BSTR("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error in RunQuery parameter: size is less one. </H4> </BODY> </HTML>");
return S_OK;
}
//!!!!!!!!!! detect the way we were stated !!!!!!!!!!!!!!
{
CString strStub;
CLocalECB ECB(varCmds, varVals, 1, NULL, &strStub, NULL,
m_bRequestToSetLocale, m_strRequestedLocale );
CString strFirstName = ECB.GetNameValue(0).strName;
if (strFirstName == NODE_LIBRARY_ASK)
{
if (g_nLaunched)
{
*pbstrPage = T2BSTR("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error in RunQuery: launched for the second time. </H4> </BODY> </HTML>");
return S_OK;
}
CString strError;
m_bStartedFromLauncher = true;
g_nLaunched = true;
if (!ExtractLauncherData(strError))
{
CString strOut;
strOut.Format(_T("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> %s. </H4> </BODY> </HTML>"), strError);
*pbstrPage = T2BSTR(strOut);
m_bStartedFromLauncher = false;
return S_OK;
}
}
}
/////////////////////////////////////////////////////////
// automatic variable declaration
HANDLE event = ::CreateEvent(NULL, false, false, NULL);
CString strWriteClient;
CLocalECB* pECB;
if (RUNNING_APARTMENT_THREADED())
pECB = !m_bStartedFromLauncher ? new CLocalECB(varCmds, varVals, size, NULL,
&strWriteClient,
dynamic_cast<CRenderConnector*>(this),
m_bRequestToSetLocale,
m_strRequestedLocale)
: new CLocalECB(m_arrNameValueFromLauncher,
NULL, &strWriteClient,
dynamic_cast<CRenderConnector*>(this),
m_bRequestToSetLocale,
m_strRequestedLocale);
if (RUNNING_FREE_THREADED())
pECB = !m_bStartedFromLauncher ? new CLocalECB(varCmds, varVals, size,
event, &strWriteClient, NULL,
m_bRequestToSetLocale,
m_strRequestedLocale)
: new CLocalECB(m_arrNameValueFromLauncher, event,
&strWriteClient, NULL,
m_bRequestToSetLocale,
m_strRequestedLocale);
m_bRequestToSetLocale= false; // Deactivate locale setting after it has been passed into the ECB.
SetLocked(true);
bool bSaveFirstPage = false;
/////////////////////////////////////////////////////////
// initialize
if (!m_bInitialized)
{
// extract topic name first
if (!m_bStartedFromLauncher)
{
CString strStub;
CLocalECB ECB(varCmds, varVals, 1, NULL, &strStub, NULL,
m_bRequestToSetLocale, m_strRequestedLocale );
m_strTopicName = ECB.GetNameValue(0).strValue;
}
else
m_strTopicName = (*m_arrNameValueFromLauncher.begin()).strValue;
if (Init((HINSTANCE)::ghModule))
{
m_bInitialized = true;
}
else
{
*pbstrPage = T2BSTR(_T("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error of initialization in RunQuery. </H4> </BODY> </HTML>"));
m_bStartedFromLauncher = false;
return S_OK;
}
}
//////////////////////////////////////////////////////////
// save first page when started from static page
if (m_strFirstPage.IsEmpty() && !m_bStartedFromLauncher)
{
CString strStaticPage;
if (size == 2 &&
// RunQuery was started from static (since !m_bStartedFromLauncher) Problem Page(since size == 2)
ReadStaticPageFile(m_strTopicName, strStaticPage)
)
{
m_strFirstPage = strStaticPage;
}
else
{
bSaveFirstPage = true;
}
}
HttpExtensionProc(pECB);
if (RUNNING_FREE_THREADED())
::WaitForSingleObject(event, INFINITE);
::CloseHandle(event);
if (bSaveFirstPage)
m_strFirstPage = strWriteClient;
/////////////////////////////////////////////////////////
// first RunQuery when started from Launcher
if (m_bStartedFromLauncher && m_bFirstCall)
{
RemoveStartOverButton(strWriteClient);
RemoveBackButton(strWriteClient);
}
/////////////////////////////////////////////////////////
// save first page when started from Launcher
if (m_strFirstPage.IsEmpty() && m_bStartedFromLauncher)
m_strFirstPage = strWriteClient;
*pbstrPage = T2BSTR(strWriteClient);
/*
//////////////////////////////////////////////////////////////////////////
// >>> $TEST
HANDLE hFile = ::CreateFile(_T("D:\\TShooter Projects\\Troubleshooter\\Local\\http\\Test\\first_step.htm"),
GENERIC_WRITE,
0,
NULL, // no security attributes
CREATE_ALWAYS,
FILE_FLAG_RANDOM_ACCESS,
NULL // handle to template file
);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD read = 0;
::WriteFile(hFile, (LPCTSTR)strWriteClient, strWriteClient.GetLength(), &read, NULL);
}
///////////////////////////////////////////////////////////////////////////
*/
m_bStartedFromLauncher = false;
m_bFirstCall = false;
return S_OK;
}
STDMETHODIMP CTSHOOTCtrl::SetSniffResult(VARIANT varNodeName, VARIANT varState, BOOL *bResult)
{
// >>> No sniffing is used. Oleg 03.26.99
*bResult = 1;
return S_OK;
}
STDMETHODIMP CTSHOOTCtrl::PreLoadURL(BSTR bstrRoot, BSTR *pbstrPage)
{
USES_CONVERSION;
// >>> This feature is not used. Oleg. 03.26.99
*pbstrPage = A2BSTR("PreLoadURL results");
return S_OK;
}
STDMETHODIMP CTSHOOTCtrl::Restart(BSTR *pbstrPage)
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
*pbstrPage = T2BSTR(m_strFirstPage);
return S_OK;
}
// The same as Restart(...).
// Implemented for compatibility with Win98's JScript
STDMETHODIMP CTSHOOTCtrl::ProblemPage(BSTR *pbstrFirstPage)
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
*pbstrFirstPage = T2BSTR(m_strFirstPage);
return S_OK;
}
STDMETHODIMP CTSHOOTCtrl::SetPair(BSTR bstrCmd, BSTR bstrVal)
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
if (!m_pVariantBuilder)
m_pVariantBuilder = new CVariantBuilder;
// check if we've started new sequence, but
// array of name - value pairs is not empty
CString type = W2T(bstrCmd);
if (type == C_TYPE || type == C_PRELOAD || type == C_TOPIC)
{
if (m_pVariantBuilder->GetSize())
{
delete m_pVariantBuilder;
m_pVariantBuilder = new CVariantBuilder;
}
}
m_pVariantBuilder->SetPair(bstrCmd, bstrVal);
return S_OK;
}
// The arguments are ignored. They are just for backward compatibility to V1.0.1.2121 & its
// successors
STDMETHODIMP CTSHOOTCtrl::RunQuery2(BSTR, BSTR, BSTR, BSTR *pbstrPage)
{
if (GetLocked())
return S_OK;
if (m_pVariantBuilder)
{
RunQuery(m_pVariantBuilder->GetCommands(),
m_pVariantBuilder->GetValues(),
m_pVariantBuilder->GetSize(),
pbstrPage);
delete m_pVariantBuilder;
m_pVariantBuilder = NULL;
}
return S_OK;
}
STDMETHODIMP CTSHOOTCtrl::NotifyNothingChecked(BSTR bstrMessage)
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
CString message = W2T(bstrMessage);
::MessageBox(::GetForegroundWindow(),
message != _T("") ? message : _T("Please choose a button and then press Next"),
_T("Error"),
MB_OK);
return S_OK;
}
long CTSHOOTCtrl::PerformSniffingInternal(CString strNodeName, CString strLaunchBasis, CString strAdditionalArgs)
{
USES_CONVERSION;
return Fire_Sniffing(T2BSTR((LPCTSTR)strNodeName), T2BSTR((LPCTSTR)strLaunchBasis), T2BSTR((LPCTSTR)strAdditionalArgs));
}
void CTSHOOTCtrl::RenderInternal(CString strPage)
{
USES_CONVERSION;
Fire_Render(T2BSTR((LPCTSTR)strPage));
}
void CTSHOOTCtrl::RegisterGlobal()
{
int nConnections = CProxy_ITSHOOTCtrlEvents< CTSHOOTCtrl >::m_vec.GetSize();
for (int nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
Lock();
CComPtr<IUnknown> sp = CProxy_ITSHOOTCtrlEvents< CTSHOOTCtrl >::m_vec.GetAt(nConnectionIndex);
Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
DWORD dwCookie;
m_pGIT->RegisterInterfaceInGlobal(pDispatch, IID_IDispatch, &dwCookie);
m_vecCookies.push_back(dwCookie);
}
}
}
STDMETHODIMP CTSHOOTCtrl::IsLocked(BOOL *pbResult)
{
*pbResult = GetLocked() ? TRUE : FALSE;
return S_OK;
}
// Set the locale.
// Parameter bstrNewLocale should be of the form:
// "lang[_country[.code_page]]"
// | ".code_page"
// | ""
// | NULL
STDMETHODIMP CTSHOOTCtrl::setLocale2( BSTR bstrNewLocale )
{
USES_CONVERSION;
if (GetLocked())
return S_OK;
m_strRequestedLocale= W2T( bstrNewLocale );
m_bRequestToSetLocale= true;
return S_OK;
}