Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

976 lines
26 KiB

  1. //
  2. // MODULE: TSHOOTCtrl.cpp
  3. //
  4. // PURPOSE: Implementation of CTSHOOTCtrl: Interface for the component
  5. //
  6. // PROJECT: Troubleshooter 99
  7. //
  8. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  9. //
  10. // AUTHOR: Oleg Kalosha
  11. //
  12. // ORIGINAL DATE: 12.23.98
  13. //
  14. // NOTES:
  15. //
  16. // Version Date By Comments
  17. //--------------------------------------------------------------------
  18. // V3.1 12/23/98 OK
  19. #include "stdafx.h"
  20. #include "TSHOOT.h"
  21. #include "TSHOOTCtrl.h"
  22. #include "LocalECB.h"
  23. #include "apgts.h"
  24. #include "apgtsinf.h"
  25. #define APGTS_COUNTER_OWNER 1
  26. #include "ApgtsCounters.h"
  27. #include "apgtsinf.h"
  28. #include "apgtspl.h"
  29. #include "apgtscfg.h"
  30. #include "apgtslog.h"
  31. #include "event.h"
  32. #include "apgtsinf.h"
  33. #include "apgtscls.h"
  34. #include "apgtsevt.h"
  35. #include "VariantBuilder.h"
  36. // Launcher integration
  37. #include "LaunchServ.h"
  38. #include "LaunchServ_i.c"
  39. #include "CHMFileReader.h"
  40. bool g_nLaunched = false;
  41. extern HANDLE ghModule;
  42. // Error codes for end user. Previously we gave verbose error messages. Microsoft
  43. // decided 8/98 that they do not want to tell the end user about presumably internal problems.
  44. // Hence these codes.
  45. DWORD k_ServErrDuringInit = 1000; // Error(s) During Initialization: m_dwErr number follows
  46. DWORD k_ServErrLimitedRequests = 1001; // The server has limited the number of requests
  47. DWORD k_ServErrThreadTokenFail = 1002; // Failed to open thread token (impersonation token)
  48. DWORD k_ServErrShuttingDown = 1003; // Server Shutting Down
  49. DWORD k_ServErrOutOfMemory = 1005; // Out of memory (probably never will occur)
  50. // Since VC++ v5.0 does not throw exceptions upon memory failure, we force the behavior.
  51. _PNH APGST_New_Handler( size_t )
  52. {
  53. throw std::bad_alloc();
  54. return( 0 );
  55. }
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CTSHOOTCtrl
  58. CTSHOOTCtrl::CTSHOOTCtrl()
  59. : m_bInitialized(false),
  60. m_bFirstCall(true),
  61. m_pThreadPool(NULL),
  62. m_poolctl(NULL),
  63. m_pConf(NULL),
  64. m_pLog(NULL),
  65. m_dwErr(0),
  66. m_bShutdown(false),
  67. m_dwRollover(0),
  68. m_bStartedFromLauncher(false),
  69. m_pVariantBuilder(NULL),
  70. m_bRequestToSetLocale(false),
  71. m_bCanRegisterGlobal(true)
  72. {
  73. // Set a new handler that throws bad_alloc exceptions (unlike VC++ v5.0).
  74. m_SetNewHandlerPtr= _set_new_handler( (_PNH)APGST_New_Handler );
  75. // Have malloc call the _set_new_handler upon failure to allocate memory.
  76. m_SetNewMode= _set_new_mode( 1 );
  77. if (RUNNING_APARTMENT_THREADED())
  78. {
  79. CoCreateInstance(CLSID_StdGlobalInterfaceTable,
  80. NULL,
  81. CLSCTX_INPROC_SERVER,
  82. IID_IGlobalInterfaceTable,
  83. reinterpret_cast<void**>(&m_pGIT));
  84. }
  85. }
  86. CTSHOOTCtrl::~CTSHOOTCtrl()
  87. {
  88. if (RUNNING_APARTMENT_THREADED())
  89. {
  90. for(vector<DWORD>::iterator it = m_vecCookies.begin(); it != m_vecCookies.end(); it++)
  91. m_pGIT->RevokeInterfaceFromGlobal(*it);
  92. m_pGIT->Release();
  93. }
  94. Destroy();
  95. // Restore the initial set_new_handler and set_new_mode.
  96. _set_new_handler( m_SetNewHandlerPtr );
  97. // Restore the malloc handling as it was previously.
  98. _set_new_mode( m_SetNewMode );
  99. }
  100. bool CTSHOOTCtrl::Init(HMODULE hModule)
  101. {
  102. try
  103. {
  104. //[BC-03022001] - added check for NULL ptr to satisfy MS code analysis tool after
  105. // all new operations in this function.
  106. m_poolctl= new CPoolQueue();
  107. if(!m_poolctl)
  108. throw bad_alloc();
  109. if ((m_dwErr = m_poolctl->GetStatus()) != 0)
  110. return false;
  111. m_pThreadPool = new CThreadPool(m_poolctl, dynamic_cast<CSniffConnector*>(this));
  112. if(!m_pThreadPool)
  113. throw bad_alloc();
  114. if ((m_dwErr = m_pThreadPool->GetStatus()) != 0)
  115. return false;
  116. // open log
  117. m_pLog = new CHTMLLog( DEF_LOGFILEDIRECTORY );
  118. if(!m_pLog)
  119. throw bad_alloc();
  120. if ((m_dwErr = m_pLog->GetStatus()) != 0)
  121. return false;
  122. m_pConf= new CDBLoadConfiguration(hModule, m_pThreadPool, m_strTopicName, m_pLog );
  123. if(!m_pConf)
  124. throw bad_alloc();
  125. }
  126. catch (bad_alloc&)
  127. {
  128. m_dwErr= EV_GTS_CANT_ALLOC;
  129. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  130. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  131. SrcLoc.GetSrcFileLineStr(),
  132. _T(""), _T(""), m_dwErr );
  133. return false;
  134. }
  135. return true;
  136. }
  137. void CTSHOOTCtrl::Destroy()
  138. {
  139. if (m_pThreadPool)
  140. {
  141. // >>>(ignore for V3.0) The following is not great encapsulation, but as of 9/22/98 we
  142. // don't see a way around it. StartRequest falls naturally in APGTSExtension, so
  143. // APGTSExtension ends up with responsibility to tell the pool threads to exit.
  144. bool bAllSuccess = true;
  145. // signal all working threads to quit
  146. DWORD dwWorkingThreadCount = m_pThreadPool->GetWorkingThreadCount();
  147. for (DWORD i = 0; i < dwWorkingThreadCount; i++)
  148. if (StartRequest(NULL, NULL) != HSE_STATUS_PENDING)
  149. bAllSuccess = false;
  150. if (bAllSuccess == false)
  151. {
  152. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  153. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  154. SrcLoc.GetSrcFileLineStr(),
  155. _T(""),
  156. _T(""),
  157. EV_GTS_USER_BAD_THRD_REQ );
  158. }
  159. }
  160. if (m_pConf)
  161. delete m_pConf;
  162. if (m_pThreadPool)
  163. delete m_pThreadPool;
  164. if (m_poolctl)
  165. {
  166. // [BC-022701] - Removed Unlock call here. Not matched with preceeding Lock() call.
  167. // This never caused a problem until run on Debug build of WindowsXP. In this environment
  168. // this Unlock call causes crash.
  169. //m_poolctl->Unlock();
  170. delete m_poolctl;
  171. }
  172. if (m_pLog)
  173. delete m_pLog;
  174. }
  175. // coded on analogy with Online troubleshooter
  176. DWORD CTSHOOTCtrl::HttpExtensionProc(CLocalECB* pECB)
  177. {
  178. bool fRet = false, bChange = false;
  179. DWORD dwRet = HSE_STATUS_PENDING;
  180. //HANDLE hImpersonationToken;
  181. CString strTemp;
  182. CLocalECB *pLocalECB = pECB;
  183. if (m_dwErr)
  184. {
  185. strTemp.Format(_T("<P>Error %d:%d"), k_ServErrDuringInit, m_dwErr);
  186. fRet = SendError( pLocalECB,
  187. _T("500 Try again later"), // 500 is from HTTP spec
  188. strTemp);
  189. pLocalECB->SetHttpStatusCode(500);
  190. return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
  191. }
  192. // Is the request queue (items requested by this fn to be serviced by working threads)
  193. // too long? If so, tell the user to come back later
  194. //
  195. if ( m_poolctl->GetTotalQueueItems() + 1 > m_pConf->GetMaxWQItems() )
  196. {
  197. //
  198. // Send a message back to client indicating we're too busy, they
  199. // should try again later.
  200. //
  201. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  202. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  203. SrcLoc.GetSrcFileLineStr(),
  204. _T(""),
  205. _T(""),
  206. EV_GTS_SERVER_BUSY );
  207. strTemp.Format(_T("<P>Error %d"), k_ServErrLimitedRequests);
  208. fRet = SendError( pLocalECB,
  209. _T("503 Try again later"),
  210. strTemp );
  211. pLocalECB->SetHttpStatusCode(503);
  212. return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
  213. }
  214. //
  215. // Capture the current impersonation token (IIS Security) so we can impersonate this
  216. // user in the other thread. Limit permissions.
  217. //
  218. /*
  219. if ( !::OpenThreadToken(::GetCurrentThread(),
  220. TOKEN_QUERY | TOKEN_IMPERSONATE,
  221. false, // Open in unimpersonated context
  222. &hImpersonationToken ))
  223. {
  224. DWORD err = ::GetLastError();
  225. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  226. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  227. SrcLoc.GetSrcFileLineStr(),
  228. _T(""),
  229. _T(""),
  230. EV_GTS_ERROR_THREAD_TOKEN );
  231. strTemp.Format(_T("<P>Error %d"), k_ServErrThreadTokenFail);
  232. fRet = SendError( pLocalECB,
  233. _T("500 Try again later"),
  234. strTemp );
  235. pLocalECB->SetHttpStatusCode(500);
  236. return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
  237. }
  238. */
  239. dwRet = StartRequest(pLocalECB, NULL/*hImpersonationToken*/);
  240. return (dwRet);
  241. }
  242. // Thread-safe.
  243. // NOTE TWO ROLES depending on INPUT pLocalECB.
  244. // INPUT pLocalECB - NULL if shutting down
  245. // Otherwise, EXTENSION_CONTROL_BLOCK is ISAPI's way of passing in the sort of
  246. // stuff you'd get from CGI. We've abstracted from that.
  247. // INPUT hImpersonationToken obtained via prior call to OpenThreadToken
  248. // Not relevant if pLocalECB == NULL
  249. // RETURNS HSE_STATUS_SUCCESS, HSE_STATUS_ERROR, HSE_STATUS_PENDING
  250. // (or HSE_REQ_DONE_WITH_SESSION in single-threaded debugging version)
  251. DWORD CTSHOOTCtrl::StartRequest(CLocalECB *pLocalECB, HANDLE hImpersonationToken)
  252. {
  253. WORK_QUEUE_ITEM * pwqi;
  254. bool fRet = false;
  255. CString strTemp;
  256. //
  257. // Take the queue lock, get a queue item and put it on the queue
  258. //
  259. if (pLocalECB && m_bShutdown)
  260. {
  261. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  262. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  263. SrcLoc.GetSrcFileLineStr(),
  264. _T(""),
  265. _T(""),
  266. EV_GTS_CANT_PROC_REQ_SS );
  267. strTemp.Format(_T("<P>Error %d"), k_ServErrShuttingDown);
  268. fRet = SendError( pLocalECB,
  269. _T("500 Try again later"),
  270. strTemp );
  271. pLocalECB->SetHttpStatusCode(500);
  272. ::CloseHandle( hImpersonationToken );
  273. return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
  274. }
  275. m_poolctl->Lock();
  276. // 9/23/98 JM got rid of a constraint here which was too tight a constraint
  277. // on size of queue
  278. try
  279. {
  280. // bundle up pointers the worker thread will need
  281. pwqi = new WORK_QUEUE_ITEM (
  282. hImpersonationToken,
  283. pLocalECB, // may be null as a signal
  284. m_pConf,
  285. m_pLog);
  286. }
  287. catch (bad_alloc&)
  288. {
  289. m_poolctl->Unlock();
  290. if (pLocalECB)
  291. {
  292. CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
  293. CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
  294. SrcLoc.GetSrcFileLineStr(),
  295. _T(""),
  296. _T(""),
  297. EV_GTS_ERROR_WORK_ITEM );
  298. strTemp.Format(_T("<P>Error %d"), k_ServErrOutOfMemory);
  299. fRet = SendError( pLocalECB,
  300. _T("500 Not enough memory"),
  301. strTemp);
  302. pLocalECB->SetHttpStatusCode(500);
  303. ::CloseHandle( hImpersonationToken );
  304. }
  305. return fRet ? HSE_STATUS_SUCCESS : HSE_STATUS_ERROR;
  306. }
  307. if (!pLocalECB)
  308. m_bShutdown = true;
  309. // Some data passed to thread just for statistical purposes
  310. // Thread can pass this info back over web; we can't.
  311. pwqi->GTSStat.dwRollover = m_dwRollover++;
  312. // put it at the tail of the queue & signal the pool threads there is work to be done
  313. m_poolctl->PushBack(pwqi);
  314. m_poolctl->Unlock();
  315. return HSE_STATUS_PENDING;
  316. }
  317. // Build an HTTP response in the case of an error.
  318. // INPUT *pszStatus short status (e.g. "503 Server too busy").
  319. // INPUT str - entire content of the page.
  320. // RETURNS true on success
  321. // NOTE that this actually uses no member variables.
  322. /*static*/ bool CTSHOOTCtrl::SendSimpleHtmlPage( CLocalECB *pLocalECB,
  323. LPCTSTR pszStatus,
  324. const CString & str)
  325. {
  326. BOOL fRet;
  327. DWORD cb;
  328. TCHAR pszTemp[200]; // safely large to copy pszStatus. pLocalECB->ServerSupportFunction
  329. // doesn't want pszStatus in a const array
  330. _tcscpy(pszTemp, pszStatus);
  331. // Send the headers
  332. //
  333. fRet = pLocalECB->ServerSupportFunction( HSE_REQ_SEND_RESPONSE_HEADER,
  334. pszTemp,
  335. NULL,
  336. (LPDWORD) _T("Content-Type: text/html\r\n\r\n") );
  337. //
  338. // If that succeeded, send the message
  339. //
  340. if ( fRet )
  341. {
  342. cb = str.GetLength();
  343. // (LPCTSTR) cast gives us the underlying text bytes.
  344. // >>> $UNICODE Actually, this would screw up under Unicode compile, because for HTML,
  345. // this must be SBCS. Should really be a conversion to LPCSTR, which is non-trivial
  346. // in a Unicode compile. JM 1/7/99
  347. fRet = pLocalECB->WriteClient((LPCTSTR)str, &cb);
  348. }
  349. return fRet ? true : false;
  350. }
  351. // Build an HTTP response in the case of an error.
  352. // INPUT pLocalECB - EXTENSION_CONTROL_BLOCK is ISAPI's way of passing in the sort of
  353. // stuff you'd get from CGI. We've abstracted from that. pLocalECB should never be null.
  354. // INPUT *pszStatus short status (e.g. "503 Try again later").
  355. // INPUT *pszMessage - typically just an error number, e.g. "1004" or
  356. // "1000:123"
  357. // RETURNS true on success
  358. /*static*/ bool CTSHOOTCtrl::SendError( CDBLoadConfiguration *pConf,
  359. CLocalECB *pLocalECB,
  360. LPCTSTR pszStatus,
  361. const CString & strMessage)
  362. {
  363. CString str;
  364. pConf->CreateErrorPage(strMessage, str);
  365. return SendSimpleHtmlPage( pLocalECB, pszStatus, str);
  366. }
  367. /*static*/ bool CTSHOOTCtrl::RemoveStartOverButton(CString& strWriteClient)
  368. {
  369. int left = 0, right = 0;
  370. if (-1 != (left = strWriteClient.Find(SZ_INPUT_TAG_STARTOVER)))
  371. {
  372. right = left;
  373. while (strWriteClient[++right] && strWriteClient[right] != _T('>'))
  374. ;
  375. if (strWriteClient[right])
  376. strWriteClient = strWriteClient.Left(left) + strWriteClient.Right(strWriteClient.GetLength() - right - 1);
  377. else
  378. return false;
  379. return true;
  380. }
  381. return false;
  382. }
  383. /*static*/ bool CTSHOOTCtrl::RemoveBackButton(CString& strWriteClient)
  384. {
  385. int left = 0, right = 0;
  386. if (-1 != (left = strWriteClient.Find(SZ_INPUT_TAG_BACK)))
  387. {
  388. right = left;
  389. while (strWriteClient[++right] && strWriteClient[right] != _T('>'))
  390. ;
  391. if (strWriteClient[right])
  392. strWriteClient = strWriteClient.Left(left) + strWriteClient.Right(strWriteClient.GetLength() - right - 1);
  393. else
  394. return false;
  395. return true;
  396. }
  397. return false;
  398. }
  399. bool CTSHOOTCtrl::SendError(CLocalECB *pLocalECB,
  400. LPCTSTR pszStatus,
  401. const CString & strMessage) const
  402. {
  403. return SendError(m_pConf, pLocalECB, pszStatus, strMessage);
  404. }
  405. bool CTSHOOTCtrl::ReadStaticPageFile(const CString& strTopicName, CString& strContent)
  406. {
  407. CString strPath;
  408. if (!m_pConf->GetRegistryMonitor().GetStringInfo(CAPGTSRegConnector::eResourcePath, strPath))
  409. return false;
  410. CString strFullPath = strPath + strTopicName + LOCALTS_SUFFIX_RESULT + LOCALTS_EXTENSION_HTM;
  411. CFileReader fileResult( CPhysicalFileReader::makeReader( strFullPath ) );
  412. if (!fileResult.Read())
  413. return false;
  414. strContent = _T("");
  415. fileResult.GetContent(strContent);
  416. return true;
  417. }
  418. bool CTSHOOTCtrl::ExtractLauncherData(CString& error)
  419. {
  420. HRESULT hRes = S_OK;
  421. DWORD dwResult = 0;
  422. OLECHAR *poleShooter = NULL;
  423. OLECHAR *poleProblem = NULL;
  424. OLECHAR *poleNode = NULL;
  425. OLECHAR *poleState = NULL;
  426. OLECHAR *poleMachine = NULL;
  427. OLECHAR *polePNPDevice = NULL;
  428. OLECHAR *poleGuidClass = NULL;
  429. OLECHAR *poleDeviceInstance = NULL;
  430. short i = 0;
  431. CNameValue name_value;
  432. ILaunchTS *pILaunchTS = NULL;
  433. CLSID clsidLaunchTS = CLSID_LaunchTS;
  434. IID iidLaunchTS = IID_ILaunchTS;
  435. // Get an interface on the launch server
  436. hRes = ::CoCreateInstance(clsidLaunchTS, NULL,
  437. CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER | CLSCTX_INPROC_SERVER,
  438. iidLaunchTS, (void **) &pILaunchTS);
  439. if (FAILED(hRes))
  440. {
  441. error = _T("LaunchServ interface not found.");
  442. return false;
  443. }
  444. // Get all of the query values.
  445. hRes = pILaunchTS->GetShooterStates(&dwResult);
  446. if (S_FALSE == hRes || FAILED(hRes))
  447. {
  448. error.Format(_T("GetShooterStates Failed. %ld"), dwResult);
  449. pILaunchTS->Release();
  450. return false;
  451. }
  452. // clear container
  453. m_arrNameValueFromLauncher.clear();
  454. // get tshooter name
  455. hRes = pILaunchTS->GetTroubleShooter(&poleShooter);
  456. if (S_FALSE == hRes || FAILED(hRes))
  457. {
  458. error = _T("GetTroubleShooter Failed.");
  459. pILaunchTS->Release();
  460. return false;
  461. }
  462. name_value.strName = C_TOPIC;
  463. name_value.strValue = poleShooter;
  464. m_arrNameValueFromLauncher.push_back(name_value);
  465. SysFreeString(poleShooter);
  466. // get problem
  467. hRes = pILaunchTS->GetProblem(&poleProblem);
  468. if (S_FALSE != hRes && !FAILED(hRes))
  469. {
  470. name_value.strName = NODE_PROBLEM_ASK;
  471. name_value.strValue = poleProblem;
  472. m_arrNameValueFromLauncher.push_back(name_value);
  473. SysFreeString(poleProblem);
  474. // get name - value pairs for nodes set by the user
  475. do
  476. {
  477. hRes = pILaunchTS->GetNode(i, &poleNode);
  478. if (FAILED(hRes) || S_FALSE == hRes)
  479. break;
  480. name_value.strName = poleNode;
  481. SysFreeString(poleNode);
  482. hRes = pILaunchTS->GetState(i, &poleState);
  483. if (FAILED(hRes) || S_FALSE == hRes)
  484. break;
  485. name_value.strValue = poleState;
  486. SysFreeString(poleState);
  487. m_arrNameValueFromLauncher.push_back(name_value);
  488. i++;
  489. }
  490. while (true);
  491. }
  492. ///////////////////////////////////////////////////////////
  493. // obtaining Machine, PNPDevice, GuidClass, DeviceInstance
  494. hRes = pILaunchTS->GetMachine(&poleMachine);
  495. if (S_FALSE == hRes || FAILED(hRes))
  496. {
  497. error = _T("GetMachine Failed.");
  498. pILaunchTS->Release();
  499. return false;
  500. }
  501. m_strMachineID = poleMachine;
  502. ::SysFreeString(poleMachine);
  503. hRes = pILaunchTS->GetPNPDevice(&polePNPDevice);
  504. if (S_FALSE == hRes || FAILED(hRes))
  505. {
  506. error = _T("GetPNPDevice Failed.");
  507. pILaunchTS->Release();
  508. return false;
  509. }
  510. m_strPNPDeviceID = polePNPDevice;
  511. ::SysFreeString(polePNPDevice);
  512. hRes = pILaunchTS->GetGuidClass(&poleGuidClass);
  513. if (S_FALSE == hRes || FAILED(hRes))
  514. {
  515. error = _T("GetGuidClass Failed.");
  516. pILaunchTS->Release();
  517. return false;
  518. }
  519. m_strGuidClass = poleGuidClass;
  520. ::SysFreeString(poleGuidClass);
  521. hRes = pILaunchTS->GetDeviceInstance(&poleDeviceInstance);
  522. if (S_FALSE == hRes || FAILED(hRes))
  523. {
  524. error = _T("GetDeviceInstance Failed.");
  525. pILaunchTS->Release();
  526. return false;
  527. }
  528. m_strDeviceInstanceID = poleDeviceInstance;
  529. ::SysFreeString(poleDeviceInstance);
  530. ////////////////////////////////////////////////////////////
  531. pILaunchTS->Release();
  532. return true;
  533. }
  534. //
  535. STDMETHODIMP CTSHOOTCtrl::RunQuery(VARIANT varCmds, VARIANT varVals, short size, BSTR *pbstrPage)
  536. {
  537. USES_CONVERSION;
  538. if (GetLocked())
  539. return S_OK;
  540. if (RUNNING_APARTMENT_THREADED())
  541. {
  542. if (m_bCanRegisterGlobal)
  543. {
  544. RegisterGlobal();
  545. m_bCanRegisterGlobal = false;
  546. }
  547. }
  548. //!!!!!!!!!!!!! Check for size < 1 !!!!!!!!!!!!!!!!!!!!!
  549. if (size < 1)
  550. {
  551. *pbstrPage = T2BSTR("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error in RunQuery parameter: size is less one. </H4> </BODY> </HTML>");
  552. return S_OK;
  553. }
  554. //!!!!!!!!!! detect the way we were stated !!!!!!!!!!!!!!
  555. {
  556. CString strStub;
  557. CLocalECB ECB(varCmds, varVals, 1, NULL, &strStub, NULL,
  558. m_bRequestToSetLocale, m_strRequestedLocale );
  559. CString strFirstName = ECB.GetNameValue(0).strName;
  560. if (strFirstName == NODE_LIBRARY_ASK)
  561. {
  562. if (g_nLaunched)
  563. {
  564. *pbstrPage = T2BSTR("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error in RunQuery: launched for the second time. </H4> </BODY> </HTML>");
  565. return S_OK;
  566. }
  567. CString strError;
  568. m_bStartedFromLauncher = true;
  569. g_nLaunched = true;
  570. if (!ExtractLauncherData(strError))
  571. {
  572. CString strOut;
  573. strOut.Format(_T("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> %s. </H4> </BODY> </HTML>"), strError);
  574. *pbstrPage = T2BSTR(strOut);
  575. m_bStartedFromLauncher = false;
  576. return S_OK;
  577. }
  578. }
  579. }
  580. /////////////////////////////////////////////////////////
  581. // automatic variable declaration
  582. HANDLE event = ::CreateEvent(NULL, false, false, NULL);
  583. CString strWriteClient;
  584. CLocalECB* pECB;
  585. if (RUNNING_APARTMENT_THREADED())
  586. pECB = !m_bStartedFromLauncher ? new CLocalECB(varCmds, varVals, size, NULL,
  587. &strWriteClient,
  588. dynamic_cast<CRenderConnector*>(this),
  589. m_bRequestToSetLocale,
  590. m_strRequestedLocale)
  591. : new CLocalECB(m_arrNameValueFromLauncher,
  592. NULL, &strWriteClient,
  593. dynamic_cast<CRenderConnector*>(this),
  594. m_bRequestToSetLocale,
  595. m_strRequestedLocale);
  596. if (RUNNING_FREE_THREADED())
  597. pECB = !m_bStartedFromLauncher ? new CLocalECB(varCmds, varVals, size,
  598. event, &strWriteClient, NULL,
  599. m_bRequestToSetLocale,
  600. m_strRequestedLocale)
  601. : new CLocalECB(m_arrNameValueFromLauncher, event,
  602. &strWriteClient, NULL,
  603. m_bRequestToSetLocale,
  604. m_strRequestedLocale);
  605. m_bRequestToSetLocale= false; // Deactivate locale setting after it has been passed into the ECB.
  606. SetLocked(true);
  607. bool bSaveFirstPage = false;
  608. /////////////////////////////////////////////////////////
  609. // initialize
  610. if (!m_bInitialized)
  611. {
  612. // extract topic name first
  613. if (!m_bStartedFromLauncher)
  614. {
  615. CString strStub;
  616. CLocalECB ECB(varCmds, varVals, 1, NULL, &strStub, NULL,
  617. m_bRequestToSetLocale, m_strRequestedLocale );
  618. m_strTopicName = ECB.GetNameValue(0).strValue;
  619. }
  620. else
  621. m_strTopicName = (*m_arrNameValueFromLauncher.begin()).strValue;
  622. if (Init((HINSTANCE)::ghModule))
  623. {
  624. m_bInitialized = true;
  625. }
  626. else
  627. {
  628. *pbstrPage = T2BSTR(_T("<HTML> <HEAD> <TITLE>Troubleshooter</TITLE> </HEAD> <BODY> <H4> Error of initialization in RunQuery. </H4> </BODY> </HTML>"));
  629. m_bStartedFromLauncher = false;
  630. return S_OK;
  631. }
  632. }
  633. //////////////////////////////////////////////////////////
  634. // save first page when started from static page
  635. if (m_strFirstPage.IsEmpty() && !m_bStartedFromLauncher)
  636. {
  637. CString strStaticPage;
  638. if (size == 2 &&
  639. // RunQuery was started from static (since !m_bStartedFromLauncher) Problem Page(since size == 2)
  640. ReadStaticPageFile(m_strTopicName, strStaticPage)
  641. )
  642. {
  643. m_strFirstPage = strStaticPage;
  644. }
  645. else
  646. {
  647. bSaveFirstPage = true;
  648. }
  649. }
  650. HttpExtensionProc(pECB);
  651. if (RUNNING_FREE_THREADED())
  652. ::WaitForSingleObject(event, INFINITE);
  653. ::CloseHandle(event);
  654. if (bSaveFirstPage)
  655. m_strFirstPage = strWriteClient;
  656. /////////////////////////////////////////////////////////
  657. // first RunQuery when started from Launcher
  658. if (m_bStartedFromLauncher && m_bFirstCall)
  659. {
  660. RemoveStartOverButton(strWriteClient);
  661. RemoveBackButton(strWriteClient);
  662. }
  663. /////////////////////////////////////////////////////////
  664. // save first page when started from Launcher
  665. if (m_strFirstPage.IsEmpty() && m_bStartedFromLauncher)
  666. m_strFirstPage = strWriteClient;
  667. *pbstrPage = T2BSTR(strWriteClient);
  668. /*
  669. //////////////////////////////////////////////////////////////////////////
  670. // >>> $TEST
  671. HANDLE hFile = ::CreateFile(_T("D:\\TShooter Projects\\Troubleshooter\\Local\\http\\Test\\first_step.htm"),
  672. GENERIC_WRITE,
  673. 0,
  674. NULL, // no security attributes
  675. CREATE_ALWAYS,
  676. FILE_FLAG_RANDOM_ACCESS,
  677. NULL // handle to template file
  678. );
  679. if (hFile != INVALID_HANDLE_VALUE)
  680. {
  681. DWORD read = 0;
  682. ::WriteFile(hFile, (LPCTSTR)strWriteClient, strWriteClient.GetLength(), &read, NULL);
  683. }
  684. ///////////////////////////////////////////////////////////////////////////
  685. */
  686. m_bStartedFromLauncher = false;
  687. m_bFirstCall = false;
  688. return S_OK;
  689. }
  690. STDMETHODIMP CTSHOOTCtrl::SetSniffResult(VARIANT varNodeName, VARIANT varState, BOOL *bResult)
  691. {
  692. // >>> No sniffing is used. Oleg 03.26.99
  693. *bResult = 1;
  694. return S_OK;
  695. }
  696. STDMETHODIMP CTSHOOTCtrl::PreLoadURL(BSTR bstrRoot, BSTR *pbstrPage)
  697. {
  698. USES_CONVERSION;
  699. // >>> This feature is not used. Oleg. 03.26.99
  700. *pbstrPage = A2BSTR("PreLoadURL results");
  701. return S_OK;
  702. }
  703. STDMETHODIMP CTSHOOTCtrl::Restart(BSTR *pbstrPage)
  704. {
  705. USES_CONVERSION;
  706. if (GetLocked())
  707. return S_OK;
  708. *pbstrPage = T2BSTR(m_strFirstPage);
  709. return S_OK;
  710. }
  711. // The same as Restart(...).
  712. // Implemented for compatibility with Win98's JScript
  713. STDMETHODIMP CTSHOOTCtrl::ProblemPage(BSTR *pbstrFirstPage)
  714. {
  715. USES_CONVERSION;
  716. if (GetLocked())
  717. return S_OK;
  718. *pbstrFirstPage = T2BSTR(m_strFirstPage);
  719. return S_OK;
  720. }
  721. STDMETHODIMP CTSHOOTCtrl::SetPair(BSTR bstrCmd, BSTR bstrVal)
  722. {
  723. USES_CONVERSION;
  724. if (GetLocked())
  725. return S_OK;
  726. if (!m_pVariantBuilder)
  727. m_pVariantBuilder = new CVariantBuilder;
  728. // check if we've started new sequence, but
  729. // array of name - value pairs is not empty
  730. CString type = W2T(bstrCmd);
  731. if (type == C_TYPE || type == C_PRELOAD || type == C_TOPIC)
  732. {
  733. if (m_pVariantBuilder->GetSize())
  734. {
  735. delete m_pVariantBuilder;
  736. m_pVariantBuilder = new CVariantBuilder;
  737. }
  738. }
  739. m_pVariantBuilder->SetPair(bstrCmd, bstrVal);
  740. return S_OK;
  741. }
  742. // The arguments are ignored. They are just for backward compatibility to V1.0.1.2121 & its
  743. // successors
  744. STDMETHODIMP CTSHOOTCtrl::RunQuery2(BSTR, BSTR, BSTR, BSTR *pbstrPage)
  745. {
  746. if (GetLocked())
  747. return S_OK;
  748. if (m_pVariantBuilder)
  749. {
  750. RunQuery(m_pVariantBuilder->GetCommands(),
  751. m_pVariantBuilder->GetValues(),
  752. m_pVariantBuilder->GetSize(),
  753. pbstrPage);
  754. delete m_pVariantBuilder;
  755. m_pVariantBuilder = NULL;
  756. }
  757. return S_OK;
  758. }
  759. STDMETHODIMP CTSHOOTCtrl::NotifyNothingChecked(BSTR bstrMessage)
  760. {
  761. USES_CONVERSION;
  762. if (GetLocked())
  763. return S_OK;
  764. CString message = W2T(bstrMessage);
  765. ::MessageBox(::GetForegroundWindow(),
  766. message != _T("") ? message : _T("Please choose a button and then press Next"),
  767. _T("Error"),
  768. MB_OK);
  769. return S_OK;
  770. }
  771. long CTSHOOTCtrl::PerformSniffingInternal(CString strNodeName, CString strLaunchBasis, CString strAdditionalArgs)
  772. {
  773. USES_CONVERSION;
  774. return Fire_Sniffing(T2BSTR((LPCTSTR)strNodeName), T2BSTR((LPCTSTR)strLaunchBasis), T2BSTR((LPCTSTR)strAdditionalArgs));
  775. }
  776. void CTSHOOTCtrl::RenderInternal(CString strPage)
  777. {
  778. USES_CONVERSION;
  779. Fire_Render(T2BSTR((LPCTSTR)strPage));
  780. }
  781. void CTSHOOTCtrl::RegisterGlobal()
  782. {
  783. int nConnections = CProxy_ITSHOOTCtrlEvents< CTSHOOTCtrl >::m_vec.GetSize();
  784. for (int nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
  785. {
  786. Lock();
  787. CComPtr<IUnknown> sp = CProxy_ITSHOOTCtrlEvents< CTSHOOTCtrl >::m_vec.GetAt(nConnectionIndex);
  788. Unlock();
  789. IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
  790. if (pDispatch != NULL)
  791. {
  792. DWORD dwCookie;
  793. m_pGIT->RegisterInterfaceInGlobal(pDispatch, IID_IDispatch, &dwCookie);
  794. m_vecCookies.push_back(dwCookie);
  795. }
  796. }
  797. }
  798. STDMETHODIMP CTSHOOTCtrl::IsLocked(BOOL *pbResult)
  799. {
  800. *pbResult = GetLocked() ? TRUE : FALSE;
  801. return S_OK;
  802. }
  803. // Set the locale.
  804. // Parameter bstrNewLocale should be of the form:
  805. // "lang[_country[.code_page]]"
  806. // | ".code_page"
  807. // | ""
  808. // | NULL
  809. STDMETHODIMP CTSHOOTCtrl::setLocale2( BSTR bstrNewLocale )
  810. {
  811. USES_CONVERSION;
  812. if (GetLocked())
  813. return S_OK;
  814. m_strRequestedLocale= W2T( bstrNewLocale );
  815. m_bRequestToSetLocale= true;
  816. return S_OK;
  817. }