977 lines
26 KiB
C++
977 lines
26 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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|