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.

1093 lines
28 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: bscript.cxx
  7. //
  8. // Contents: Implementation of CBServerScript
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "headers.hxx"
  12. CScriptHost::CScriptHost(CMTScript * pMT,
  13. BOOL fPrimary,
  14. BOOL fDispatchOnly)
  15. : _pMT(pMT),
  16. _fIsPrimaryScript(fPrimary)
  17. {
  18. _ulRefs = 1;
  19. VariantInit(&_vPubCache);
  20. VariantInit(&_vPrivCache);
  21. Assert(_dwPublicSN == 0);
  22. Assert(_dwPrivateSN == 0);
  23. }
  24. CScriptHost::~CScriptHost()
  25. {
  26. int i;
  27. // Any thread can call the dtor.
  28. WHEN_DBG(_dwThreadId = GetCurrentThreadId());
  29. AssertSz(PopScript() == S_FALSE,
  30. "Script object not closed properly!");
  31. VariantClear(&_vPubCache);
  32. VariantClear(&_vPrivCache);
  33. for (i = 0; i < _aryEvtSinks.Size(); i++)
  34. {
  35. _aryEvtSinks[i]->Disconnect();
  36. }
  37. _aryEvtSinks.ReleaseAll();
  38. ReleaseInterface(_pTypeInfoIGlobalMTScript);
  39. ReleaseInterface(_pTypeInfoCMTScript);
  40. }
  41. HRESULT
  42. CScriptHost::QueryInterface(REFIID iid, void **ppvObj)
  43. {
  44. if (iid == IID_IGlobalMTScript || iid == IID_IUnknown || iid == IID_IDispatch)
  45. {
  46. *ppvObj = (IGlobalMTScript *)this;
  47. }
  48. else
  49. {
  50. *ppvObj = NULL;
  51. return E_NOINTERFACE;
  52. }
  53. ((IUnknown *)*ppvObj)->AddRef();
  54. return S_OK;
  55. }
  56. DWORD
  57. CScriptHost::ThreadMain()
  58. {
  59. HRESULT hr;
  60. CStr cstrScript;
  61. VARIANT varParam;
  62. SCRIPT_PARAMS *pscrParams;
  63. VariantInit(&varParam);
  64. VERIFY_THREAD();
  65. pscrParams = (SCRIPT_PARAMS*)_pvParams;
  66. cstrScript.Set(pscrParams->pszPath);
  67. #if DBG == 1
  68. char achBuf[10];
  69. cstrScript.GetMultiByte(achBuf, 10);
  70. SetName(achBuf);
  71. #endif
  72. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
  73. COINIT_DISABLE_OLE1DDE |
  74. COINIT_SPEED_OVER_MEMORY);
  75. if (!SUCCEEDED(hr))
  76. {
  77. ThreadStarted(hr); // Free our creating thread
  78. goto Cleanup;
  79. }
  80. if (pscrParams->pvarParams)
  81. {
  82. if (V_VT(pscrParams->pvarParams) == VT_DISPATCH)
  83. {
  84. // Unmarshal the IDispatch pointer being handed to us from the
  85. // other thread.
  86. IDispatch *pDisp;
  87. DWORD dwCookie = V_I4(pscrParams->pvarParams);
  88. hr = _pMT->_pGIT->GetInterfaceFromGlobal(dwCookie,
  89. IID_IDispatch,
  90. (LPVOID*)&pDisp);
  91. if (!hr)
  92. {
  93. V_VT(&varParam) = VT_DISPATCH;
  94. V_DISPATCH(&varParam) = pDisp;
  95. }
  96. }
  97. else
  98. {
  99. VariantCopy(&varParam, pscrParams->pvarParams);
  100. }
  101. }
  102. // Hold a reference on ourself while the script is running
  103. AddRef();
  104. if (_fIsPrimaryScript)
  105. {
  106. hr = THR(LoadTypeLibrary());
  107. // Ensure that ScriptMain() completes before we fire any other events.
  108. _fDontHandleEvents = TRUE;
  109. }
  110. if (hr)
  111. {
  112. ThreadStarted(hr);
  113. goto Cleanup;
  114. }
  115. hr = ExecuteTopLevelScript(cstrScript, &varParam);
  116. if (hr)
  117. {
  118. ThreadStarted(hr);
  119. TraceTag((tagError, "Failed to execute script: %x", hr));
  120. AssertSz(!_fIsPrimaryScript, "Failed to execute script");
  121. PostQuitMessage(0);
  122. goto Cleanup;
  123. }
  124. ThreadStarted(hr);
  125. FireEvent(DISPID_MTScript_ScriptMain, 0, NULL);
  126. //
  127. // Secondary scripts go away as soon as they're done.
  128. //
  129. if (_fIsPrimaryScript)
  130. {
  131. DWORD dwRet;
  132. _fDontHandleEvents = FALSE;
  133. dwRet = MessageEventPump(TRUE);
  134. AssertSz(dwRet == MEP_EXIT, "NONFATAL: Invalid return value from MessageEventPump!");
  135. }
  136. else
  137. {
  138. CScriptHost *pThis = this;
  139. PostToThread(_pMT,
  140. MD_SECONDARYSCRIPTTERMINATE,
  141. (LPVOID)&pThis,
  142. sizeof(CScriptHost*));
  143. }
  144. Cleanup:
  145. CloseScripts();
  146. VariantClear(&varParam);
  147. if (_fIsPrimaryScript)
  148. {
  149. int i;
  150. for (i = 0; i < s_arySyncEvents.Size(); i++)
  151. {
  152. CloseHandle(s_arySyncEvents[i]._hEvent);
  153. s_arySyncEvents[i]._cstrName.Free();
  154. }
  155. s_arySyncEvents.DeleteAll();
  156. for (i = 0; i < (int)s_cThreadLocks; i++)
  157. {
  158. DeleteCriticalSection(&s_aThreadLocks[i]._csLock);
  159. s_aThreadLocks[i]._cstrName.Free();
  160. }
  161. memset(&s_aThreadLocks, 0, sizeof(s_aThreadLocks));
  162. s_cThreadLocks = 0;
  163. }
  164. Release();
  165. CoUninitialize();
  166. return 0;
  167. }
  168. //+---------------------------------------------------------------------------
  169. //
  170. // Member: CScriptHost::MessageEventPump, public
  171. //
  172. // Synopsis: Empties our message queues (both windows' and our private
  173. // threadcomm queue)
  174. //
  175. // Arguments: [fWait] -- If TRUE, will not return until an event occurs
  176. // [cEvents] -- Count of events to monitor
  177. // [pEvents] -- Pointer to list of event handles
  178. // [fAll] -- If TRUE, don't return until all handles in
  179. // pEvents are signaled.
  180. // [dwTimeout] -- Timeout after this many ms if nothing signals
  181. // [fNoEvents] -- If TRUE, don't fire events while waiting
  182. //
  183. // Returns: MEP_TIMEOUT: The given timeout period expired without any
  184. // event objects becoming signaled. Returned only
  185. // if dwTimeout != INFINITE
  186. // MEP_EXIT: An event occurred which is causing this thread to
  187. // terminate. The caller should clean up and finish
  188. // what it's doing.
  189. // MEP_FALLTHROUGH: Indicates that no objects signaled.
  190. // Returned only if fWait==FALSE.
  191. // MEP_EVENT_0: If one (or all if fAll==TRUE) of the passed-in
  192. // event handles became signaled. The index of the
  193. // signaled handle is added to MEP_EVENT_0. Returned
  194. // only if one or more event handles were passed in.
  195. //
  196. //----------------------------------------------------------------------------
  197. DWORD
  198. CScriptHost::MessageEventPump(BOOL fWait,
  199. UINT cEvents /* = 0 */,
  200. HANDLE *pEvents /* = NULL */,
  201. BOOL fAll /* = FALSE */,
  202. DWORD dwTimeout /* = INFINITE */,
  203. BOOL fNoEvents /* = FALSE */)
  204. {
  205. CStackPtrAry<HANDLE, 5> aryHandles;
  206. MSG msg;
  207. DWORD dwRet;
  208. DWORD mepReturn = MEP_FALLTHROUGH;
  209. _int64 i64Freq = 0;
  210. _int64 i64Time;
  211. _int64 i64Goal = 0;
  212. long lTimeout = dwTimeout;
  213. BOOL fTimeout = dwTimeout != INFINITE;
  214. if (cEvents)
  215. {
  216. aryHandles.CopyIndirect(cEvents, pEvents, FALSE);
  217. }
  218. if (_fMustExitThread)
  219. {
  220. return MEP_EXIT;
  221. }
  222. // WARNING! aryHandles will get rebuilt under certain conditions below.
  223. // If you add code which adds handles to the array, you must update the
  224. // code below as well!
  225. if (!fNoEvents && !_fDontHandleEvents)
  226. {
  227. aryHandles.Insert(0, _hCommEvent);
  228. }
  229. else if (fNoEvents)
  230. {
  231. _fDontHandleEvents = TRUE;
  232. }
  233. if (fTimeout)
  234. {
  235. QueryPerformanceFrequency((LARGE_INTEGER*)&i64Freq);
  236. QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);
  237. // Resolution must be at least milliseconds
  238. Assert(i64Freq >= 1000);
  239. // Compute the time when the timer will be complete, converted to ms
  240. i64Goal = ((i64Time * 1000) / i64Freq) + lTimeout;
  241. }
  242. do
  243. {
  244. //
  245. // Purge out all window messages (primarily for OLE's benefit).
  246. //
  247. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  248. {
  249. if (msg.message == WM_QUIT)
  250. {
  251. _fMustExitThread = TRUE;
  252. return MEP_EXIT;
  253. }
  254. TranslateMessage(&msg);
  255. DispatchMessage(&msg);
  256. }
  257. if (_fMustExitThread)
  258. {
  259. AbortScripts();
  260. return MEP_EXIT;
  261. }
  262. dwRet = MsgWaitForMultipleObjects(aryHandles.Size(),
  263. aryHandles,
  264. FALSE,
  265. (fWait) ? (DWORD)lTimeout : 0,
  266. QS_ALLINPUT);
  267. if (dwRet == WAIT_OBJECT_0 && !_fDontHandleEvents)
  268. {
  269. //
  270. // Another thread is sending us a message.
  271. //
  272. HandleThreadMessage();
  273. }
  274. else if (dwRet < WAIT_OBJECT_0 + aryHandles.Size())
  275. {
  276. Assert(cEvents);
  277. int iEvent = dwRet - WAIT_OBJECT_0;
  278. //
  279. // One of the events the script is waiting for has been signaled.
  280. //
  281. if (fAll)
  282. {
  283. // They want to wait for all the events. Remove the signaled
  284. // event from the array and if it's the last one then we're
  285. // there!
  286. aryHandles.Delete(iEvent);
  287. if (aryHandles.Size() == ((_fDontHandleEvents) ? 0 : 1))
  288. {
  289. // All the events have come back signaled. Check that none
  290. // have become unsignaled.
  291. if (WaitForMultipleObjects(cEvents, pEvents, TRUE, 0) == WAIT_TIMEOUT)
  292. {
  293. // Something became unsignaled. Start over! Rebuild
  294. // the array of handles.
  295. aryHandles.CopyIndirect(cEvents, pEvents, FALSE);
  296. if (!_fDontHandleEvents)
  297. {
  298. aryHandles.Insert(0, _hCommEvent);
  299. }
  300. }
  301. else
  302. {
  303. mepReturn = MEP_EVENT_0;
  304. break;
  305. }
  306. }
  307. }
  308. else
  309. {
  310. mepReturn = MEP_EVENT_0 + iEvent;
  311. if (!_fDontHandleEvents)
  312. {
  313. mepReturn--;
  314. }
  315. break;
  316. }
  317. }
  318. else if (dwRet == WAIT_OBJECT_0 + aryHandles.Size())
  319. {
  320. //
  321. // A windows message came through. It will be handled at the
  322. // top of the loop.
  323. //
  324. }
  325. else if (dwRet == WAIT_FAILED)
  326. {
  327. TraceTag((tagError, "WaitForMultipleObjects failure (%d)", GetLastError()));
  328. AssertSz(FALSE, "WaitForMultipleObjects failure");
  329. _fMustExitThread = TRUE;
  330. mepReturn = MEP_EXIT;
  331. break;
  332. }
  333. else
  334. {
  335. Assert(dwRet == WAIT_TIMEOUT);
  336. mepReturn = MEP_TIMEOUT;
  337. break;
  338. }
  339. // Since any number of things could have brought us out of MWFMO,
  340. // we need to compute the remaining timeout for the next time around.
  341. if (fTimeout)
  342. {
  343. QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);
  344. // Convert current time to milliseconds.
  345. i64Time = ((i64Time * 1000) / i64Freq);
  346. // Compute the delta between the current time and our goal
  347. lTimeout = (DWORD)(i64Goal - i64Time);
  348. // Are we timed out?
  349. if (lTimeout <= 0)
  350. {
  351. mepReturn = MEP_TIMEOUT;
  352. break;
  353. }
  354. }
  355. }
  356. while (fWait); // Only do the loop once if fWait == FALSE
  357. if (fNoEvents)
  358. {
  359. _fDontHandleEvents = FALSE;
  360. }
  361. // MEP_FALLTHROUGH is not a valid return if fWait == TRUE
  362. Assert(!fWait || mepReturn != MEP_FALLTHROUGH);
  363. return mepReturn;
  364. }
  365. void
  366. CScriptHost::HandleThreadMessage()
  367. {
  368. VERIFY_THREAD();
  369. THREADMSG tm;
  370. BYTE bData[MSGDATABUFSIZE];
  371. DWORD cbData;
  372. if (_fDontHandleEvents)
  373. return;
  374. //
  375. //$ FUTURE: Add a way to filter messages so we can check for MD_PLEASEEXIT
  376. // without pulling off the event messages
  377. //
  378. while (GetNextMsg(&tm, (void **)bData, &cbData))
  379. {
  380. switch (tm)
  381. {
  382. case MD_PLEASEEXIT:
  383. //
  384. // We're being asked to terminate.
  385. //
  386. AbortScripts();
  387. PostQuitMessage(0);
  388. break;
  389. case MD_MACHINECONNECT:
  390. AssertSz(_fIsPrimaryScript, "Non-primary script got machine event!");
  391. _fDontHandleEvents = TRUE;
  392. FireEvent(DISPID_MTScript_OnMachineConnect, 0, NULL);
  393. _fDontHandleEvents = FALSE;
  394. break;
  395. case MD_MACHEVENTCALL:
  396. AssertSz(_fIsPrimaryScript, "Non-primary script got machine event!");
  397. Assert(cbData == sizeof(MACHPROC_EVENT_DATA*));
  398. _fDontHandleEvents = TRUE;
  399. // This call will set the event object in the
  400. // MACHPROC_EVENT_DATA struct when everything completes.
  401. FireMachineEvent(*(MACHPROC_EVENT_DATA**)bData, TRUE);
  402. _fDontHandleEvents = FALSE;
  403. break;
  404. case MD_PROCESSDATA:
  405. Assert(cbData == sizeof(MACHPROC_EVENT_DATA*));
  406. _fDontHandleEvents = TRUE;
  407. // This call will set the event object in the
  408. // MACHPROC_EVENT_DATA struct when everything completes.
  409. FireMachineEvent(*(MACHPROC_EVENT_DATA**)bData, FALSE);
  410. _fDontHandleEvents = FALSE;
  411. break;
  412. case MD_PROCESSEXITED:
  413. case MD_PROCESSTERMINATED:
  414. case MD_PROCESSCONNECTED:
  415. case MD_PROCESSCRASHED:
  416. Assert(cbData == sizeof(CProcessThread*));
  417. _fDontHandleEvents = TRUE;
  418. FireProcessEvent(tm, *(CProcessThread**)bData);
  419. _fDontHandleEvents = FALSE;
  420. break;
  421. default:
  422. AssertSz(FALSE, "CScriptHost got a message it couldn't handle!");
  423. break;
  424. }
  425. }
  426. }
  427. //---------------------------------------------------------------------------
  428. //
  429. // Member: CScriptHost::PushScript
  430. //
  431. // Create a new script site/engine and push it on the script stack
  432. //
  433. //---------------------------------------------------------------------------
  434. HRESULT
  435. CScriptHost::PushScript(TCHAR *pchName)
  436. {
  437. VERIFY_THREAD();
  438. HRESULT hr;
  439. CScriptSite * pScriptSite;
  440. TCHAR * pchFile;
  441. hr = LoadTypeLibrary();
  442. if (hr)
  443. goto Cleanup;
  444. pScriptSite = new CScriptSite(this);
  445. if(!pScriptSite)
  446. {
  447. hr = E_OUTOFMEMORY;
  448. goto Cleanup;
  449. }
  450. pchFile = _tcsrchr(pchName, _T('\\'));
  451. if (!pchFile)
  452. {
  453. pchFile = pchName;
  454. }
  455. else
  456. pchFile++;
  457. hr = pScriptSite->Init(pchFile);
  458. if (hr)
  459. {
  460. delete pScriptSite;
  461. pScriptSite = NULL;
  462. goto Cleanup;
  463. }
  464. pScriptSite->_pScriptSitePrev = _pScriptSite;
  465. _pScriptSite = pScriptSite;
  466. Cleanup:
  467. RRETURN(hr);
  468. }
  469. //---------------------------------------------------------------------------
  470. //
  471. // Member: CScriptHost::PopScript
  472. //
  473. // Pop last script site/engine off the script stack
  474. //
  475. //---------------------------------------------------------------------------
  476. HRESULT
  477. CScriptHost::PopScript()
  478. {
  479. VERIFY_THREAD();
  480. CScriptSite * pScriptSite = _pScriptSite;
  481. if(!_pScriptSite)
  482. return S_FALSE;
  483. _pScriptSite = _pScriptSite->_pScriptSitePrev;
  484. pScriptSite->Close();
  485. pScriptSite->Release();
  486. return S_OK;
  487. }
  488. //---------------------------------------------------------------------------
  489. //
  490. // Member: CScriptHost::CloseScripts
  491. //
  492. // Clear the stack of script engines
  493. //
  494. //---------------------------------------------------------------------------
  495. HRESULT
  496. CScriptHost::CloseScripts()
  497. {
  498. VERIFY_THREAD();
  499. while(PopScript() == S_OK)
  500. ;
  501. AssertSz(_pScriptSite == NULL, "Should have released script site");
  502. return S_OK;
  503. }
  504. //---------------------------------------------------------------------------
  505. //
  506. // Member: CScriptHost::AbortScripts
  507. //
  508. // Clear the stack of script engines
  509. //
  510. //---------------------------------------------------------------------------
  511. HRESULT
  512. CScriptHost::AbortScripts()
  513. {
  514. VERIFY_THREAD();
  515. // Make sure we're not stuck on MsgWaitForMultipleObjects and that we
  516. // never will be again.
  517. _fMustExitThread = TRUE;
  518. SetEvent(_hCommEvent);
  519. CScriptSite * pScriptSite;
  520. pScriptSite = _pScriptSite;
  521. while (pScriptSite)
  522. {
  523. pScriptSite->Abort();
  524. pScriptSite = pScriptSite->_pScriptSitePrev;
  525. }
  526. return S_OK;
  527. }
  528. //---------------------------------------------------------------------------
  529. //
  530. // Member: CScriptHost::ExecuteTopLevelScript
  531. //
  532. // Close previous top level script engine then load and execute script
  533. // in a new top level script engine
  534. //
  535. //---------------------------------------------------------------------------
  536. HRESULT
  537. CScriptHost::ExecuteTopLevelScript(TCHAR * pchPath, VARIANT *pvarParams)
  538. {
  539. VERIFY_THREAD();
  540. HRESULT hr;
  541. // Stablize reference count during script execution.
  542. // Script can hide window which decrements reference count.
  543. AddRef();
  544. // Getting read to close the scripts fire unload event.
  545. CloseScripts();
  546. hr = THR(PushScript(pchPath));
  547. if(hr)
  548. goto Cleanup;
  549. hr = THR(VariantCopy(&_pScriptSite->_varParam, pvarParams));
  550. if (hr)
  551. goto Cleanup;
  552. hr = THR(_pScriptSite->ExecuteScriptFile(pchPath));
  553. if(hr)
  554. goto Cleanup;
  555. hr = THR(_pScriptSite->SetScriptState(SCRIPTSTATE_CONNECTED));
  556. if (hr)
  557. goto Cleanup;
  558. Cleanup:
  559. Release();
  560. RRETURN(hr);
  561. }
  562. //---------------------------------------------------------------------------
  563. //
  564. // Member: CScriptHost::ExecuteScriptlet
  565. //
  566. // Add a scriptlet to the current top level script engine and execute it
  567. //
  568. //---------------------------------------------------------------------------
  569. HRESULT
  570. CScriptHost::ExecuteTopLevelScriptlet(TCHAR * pchScript)
  571. {
  572. VERIFY_THREAD();
  573. HRESULT hr;
  574. // Stablize reference count during script execution.
  575. // Script can hide window which decrements reference count.
  576. AddRef();
  577. if(!_pScriptSite)
  578. {
  579. hr = THR(PushScript(_T("Scriptlet")));
  580. if(hr)
  581. goto Cleanup;
  582. }
  583. else
  584. {
  585. Assert(_pScriptSite->_pScriptSitePrev == NULL);
  586. }
  587. hr = THR(_pScriptSite->ExecuteScriptStr(pchScript));
  588. if (hr)
  589. goto Cleanup;
  590. hr = THR(_pScriptSite->SetScriptState(SCRIPTSTATE_CONNECTED));
  591. Cleanup:
  592. Release();
  593. RRETURN(hr);
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // Member: CScriptHost::FireProcessEvent, public
  598. //
  599. // Synopsis: Fires an OnProcessEvent event into the script
  600. //
  601. //----------------------------------------------------------------------------
  602. void
  603. CScriptHost::FireProcessEvent(THREADMSG tm, CProcessThread *pProc)
  604. {
  605. VARIANTARG varg[3];
  606. TCHAR *pszMsg;
  607. DISPID dispid = DISPID_MTScript_OnProcessEvent;
  608. VERIFY_THREAD();
  609. VariantInit(&varg[0]);
  610. VariantInit(&varg[1]);
  611. VariantInit(&varg[2]);
  612. // Parameters are in order from last to first
  613. V_VT(&varg[2]) = VT_I4;
  614. V_I4(&varg[2]) = pProc->ProcId();
  615. switch (tm)
  616. {
  617. case MD_PROCESSEXITED:
  618. pszMsg = _T("exited");
  619. V_VT(&varg[0]) = VT_I4;
  620. V_I4(&varg[0]) = pProc->GetExitCode();
  621. break;
  622. case MD_PROCESSCRASHED:
  623. pszMsg = _T("crashed");
  624. // 3rd parameter is empty
  625. break;
  626. case MD_PROCESSTERMINATED:
  627. pszMsg = _T("terminated");
  628. // 3rd parameter is empty
  629. break;
  630. case MD_PROCESSCONNECTED:
  631. pszMsg = _T("connected");
  632. // 3rd parameter is empty
  633. break;
  634. default:
  635. AssertSz(FALSE, "NONFATAL: Invalid THREADMSG value");
  636. return;
  637. break;
  638. }
  639. V_VT(&varg[1]) = VT_BSTR;
  640. V_BSTR(&varg[1]) = SysAllocString(pszMsg); // NULL is a valid value for BSTR
  641. FireEvent(dispid, 3, varg);
  642. VariantClear(&varg[0]);
  643. VariantClear(&varg[1]);
  644. VariantClear(&varg[2]);
  645. return;
  646. }
  647. long CScriptHost::FireScriptErrorEvent(
  648. TCHAR *bstrFile,
  649. long nLine,
  650. long nChar,
  651. TCHAR *bstrText,
  652. long sCode,
  653. TCHAR *bstrSource,
  654. TCHAR *bstrDescription)
  655. {
  656. long cSucceeded = 0;
  657. VERIFY_THREAD();
  658. // Parameters are in order from last to first
  659. AutoVariant varg[7];
  660. cSucceeded += varg[6].Set(bstrFile);
  661. cSucceeded += varg[5].Set(nLine);
  662. cSucceeded += varg[4].Set(nChar);
  663. cSucceeded += varg[3].Set(bstrText);
  664. cSucceeded += varg[2].Set(sCode);
  665. cSucceeded += varg[1].Set(bstrSource);
  666. cSucceeded += varg[0].Set(bstrDescription);
  667. if (cSucceeded != ARRAY_SIZE(varg))
  668. return 0; // Default return value
  669. AutoVariant varResult;
  670. FireEvent(DISPID_MTScript_OnScriptError, ARRAY_SIZE(varg), varg, &varResult);
  671. AutoVariant varResultInt;
  672. if (VariantChangeType(&varResultInt, &varResult, 0, VT_I4) == S_OK)
  673. return V_I4(&varResultInt);
  674. return 0;
  675. }
  676. //---------------------------------------------------------------------------
  677. //
  678. // Member: CScriptHost::FireMachineEvent
  679. //
  680. // Notes: Fires the OnRemoteExec event when a machine connected to us
  681. // remotely calls the Exec() method.
  682. //
  683. //---------------------------------------------------------------------------
  684. void
  685. CScriptHost::FireMachineEvent(MACHPROC_EVENT_DATA *pmed, BOOL fExec)
  686. {
  687. VERIFY_THREAD();
  688. DISPID dispid = (fExec)
  689. ? DISPID_MTScript_OnRemoteExec
  690. : DISPID_MTScript_OnProcessEvent;
  691. DISPPARAMS dp;
  692. EXCEPINFO ei;
  693. UINT uArgErr = 0;
  694. VARIANTARG vararg[3];
  695. VARIANTARG varResult;
  696. HRESULT hr = S_OK;
  697. pmed->hrReturn = S_OK;
  698. if (GetSite() && GetSite()->_pDispSink)
  699. {
  700. VariantInit(&vararg[0]);
  701. VariantInit(&vararg[1]);
  702. VariantInit(&vararg[2]);
  703. VariantInit(&varResult);
  704. // Params are in order from last to first in the array
  705. V_VT(&vararg[0]) = VT_BSTR;
  706. V_BSTR(&vararg[0]) = pmed->bstrParams;
  707. V_VT(&vararg[1]) = VT_BSTR;
  708. V_BSTR(&vararg[1]) = pmed->bstrCmd;
  709. if (!fExec)
  710. {
  711. V_VT(&vararg[2]) = VT_I4;
  712. V_I4(&vararg[2]) = pmed->dwProcId;
  713. }
  714. dp.rgvarg = vararg;
  715. dp.rgdispidNamedArgs = NULL;
  716. dp.cArgs = (fExec) ? 2 : 3;
  717. dp.cNamedArgs = 0;
  718. hr = GetSite()->_pDispSink->Invoke(dispid,
  719. IID_NULL,
  720. 0,
  721. DISPATCH_METHOD,
  722. &dp,
  723. &varResult,
  724. &ei,
  725. &uArgErr);
  726. pmed->hrReturn = hr;
  727. if (hr)
  728. {
  729. // If an error occurred, do nothing except return the error code.
  730. }
  731. // Check for data types which we don't support.
  732. else if ( V_ISBYREF(&varResult)
  733. || V_ISARRAY(&varResult)
  734. || V_ISVECTOR(&varResult)
  735. || V_VT(&varResult) == VT_UNKNOWN)
  736. {
  737. // Do nothing. Return an empty result
  738. AssertSz(FALSE, "NONFATAL: Unsupported data type returned from OnRemoteExec event");
  739. }
  740. else if (V_VT(&varResult) == VT_DISPATCH)
  741. {
  742. if (fExec)
  743. {
  744. // Note that the return value is an IDispatch, but don't set the
  745. // pointer because it will need to be retrieved out of the GIT
  746. V_VT(pmed->pvReturn) = VT_DISPATCH;
  747. V_DISPATCH(pmed->pvReturn) = NULL;
  748. hr =_pMT->_pGIT->RegisterInterfaceInGlobal(V_DISPATCH(&varResult),
  749. IID_IDispatch,
  750. &pmed->dwGITCookie);
  751. if (hr)
  752. {
  753. pmed->hrReturn = hr;
  754. }
  755. }
  756. // Leave the result empty if they returned an IDispatch from an
  757. // OnProcessEvent call.
  758. }
  759. else
  760. {
  761. VariantCopy(pmed->pvReturn, &varResult);
  762. }
  763. VariantClear(&varResult);
  764. }
  765. // Tell the calling thread we're done with the call and it can continue.
  766. SetEvent(pmed->hEvent);
  767. }
  768. //---------------------------------------------------------------------------
  769. //
  770. // Member: CScriptHost::FireEvent
  771. //
  772. //---------------------------------------------------------------------------
  773. void
  774. CScriptHost::FireEvent(DISPID dispid, UINT cArg, VARIANTARG *pvararg, VARIANTARG *pvarResult)
  775. {
  776. VERIFY_THREAD();
  777. DISPPARAMS dp;
  778. EXCEPINFO ei;
  779. UINT uArgErr = 0;
  780. if (GetSite() && GetSite()->_pDispSink)
  781. {
  782. dp.rgvarg = pvararg;
  783. dp.rgdispidNamedArgs = NULL;
  784. dp.cArgs = cArg;
  785. dp.cNamedArgs = 0;
  786. GetSite()->_pDispSink->Invoke(
  787. dispid,
  788. IID_NULL,
  789. 0,
  790. DISPATCH_METHOD,
  791. &dp,
  792. pvarResult,
  793. &ei,
  794. &uArgErr);
  795. }
  796. }
  797. void
  798. CScriptHost::FireEvent(DISPID dispid, UINT carg, VARIANTARG *pvararg)
  799. {
  800. FireEvent(dispid, carg, pvararg, NULL);
  801. }
  802. //---------------------------------------------------------------------------
  803. //
  804. // Member: CScriptHost::FireEvent
  805. //
  806. //---------------------------------------------------------------------------
  807. void
  808. CScriptHost::FireEvent(DISPID dispid, LPCTSTR pch)
  809. {
  810. VERIFY_THREAD();
  811. VARIANT var;
  812. V_BSTR(&var) = SysAllocString(pch);
  813. V_VT(&var) = VT_BSTR;
  814. FireEvent(dispid, 1, &var);
  815. SysFreeString(V_BSTR(&var));
  816. }
  817. //---------------------------------------------------------------------------
  818. //
  819. // Member: CScriptHost::FireEvent
  820. //
  821. //---------------------------------------------------------------------------
  822. void
  823. CScriptHost::FireEvent(DISPID dispid, BOOL fArg)
  824. {
  825. VERIFY_THREAD();
  826. VARIANT var;
  827. V_BOOL(&var) = fArg ? VARIANT_TRUE : VARIANT_FALSE;
  828. V_VT(&var) = VT_BOOL;
  829. FireEvent(dispid, 1, &var);
  830. }
  831. //---------------------------------------------------------------------------
  832. //
  833. // Member: CScriptHost::FireEvent
  834. //
  835. //---------------------------------------------------------------------------
  836. void
  837. CScriptHost::FireEvent(DISPID dispid, IDispatch *pDisp)
  838. {
  839. VERIFY_THREAD();
  840. VARIANT var;
  841. V_DISPATCH(&var) = pDisp;
  842. V_VT(&var) = VT_DISPATCH;
  843. FireEvent(dispid, 1, &var);
  844. }
  845. HRESULT
  846. CScriptHost::LoadTypeLibrary()
  847. {
  848. VERIFY_THREAD();
  849. HRESULT hr = S_OK;
  850. if (!_pTypeLibEXE)
  851. {
  852. // BUGBUG -- Is this valid, or does this need to be marshalled?
  853. _pTypeLibEXE = _pMT->_pTypeLibEXE;
  854. }
  855. if (!_pTypeInfoCMTScript)
  856. {
  857. hr = THR(_pTypeLibEXE->GetTypeInfoOfGuid(CLSID_LocalMTScript, &_pTypeInfoCMTScript));
  858. if (hr)
  859. goto Cleanup;
  860. }
  861. if (!_pTypeInfoIGlobalMTScript)
  862. {
  863. hr = THR(_pTypeLibEXE->GetTypeInfoOfGuid(IID_IGlobalMTScript, &_pTypeInfoIGlobalMTScript));
  864. if (hr)
  865. goto Cleanup;
  866. }
  867. Cleanup:
  868. return hr;
  869. }
  870. void
  871. CScriptHost::GetScriptPath(CStr *pcstrPath)
  872. {
  873. _pMT->_options.GetScriptPath(pcstrPath);
  874. }