Leaked source code of windows server 2003
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.

1969 lines
50 KiB

  1. //+------------------------------------------------------------------------
  2. //
  3. // Microsoft Forms
  4. // Copyright (C) Microsoft Corporation, 1996
  5. //
  6. // File: bsauto.cxx
  7. //
  8. //-------------------------------------------------------------------------
  9. #include "headers.hxx"
  10. #include <mapi.h>
  11. #undef ASSERT
  12. DeclareTag(tagSync, "MTScript", "Trace Thread Sync events");
  13. DeclareTag(tagLock, "MTScript", "Trace Thread Lock events");
  14. ExternTag(tagProcess);
  15. AutoCriticalSection CScriptHost::s_csSync;
  16. CStackDataAry<CScriptHost::SYNCEVENT, 5> CScriptHost::s_arySyncEvents;
  17. CScriptHost::THREADLOCK CScriptHost::s_aThreadLocks[MAX_LOCKS];
  18. UINT CScriptHost::s_cThreadLocks = 0;
  19. static const wchar_t *g_pszListDeliminator = L";,";
  20. static wchar_t *g_pszAtomicSyncLock = L"g_pszAtomicSyncLock";
  21. //---------------------------------------------------------------------------
  22. //
  23. // Member: CScriptHost::GetTypeInfo, IDispatch
  24. //
  25. //---------------------------------------------------------------------------
  26. HRESULT
  27. CScriptHost::GetTypeInfo(UINT itinfo, ULONG lcid, ITypeInfo ** pptinfo)
  28. {
  29. VERIFY_THREAD();
  30. HRESULT hr;
  31. hr = LoadTypeLibrary();
  32. if (hr)
  33. goto Cleanup;
  34. *pptinfo = _pTypeInfoIGlobalMTScript;
  35. (*pptinfo)->AddRef();
  36. Cleanup:
  37. return hr;
  38. }
  39. //---------------------------------------------------------------------------
  40. //
  41. // Member: CScriptHost::GetTypeInfoCount, IDispatch
  42. //
  43. //---------------------------------------------------------------------------
  44. HRESULT
  45. CScriptHost::GetTypeInfoCount(UINT * pctinfo)
  46. {
  47. VERIFY_THREAD();
  48. *pctinfo = 1;
  49. return S_OK;
  50. }
  51. //---------------------------------------------------------------------------
  52. //
  53. // Member: CScriptHost::GetIDsOfNames, IDispatch
  54. //
  55. //---------------------------------------------------------------------------
  56. HRESULT
  57. CScriptHost::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  58. {
  59. VERIFY_THREAD();
  60. HRESULT hr;
  61. hr = THR(LoadTypeLibrary());
  62. if (hr)
  63. goto Cleanup;
  64. hr = _pTypeInfoIGlobalMTScript->GetIDsOfNames(rgszNames, cNames, rgdispid);
  65. Cleanup:
  66. return hr;
  67. }
  68. //---------------------------------------------------------------------------
  69. //
  70. // Member: CScriptHost::Invoke, IDispatch
  71. //
  72. //---------------------------------------------------------------------------
  73. HRESULT
  74. CScriptHost::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS * pdispparams, VARIANT * pvarResult,EXCEPINFO * pexcepinfo, UINT * puArgErr)
  75. {
  76. VERIFY_THREAD();
  77. HRESULT hr;
  78. hr = LoadTypeLibrary();
  79. if (hr)
  80. goto Cleanup;
  81. hr = _pTypeInfoIGlobalMTScript->Invoke((IGlobalMTScript *)this, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  82. Cleanup:
  83. return hr;
  84. }
  85. //***************************************************************************
  86. //
  87. // IGlobalMTScript implementation
  88. //
  89. //***************************************************************************
  90. HRESULT
  91. CScriptHost::get_PublicData(VARIANT * pvData)
  92. {
  93. VERIFY_THREAD();
  94. HRESULT hr = S_OK;
  95. // NOTE: We assume that the output parameter pvData is an empty or
  96. // uninitialized VARIANT. This should be safe because it is defined as
  97. // the return value for this method to the scripting engines and is
  98. // a pure [out] parameter.
  99. VariantInit(pvData);
  100. // Check to see if the data has changed since we last got it.
  101. // _dwPublicSerialNum is a DWORD so we are guaranteed an atomic read.
  102. if (_pMT->_dwPublicSerialNum != _dwPublicSN)
  103. {
  104. LOCK_LOCALS(_pMT);
  105. VariantClear(&_vPubCache);
  106. // If the data is an IDispatch pointer (how the scripting engines
  107. // implement most objects) we must get a marshalled copy to this thread.
  108. // Otherwise we can just copy the data into the return value.
  109. if (V_VT(&_pMT->_vPublicData) == VT_DISPATCH)
  110. {
  111. IDispatch *pDisp;
  112. Assert(_pMT->_dwPublicDataCookie != 0);
  113. hr = _pMT->_pGIT->GetInterfaceFromGlobal(_pMT->_dwPublicDataCookie,
  114. IID_IDispatch,
  115. (LPVOID*)&pDisp);
  116. if (!hr)
  117. {
  118. V_VT(&_vPubCache) = VT_DISPATCH;
  119. V_DISPATCH(&_vPubCache) = pDisp;
  120. }
  121. }
  122. else
  123. {
  124. hr = VariantCopy(&_vPubCache, &_pMT->_vPublicData);
  125. }
  126. _dwPublicSN = _pMT->_dwPublicSerialNum;
  127. }
  128. if (!hr)
  129. {
  130. hr = VariantCopy(pvData, &_vPubCache);
  131. }
  132. return hr;
  133. }
  134. HRESULT
  135. CScriptHost::put_PublicData(VARIANT vData)
  136. {
  137. VERIFY_THREAD();
  138. HRESULT hr = S_OK;
  139. // Check for data types which we don't support.
  140. if ( V_ISBYREF(&vData)
  141. || V_ISARRAY(&vData)
  142. || V_ISVECTOR(&vData)
  143. || V_VT(&vData) == VT_UNKNOWN)
  144. {
  145. return E_INVALIDARG;
  146. }
  147. LOCK_LOCALS(_pMT);
  148. // If the previous data is an IDispatch pointer revoke it from the
  149. // GlobalInterfaceTable.
  150. if (V_VT(&_pMT->_vPublicData) == VT_DISPATCH)
  151. {
  152. Assert(_pMT->_dwPublicDataCookie != 0);
  153. hr = _pMT->_pGIT->RevokeInterfaceFromGlobal(_pMT->_dwPublicDataCookie);
  154. AssertSz(!hr, "Unexpected failure revoking itf from GIT");
  155. _pMT->_dwPublicDataCookie = 0;
  156. }
  157. // If the new data is an IDispatch pointer then we must register it.
  158. if (V_VT(&vData) == VT_DISPATCH)
  159. {
  160. Assert(_pMT->_dwPublicDataCookie == 0);
  161. hr = _pMT->_pGIT->RegisterInterfaceInGlobal(V_DISPATCH(&vData),
  162. IID_IDispatch,
  163. &_pMT->_dwPublicDataCookie);
  164. AssertSz(!hr, "Unexpected failure registering itf in GIT");
  165. }
  166. // Update the global copy of the data.
  167. //$ FUTURE: This can be optimized to reduce memory usage (by not making
  168. // a copy of a string in every thread, for example).
  169. _pMT->_dwPublicSerialNum++;
  170. hr = VariantCopy(&_pMT->_vPublicData, &vData);
  171. if (!hr)
  172. {
  173. // Even if it's an IDispatch, we don't need to marshal it for
  174. // ourselves because we're running in the same thread as the script
  175. // engine that gave it to us.
  176. hr = VariantCopy(&_vPubCache, &vData);
  177. _dwPublicSN = _pMT->_dwPublicSerialNum;
  178. }
  179. return S_OK;
  180. }
  181. HRESULT
  182. CScriptHost::get_PrivateData(VARIANT * pvData)
  183. {
  184. VERIFY_THREAD();
  185. HRESULT hr = S_OK;
  186. // NOTE: We assume that the output parameter pvData is an empty or
  187. // uninitialized VARIANT. This should be safe because it is defined as
  188. // the return value for this method to the scripting engines and is
  189. // a pure [out] parameter.
  190. VariantInit(pvData);
  191. // Check to see if the data has changed since we last got it.
  192. // _dwPrivateSerialNum is a DWORD so we are guaranteed an atomic read.
  193. if (_pMT->_dwPrivateSerialNum != _dwPrivateSN)
  194. {
  195. LOCK_LOCALS(_pMT);
  196. VariantClear(&_vPrivCache);
  197. // If the data is an IDispatch pointer (how the scripting engines
  198. // implement most objects) we must get a marshalled copy to this thread.
  199. // Otherwise we can just copy the data into the return value.
  200. if (V_VT(&_pMT->_vPrivateData) == VT_DISPATCH)
  201. {
  202. IDispatch *pDisp;
  203. Assert(_pMT->_dwPrivateDataCookie != 0);
  204. hr = _pMT->_pGIT->GetInterfaceFromGlobal(_pMT->_dwPrivateDataCookie,
  205. IID_IDispatch,
  206. (LPVOID*)&pDisp);
  207. if (!hr)
  208. {
  209. V_VT(&_vPrivCache) = VT_DISPATCH;
  210. V_DISPATCH(&_vPrivCache) = pDisp;
  211. }
  212. }
  213. else
  214. {
  215. hr = VariantCopy(&_vPrivCache, &_pMT->_vPrivateData);
  216. }
  217. _dwPrivateSN = _pMT->_dwPrivateSerialNum;
  218. }
  219. if (!hr)
  220. {
  221. hr = VariantCopy(pvData, &_vPrivCache);
  222. }
  223. return hr;
  224. }
  225. HRESULT
  226. CScriptHost::put_PrivateData(VARIANT vData)
  227. {
  228. VERIFY_THREAD();
  229. HRESULT hr = S_OK;
  230. // Check for data types which we don't support.
  231. if ( V_ISBYREF(&vData)
  232. || V_ISARRAY(&vData)
  233. || V_ISVECTOR(&vData)
  234. || V_VT(&vData) == VT_UNKNOWN)
  235. {
  236. return E_INVALIDARG;
  237. }
  238. LOCK_LOCALS(_pMT);
  239. // If the previous data is an IDispatch pointer revoke it from the
  240. // GlobalInterfaceTable.
  241. if (V_VT(&_pMT->_vPrivateData) == VT_DISPATCH)
  242. {
  243. Assert(_pMT->_dwPrivateDataCookie != 0);
  244. hr = _pMT->_pGIT->RevokeInterfaceFromGlobal(_pMT->_dwPrivateDataCookie);
  245. AssertSz(!hr, "Unexpected failure revoking itf from GIT");
  246. _pMT->_dwPrivateDataCookie = 0;
  247. }
  248. // If the new data is an IDispatch pointer then we must register it.
  249. if (V_VT(&vData) == VT_DISPATCH)
  250. {
  251. Assert(_pMT->_dwPrivateDataCookie == 0);
  252. hr = _pMT->_pGIT->RegisterInterfaceInGlobal(V_DISPATCH(&vData),
  253. IID_IDispatch,
  254. &_pMT->_dwPrivateDataCookie);
  255. AssertSz(!hr, "Unexpected failure registering itf in GIT");
  256. }
  257. // Update the global copy of the data.
  258. //$ FUTURE: This can be optimized to reduce memory usage (by not making
  259. // a copy of a string in every thread, for example).
  260. _pMT->_dwPrivateSerialNum++;
  261. hr = VariantCopy(&_pMT->_vPrivateData, &vData);
  262. if (!hr)
  263. {
  264. // Even if it's an IDispatch, we don't need to marshal it for
  265. // ourselves because we're running in the same thread as the script
  266. // engine that gave it to us.
  267. hr = VariantCopy(&_vPrivCache, &vData);
  268. _dwPrivateSN = _pMT->_dwPrivateSerialNum;
  269. }
  270. return S_OK;
  271. }
  272. HRESULT
  273. CScriptHost::ExitProcess()
  274. {
  275. VERIFY_THREAD();
  276. PostToThread(_pMT, MD_PLEASEEXIT);
  277. return S_OK;
  278. }
  279. HRESULT
  280. CScriptHost::Restart()
  281. {
  282. VERIFY_THREAD();
  283. PostToThread(_pMT, MD_RESTART);
  284. return S_OK;
  285. }
  286. HRESULT
  287. CScriptHost::get_LocalMachine(BSTR *pbstrName)
  288. {
  289. TCHAR achCompName[MAX_COMPUTERNAME_LENGTH+1];
  290. DWORD dwLen = MAX_COMPUTERNAME_LENGTH+1;
  291. VERIFY_THREAD();
  292. if (!pbstrName)
  293. return E_POINTER;
  294. GetComputerName(achCompName, &dwLen);
  295. achCompName[dwLen] = '\0';
  296. *pbstrName = SysAllocString(achCompName);
  297. if (!*pbstrName)
  298. return E_OUTOFMEMORY;
  299. return S_OK;
  300. }
  301. HRESULT
  302. CScriptHost::Include(BSTR bstrPath)
  303. {
  304. VERIFY_THREAD();
  305. HRESULT hr;
  306. if(!bstrPath)
  307. return E_INVALIDARG;
  308. if (!_fIsPrimaryScript)
  309. MessageEventPump(FALSE);
  310. //$ TODO: Define a new named item context for the included file for better
  311. // debugging.
  312. hr = THR(GetSite()->ExecuteScriptFile(bstrPath));
  313. return hr;
  314. }
  315. HRESULT
  316. CScriptHost::CallScript(BSTR bstrPath, VARIANT *pvarScriptParam)
  317. {
  318. VERIFY_THREAD();
  319. HRESULT hr;
  320. if(!bstrPath)
  321. return E_INVALIDARG;
  322. if (!_fIsPrimaryScript)
  323. MessageEventPump(FALSE);
  324. hr = THR(PushScript(_tcsrchr(bstrPath, _T('.'))));
  325. if(hr)
  326. goto Cleanup;
  327. if (pvarScriptParam && pvarScriptParam->vt != VT_ERROR)
  328. {
  329. hr = THR(VariantCopy(&GetSite()->_varParam, pvarScriptParam));
  330. if (hr)
  331. goto Cleanup;
  332. }
  333. hr = THR(GetSite()->ExecuteScriptFile(bstrPath));
  334. hr = THR(GetSite()->SetScriptState(SCRIPTSTATE_CONNECTED));
  335. if (hr)
  336. goto Cleanup;
  337. FireEvent(DISPID_MTScript_ScriptMain, 0, NULL);
  338. PopScript();
  339. Cleanup:
  340. return hr;
  341. }
  342. HRESULT
  343. CScriptHost::SpawnScript(BSTR bstrPath, VARIANT *pvarScriptParam)
  344. {
  345. VERIFY_THREAD();
  346. HRESULT hr = S_OK;
  347. VARIANT *pvarParam = NULL;
  348. DWORD dwCookie = 0;
  349. BOOL fRegistered = false;
  350. // Check for data types which we don't support.
  351. if ( !bstrPath
  352. || SysStringLen(bstrPath) == 0
  353. || V_ISBYREF(pvarScriptParam)
  354. || V_ISARRAY(pvarScriptParam)
  355. || V_ISVECTOR(pvarScriptParam)
  356. || V_VT(pvarScriptParam) == VT_UNKNOWN)
  357. {
  358. return E_INVALIDARG;
  359. }
  360. if (!_fIsPrimaryScript)
  361. MessageEventPump(FALSE);
  362. if (pvarScriptParam && pvarScriptParam->vt != VT_ERROR)
  363. {
  364. pvarParam = new VARIANT;
  365. if (!pvarParam)
  366. return E_OUTOFMEMORY;
  367. VariantInit(pvarParam);
  368. if (V_VT(pvarScriptParam) == VT_DISPATCH)
  369. {
  370. // Stick the pointer in the GlobalInterfaceTable, so the other
  371. // thread can pull it out safely.
  372. hr = _pMT->_pGIT->RegisterInterfaceInGlobal(V_DISPATCH(pvarScriptParam),
  373. IID_IDispatch,
  374. &dwCookie);
  375. if (hr)
  376. goto Cleanup;
  377. // Stick the cookie in the variant we hand to the other thread.
  378. V_VT(pvarParam) = VT_DISPATCH;
  379. V_I4(pvarParam) = dwCookie;
  380. fRegistered = true;
  381. }
  382. else
  383. {
  384. hr = THR(VariantCopy(pvarParam, pvarScriptParam));
  385. if (hr)
  386. goto Cleanup;
  387. }
  388. }
  389. hr = _pMT->RunScript(bstrPath, pvarParam);
  390. Cleanup:
  391. if (pvarParam)
  392. {
  393. if (fRegistered)
  394. {
  395. Verify(_pMT->_pGIT->RevokeInterfaceFromGlobal(dwCookie) == S_OK);
  396. }
  397. if (V_VT(pvarParam) != VT_DISPATCH)
  398. VariantClear(pvarParam);
  399. delete pvarParam;
  400. }
  401. return hr;
  402. }
  403. HRESULT
  404. CScriptHost::get_ScriptParam(VARIANT *pvarScriptParam)
  405. {
  406. VERIFY_THREAD();
  407. HRESULT hr;
  408. if (!_fIsPrimaryScript)
  409. MessageEventPump(FALSE);
  410. if (GetSite())
  411. {
  412. hr = THR(VariantCopy(pvarScriptParam, &GetSite()->_varParam));
  413. }
  414. else
  415. {
  416. hr = E_FAIL;
  417. }
  418. return hr;
  419. }
  420. HRESULT
  421. CScriptHost::get_ScriptPath(BSTR *pbstrPath)
  422. {
  423. CStr cstrPath;
  424. VERIFY_THREAD();
  425. if (!_fIsPrimaryScript)
  426. MessageEventPump(FALSE);
  427. _pMT->_options.GetScriptPath(&cstrPath);
  428. return cstrPath.AllocBSTR(pbstrPath);
  429. }
  430. typedef HRESULT (TestExternal_Func)(VARIANT *pParam, long *plRetVal);
  431. HRESULT
  432. CScriptHost::CallExternal(BSTR bstrDLLName,
  433. BSTR bstrFunctionName,
  434. VARIANT *pParam,
  435. long * plRetVal)
  436. {
  437. VERIFY_THREAD();
  438. HRESULT hr = S_OK;
  439. HINSTANCE hInstDLL = NULL;
  440. TestExternal_Func *pfn = NULL;
  441. if (!_fIsPrimaryScript)
  442. MessageEventPump(FALSE);
  443. if (!plRetVal || !bstrDLLName || !bstrFunctionName)
  444. return E_POINTER;
  445. *plRetVal = -1;
  446. hInstDLL = LoadLibrary(bstrDLLName);
  447. if (NULL == hInstDLL)
  448. {
  449. return S_FALSE; // Can't return error codes or the script will abort
  450. }
  451. int cchLen = SysStringLen(bstrFunctionName);
  452. char *pchBuf = new char[cchLen+1];
  453. if (pchBuf)
  454. {
  455. WideCharToMultiByte(CP_ACP, 0, bstrFunctionName, cchLen, pchBuf, cchLen+1, NULL, NULL);
  456. pchBuf[cchLen] = '\0';
  457. pfn = (TestExternal_Func *)GetProcAddress(hInstDLL, pchBuf);
  458. delete pchBuf;
  459. }
  460. if (NULL == pfn)
  461. {
  462. hr = S_FALSE;
  463. }
  464. else
  465. {
  466. *plRetVal = 0;
  467. hr = (*pfn)(pParam, plRetVal);
  468. }
  469. FreeLibrary(hInstDLL);
  470. return hr;
  471. }
  472. HRESULT
  473. CScriptHost::GetSyncEventName(int nEvent, CStr *pCStr, HANDLE *phEvent)
  474. {
  475. HRESULT hr = S_OK;
  476. *phEvent = NULL;
  477. if (nEvent < 0)
  478. return E_INVALIDARG;
  479. EnterCriticalSection(&s_csSync);
  480. if (nEvent >= s_arySyncEvents.Size())
  481. {
  482. hr = E_INVALIDARG;
  483. goto Cleanup;
  484. }
  485. pCStr->Set(s_arySyncEvents[nEvent]._cstrName);
  486. *phEvent = s_arySyncEvents[nEvent]._hEvent;
  487. Cleanup:
  488. LeaveCriticalSection(&s_csSync);
  489. RRETURN(hr);
  490. }
  491. HRESULT
  492. CScriptHost::GetSyncEvent(LPCTSTR pszName, HANDLE *phEvent)
  493. {
  494. int i;
  495. SYNCEVENT *pse;
  496. HRESULT hr = S_OK;
  497. *phEvent = NULL;
  498. if (_tcslen(pszName) < 1)
  499. return E_INVALIDARG;
  500. EnterCriticalSection(&s_csSync);
  501. for (i = s_arySyncEvents.Size(), pse = s_arySyncEvents;
  502. i > 0;
  503. i--, pse++)
  504. {
  505. if (_tcsicmp(pszName, pse->_cstrName) == 0)
  506. {
  507. *phEvent = pse->_hEvent;
  508. break;
  509. }
  510. }
  511. if (i == 0)
  512. {
  513. //
  514. // The event doesn't exist yet. Create one. The primary script thread
  515. // owns cleaning all this stuff up.
  516. //
  517. SYNCEVENT se;
  518. se._hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  519. if (!se._hEvent)
  520. {
  521. hr = HRESULT_FROM_WIN32(GetLastError());
  522. goto Cleanup;
  523. }
  524. else
  525. {
  526. se._cstrName.Set(pszName);
  527. s_arySyncEvents.AppendIndirect(&se);
  528. //
  529. // The cstr in 'se' will destroy its memory unless we take it away.
  530. // It's now owned by the cstrName member of the array.
  531. //
  532. (void)se._cstrName.TakePch();
  533. *phEvent = se._hEvent;
  534. }
  535. }
  536. Cleanup:
  537. LeaveCriticalSection(&s_csSync);
  538. RRETURN(hr);
  539. }
  540. HRESULT
  541. CScriptHost::StringToEventArray(const wchar_t *pszNameList, CStackPtrAry<HANDLE, 5> *pAryEvents)
  542. {
  543. HRESULT hr = S_OK;
  544. if (wcspbrk(pszNameList, g_pszListDeliminator))
  545. {
  546. CStr cstrNameList;
  547. HRESULT hr = cstrNameList.Set(pszNameList);
  548. wchar_t *pch = NULL;
  549. if (hr == S_OK)
  550. pch = wcstok(cstrNameList, g_pszListDeliminator);
  551. while (hr == S_OK && pch)
  552. {
  553. HANDLE hEvent;
  554. hr = THR(GetSyncEvent(pch, &hEvent));
  555. if (hr != S_OK)
  556. break;
  557. // Don't allow duplicates. MsgWaitForMultipleObjects will barf.
  558. if (pAryEvents->Find(hEvent) != -1)
  559. {
  560. hr = E_INVALIDARG;
  561. break;
  562. }
  563. hr = pAryEvents->Append(hEvent);
  564. pch = wcstok(NULL, g_pszListDeliminator);
  565. }
  566. }
  567. else
  568. {
  569. HANDLE hEvent;
  570. hr = THR(GetSyncEvent(pszNameList, &hEvent));
  571. if (hr == S_OK)
  572. hr = pAryEvents->Append(hEvent);
  573. }
  574. RRETURN(hr);
  575. }
  576. HRESULT
  577. CScriptHost::ResetSync(const BSTR bstrName)
  578. {
  579. VERIFY_THREAD();
  580. HRESULT hr;
  581. if (!_fIsPrimaryScript)
  582. MessageEventPump(FALSE);
  583. CStackPtrAry<HANDLE, 5> aryEvents;
  584. hr = StringToEventArray(bstrName, &aryEvents);
  585. if (hr == S_OK)
  586. {
  587. for(int i = aryEvents.Size() - 1; i>= 0; --i)
  588. ResetEvent(aryEvents[i]);
  589. }
  590. return hr;
  591. }
  592. HRESULT
  593. CScriptHost::WaitForSync(BSTR bstrName, long nTimeout, VARIANT_BOOL *pfSignaled)
  594. {
  595. VERIFY_THREAD();
  596. HANDLE hEvent;
  597. HRESULT hr;
  598. if (!pfSignaled)
  599. return E_POINTER;
  600. *pfSignaled = VB_TRUE;
  601. hr = THR(GetSyncEvent(bstrName, &hEvent));
  602. if (hr)
  603. RRETURN(hr);
  604. TraceTag((tagSync, "Thread 0x%x is starting a wait for sync %ls",
  605. _dwThreadId, bstrName));
  606. if (MessageEventPump(TRUE,
  607. 1,
  608. &hEvent,
  609. FALSE,
  610. (nTimeout > 0) ? nTimeout : INFINITE) != MEP_EVENT_0)
  611. {
  612. *pfSignaled = VB_FALSE;
  613. }
  614. // Now make sure that SignalThreadSync() and ResetSync()
  615. // are atomic when manipulating multiple syncs.
  616. TakeThreadLock(g_pszAtomicSyncLock);
  617. ReleaseThreadLock(g_pszAtomicSyncLock);
  618. TraceTag((tagSync, "Thread 0x%x has returned from a wait for sync %ls (signaled=%s)",
  619. _dwThreadId,
  620. bstrName,
  621. (*pfSignaled==VB_FALSE) ? "false" : "true"));
  622. return S_OK;
  623. }
  624. HRESULT
  625. CScriptHost::WaitForMultipleSyncs(const BSTR bstrNameList,
  626. VARIANT_BOOL fWaitForAll,
  627. long nTimeout,
  628. long *plSignal)
  629. {
  630. VERIFY_THREAD();
  631. HRESULT hr;
  632. DWORD dwRet;
  633. *plSignal = 0;
  634. CStackPtrAry<HANDLE, 5> aryEvents;
  635. hr = StringToEventArray(bstrNameList, &aryEvents);
  636. if (hr == S_OK)
  637. {
  638. TraceTag((tagSync, "Thread 0x%x is starting a multiwait for sync %ls",
  639. _dwThreadId, bstrNameList));
  640. dwRet = MessageEventPump(TRUE,
  641. aryEvents.Size(),
  642. aryEvents,
  643. (fWaitForAll == VB_TRUE) ? TRUE : FALSE,
  644. (nTimeout > 0) ? nTimeout : INFINITE);
  645. if (dwRet >= MEP_EVENT_0)
  646. {
  647. *plSignal = dwRet - MEP_EVENT_0 + 1; // result is 1-based, not zero-based
  648. // Now make sure that SignalThreadSync() and ResetSync()
  649. // are atomic when manipulating multiple syncs.
  650. TakeThreadLock(g_pszAtomicSyncLock);
  651. ReleaseThreadLock(g_pszAtomicSyncLock);
  652. }
  653. TraceTag((tagSync, "Thread 0x%x has returned from a multiwait for sync %ls (signaled=%d)",
  654. _dwThreadId,
  655. bstrNameList,
  656. *plSignal));
  657. }
  658. return hr;
  659. }
  660. HRESULT
  661. CScriptHost::SignalThreadSync(BSTR bstrName)
  662. {
  663. HRESULT hr;
  664. if (!_fIsPrimaryScript)
  665. MessageEventPump(FALSE);
  666. TraceTag((tagSync, "Thread 0x%x is signalling sync %ls",
  667. _dwThreadId, bstrName));
  668. CStackPtrAry<HANDLE, 5> aryEvents;
  669. hr = StringToEventArray(bstrName, &aryEvents);
  670. if (hr == S_OK)
  671. {
  672. if (aryEvents.Size() > 1)
  673. TakeThreadLock(g_pszAtomicSyncLock);
  674. for(int i = aryEvents.Size() - 1; i>= 0; --i)
  675. SetEvent(aryEvents[i]);
  676. if (aryEvents.Size() > 1)
  677. ReleaseThreadLock(g_pszAtomicSyncLock);
  678. }
  679. return S_OK;
  680. }
  681. HRESULT
  682. CScriptHost::GetLockCritSec(LPTSTR pszName,
  683. CRITICAL_SECTION **ppcs,
  684. DWORD **ppdwOwner)
  685. {
  686. int i;
  687. THREADLOCK *ptl;
  688. HRESULT hr = S_OK;
  689. if (_tcslen(pszName) < 1)
  690. return E_INVALIDARG;
  691. *ppcs = NULL;
  692. EnterCriticalSection(&s_csSync);
  693. for (i = s_cThreadLocks, ptl = s_aThreadLocks;
  694. i > 0;
  695. i--, ptl++)
  696. {
  697. if (_tcsicmp(pszName, ptl->_cstrName) == 0)
  698. {
  699. *ppcs = &ptl->_csLock;
  700. *ppdwOwner = &ptl->_dwOwner;
  701. break;
  702. }
  703. }
  704. if (i == 0)
  705. {
  706. //
  707. // The critical section doesn't exist yet. Create one. The primary
  708. // script thread owns cleaning all this stuff up.
  709. //
  710. if (s_cThreadLocks == MAX_LOCKS)
  711. {
  712. // BUGBUG -- SetErrorInfo
  713. hr = E_OUTOFMEMORY;
  714. goto Cleanup;
  715. }
  716. ptl = &s_aThreadLocks[s_cThreadLocks++];
  717. InitializeCriticalSection(&ptl->_csLock);
  718. ptl->_cstrName.Set(pszName);
  719. ptl->_dwOwner = 0;
  720. *ppcs = &ptl->_csLock;
  721. *ppdwOwner = &ptl->_dwOwner;
  722. }
  723. Cleanup:
  724. LeaveCriticalSection(&s_csSync);
  725. RRETURN(hr);
  726. }
  727. HRESULT
  728. CScriptHost::TakeThreadLock(BSTR bstrName)
  729. {
  730. HRESULT hr;
  731. CRITICAL_SECTION *pcs;
  732. DWORD *pdwOwner;
  733. VERIFY_THREAD();
  734. if (!_fIsPrimaryScript)
  735. MessageEventPump(FALSE);
  736. hr = THR(GetLockCritSec(bstrName, &pcs, &pdwOwner));
  737. if (hr)
  738. RRETURN(hr);
  739. TraceTag((tagLock, "Thread 0x%x is trying to obtain lock %ls",
  740. _dwThreadId, bstrName));
  741. while (!TryEnterCriticalSection(pcs))
  742. {
  743. // Make sure we don't get hung here if the thread's trying to exit
  744. if (MessageEventPump(TRUE, 0, NULL, FALSE, 100, TRUE) == MEP_EXIT)
  745. return E_FAIL;
  746. }
  747. TraceTag((tagLock, "Thread 0x%x has obtained lock %ls",
  748. _dwThreadId, bstrName));
  749. *pdwOwner = GetCurrentThreadId();
  750. return S_OK;
  751. }
  752. HRESULT
  753. CScriptHost::ReleaseThreadLock(BSTR bstrName)
  754. {
  755. HRESULT hr;
  756. CRITICAL_SECTION *pcs;
  757. DWORD *pdwOwner;
  758. VERIFY_THREAD();
  759. if (!_fIsPrimaryScript)
  760. MessageEventPump(FALSE);
  761. hr = THR(GetLockCritSec(bstrName, &pcs, &pdwOwner));
  762. if (hr)
  763. RRETURN(hr);
  764. // LeaveCriticalSection can cause other threads to lock indefinitely on
  765. // the critical section if we don't actually own it.
  766. if (*pdwOwner != GetCurrentThreadId())
  767. {
  768. return HRESULT_FROM_WIN32(ERROR_NOT_OWNER);
  769. }
  770. LeaveCriticalSection(pcs);
  771. TraceTag((tagLock, "Thread 0x%x has released lock %ls",
  772. _dwThreadId, bstrName));
  773. return S_OK;
  774. }
  775. HRESULT
  776. CScriptHost::DoEvents()
  777. {
  778. VERIFY_THREAD();
  779. MessageEventPump(FALSE);
  780. return S_OK;
  781. }
  782. HRESULT
  783. CScriptHost::MessageBoxTimeout(BSTR bstrMessage, // Message Text
  784. long cButtons, // Number of buttons (max 5)
  785. BSTR bstrButtonText, // Comma separated list of button text. Number must match cButtons
  786. long lTimeout, // Timeout in minutes. If zero then no timeout.
  787. long lEventInterval, // Fire a OnMessageBoxInterval event every lEventInterval minutes
  788. VARIANT_BOOL fCanCancel, // If TRUE then timeout can be canceled.
  789. VARIANT_BOOL fConfirm, // If TRUE then confirm the button pushed before returning.
  790. long *plSelected) // Returns button pushed. 0=timeout, 1=Button1, 2=Button2, etc.
  791. {
  792. VERIFY_THREAD();
  793. HANDLE hEvent;
  794. MBTIMEOUT mbt = { 0 };
  795. BOOL fExit = FALSE;
  796. HRESULT hr = S_OK;
  797. if (!plSelected)
  798. return E_POINTER;
  799. *plSelected = -1;
  800. if (cButtons < 1 || cButtons > 5)
  801. return E_INVALIDARG;
  802. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  803. if (!hEvent)
  804. return HRESULT_FROM_WIN32(GetLastError());
  805. mbt.bstrMessage = bstrMessage;
  806. mbt.cButtons = cButtons;
  807. mbt.bstrButtonText = bstrButtonText;
  808. mbt.lTimeout = lTimeout;
  809. mbt.lEventInterval = lEventInterval;
  810. mbt.fCanCancel = (fCanCancel == VB_TRUE) ? TRUE : FALSE;
  811. mbt.fConfirm = (fConfirm == VB_TRUE) ? TRUE : FALSE;
  812. mbt.hEvent = hEvent;
  813. CMessageBoxTimeout *pmbt = new CMessageBoxTimeout(&mbt);
  814. if (!pmbt)
  815. return E_OUTOFMEMORY;
  816. pmbt->StartThread(NULL);
  817. while (!fExit)
  818. {
  819. // Make sure it was our event being signaled that caused the loop to end
  820. if (MessageEventPump(TRUE, 1, &hEvent) != MEP_EVENT_0)
  821. {
  822. hr = S_FALSE;
  823. fExit = TRUE;
  824. break;
  825. }
  826. switch (mbt.mbts)
  827. {
  828. case MBTS_BUTTON1:
  829. case MBTS_BUTTON2:
  830. case MBTS_BUTTON3:
  831. case MBTS_BUTTON4:
  832. case MBTS_BUTTON5:
  833. case MBTS_TIMEOUT:
  834. *plSelected = (long)mbt.mbts;
  835. fExit = TRUE;
  836. break;
  837. case MBTS_INTERVAL:
  838. FireEvent(DISPID_MTScript_OnMessageBoxInterval, 0, NULL);
  839. ResetEvent(hEvent);
  840. break;
  841. case MBTS_ERROR:
  842. hr = E_FAIL;
  843. fExit = TRUE;
  844. break;
  845. default:
  846. AssertSz(FALSE, "FATAL: Invalid value for mbts!");
  847. fExit = TRUE;
  848. break;
  849. }
  850. }
  851. if (pmbt->_hwnd != NULL)
  852. {
  853. EndDialog(pmbt->_hwnd, 0);
  854. }
  855. pmbt->Release();
  856. CloseHandle(hEvent);
  857. return hr;
  858. }
  859. HRESULT
  860. CScriptHost::RunLocalCommand(BSTR bstrCommand,
  861. BSTR bstrDir,
  862. BSTR bstrTitle,
  863. VARIANT_BOOL fMinimize,
  864. VARIANT_BOOL fGetOutput,
  865. VARIANT_BOOL fWait,
  866. VARIANT_BOOL fNoCrashPopup,
  867. VARIANT_BOOL fNoEnviron,
  868. long * plErrorCode)
  869. {
  870. VERIFY_THREAD();
  871. CProcessThread *pProc;
  872. PROCESS_PARAMS pp;
  873. if (!_fIsPrimaryScript)
  874. MessageEventPump(FALSE);
  875. if (!plErrorCode)
  876. return E_POINTER;
  877. pp.pszCommand = bstrCommand;
  878. pp.pszDir = bstrDir;
  879. pp.pszTitle = bstrTitle;
  880. pp.fMinimize = (fMinimize == VB_TRUE) ? TRUE : FALSE;
  881. pp.fGetOutput = (fGetOutput == VB_TRUE) ? TRUE : FALSE;
  882. pp.fNoCrashPopup = (fNoCrashPopup == VB_TRUE) ? TRUE : FALSE;
  883. pp.fNoEnviron = (fNoEnviron == VB_TRUE) ? TRUE : FALSE;
  884. _hrLastRunLocalError = S_OK;
  885. pProc = new CProcessThread(this);
  886. if (!pProc)
  887. {
  888. _hrLastRunLocalError = E_OUTOFMEMORY;
  889. *plErrorCode = 0;
  890. return S_FALSE;
  891. }
  892. _hrLastRunLocalError = pProc->StartThread(&pp);
  893. if (FAILED(_hrLastRunLocalError))
  894. {
  895. *plErrorCode = 0;
  896. pProc->Release();
  897. // Don't cause a script error by returning a failure code.
  898. return S_FALSE;
  899. }
  900. _pMT->AddProcess(pProc);
  901. if (fWait == VB_TRUE)
  902. {
  903. HANDLE hEvent = pProc->hThread();
  904. // The actual return code here doesn't matter. We'll do the same thing
  905. // no matter what causes MessageEventPump to exit.
  906. MessageEventPump(TRUE, 1, &hEvent);
  907. }
  908. TraceTag((tagProcess, "RunLocalCommand PID=%d, %s", pProc->ProcId(), bstrCommand));
  909. *plErrorCode = pProc->ProcId();
  910. return S_OK;
  911. }
  912. HRESULT
  913. CScriptHost::GetLastRunLocalError(long *plErrorCode)
  914. {
  915. VERIFY_THREAD();
  916. *plErrorCode = _hrLastRunLocalError;
  917. return S_OK;
  918. }
  919. HRESULT
  920. CScriptHost::GetProcessOutput(long lProcessID, BSTR *pbstrData)
  921. {
  922. VERIFY_THREAD();
  923. CProcessThread *pProc;
  924. pProc = _pMT->FindProcess((DWORD)lProcessID);
  925. if (!pProc)
  926. {
  927. return E_INVALIDARG;
  928. }
  929. return pProc->GetProcessOutput(pbstrData);
  930. }
  931. HRESULT
  932. CScriptHost::GetProcessExitCode(long lProcessID, long *plExitCode)
  933. {
  934. VERIFY_THREAD();
  935. CProcessThread *pProc;
  936. pProc = _pMT->FindProcess((DWORD)lProcessID);
  937. if (!pProc)
  938. {
  939. return E_INVALIDARG;
  940. }
  941. *plExitCode = pProc->GetExitCode();
  942. return S_OK;
  943. }
  944. HRESULT
  945. CScriptHost::TerminateProcess(long lProcessID)
  946. {
  947. VERIFY_THREAD();
  948. CProcessThread *pProc;
  949. pProc = _pMT->FindProcess((DWORD)lProcessID);
  950. if (!pProc)
  951. {
  952. return E_INVALIDARG;
  953. }
  954. PostToThread(pProc, MD_PLEASEEXIT);
  955. return S_OK;
  956. }
  957. HRESULT
  958. CScriptHost::SendToProcess(long lProcessID,
  959. BSTR bstrType,
  960. BSTR bstrData,
  961. long *plReturn)
  962. {
  963. VERIFY_THREAD();
  964. MACHPROC_EVENT_DATA med;
  965. MACHPROC_EVENT_DATA *pmed;
  966. VARIANT vRet;
  967. HRESULT hr = S_OK;
  968. CProcessThread *pProc;
  969. pProc = _pMT->FindProcess((DWORD)lProcessID);
  970. //$ TODO -- Fix these error return codes to not cause script errors.
  971. if (!pProc || !plReturn)
  972. {
  973. return E_INVALIDARG;
  974. }
  975. else if (pProc->GetExitCode() != STILL_ACTIVE)
  976. {
  977. *plReturn = -1;
  978. return S_FALSE;
  979. }
  980. VariantInit(&vRet);
  981. med.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  982. if (med.hEvent == NULL)
  983. {
  984. return HRESULT_FROM_WIN32(GetLastError());
  985. }
  986. med.bstrCmd = bstrType;
  987. med.bstrParams = bstrData;
  988. med.dwProcId = (DWORD)lProcessID;
  989. med.pvReturn = &vRet;
  990. med.dwGITCookie = 0;
  991. med.hrReturn = S_OK;
  992. pmed = &med;
  993. PostToThread(_pMT, MD_SENDTOPROCESS, &pmed, sizeof(MACHPROC_EVENT_DATA*));
  994. // BUGBUG - we could get a crash if something causes us to exit before
  995. // the CMTScript thread handles the MD_SENDTOPROCESS message.
  996. MessageEventPump(TRUE, 1, &med.hEvent);
  997. hr = med.hrReturn;
  998. *plReturn = V_I4(&vRet);
  999. VariantClear(&vRet);
  1000. CloseHandle(med.hEvent);
  1001. return hr;
  1002. }
  1003. #define USERPROFILESTRING_SZ (256 * sizeof(TCHAR))
  1004. TCHAR UserProfileString[USERPROFILESTRING_SZ];
  1005. HRESULT
  1006. CScriptHost::SendMail(BSTR bstrTo,
  1007. BSTR bstrCC,
  1008. BSTR bstrBCC,
  1009. BSTR bstrSubject,
  1010. BSTR bstrMessage,
  1011. BSTR bstrAttachmentPath,
  1012. BSTR bstrUsername,
  1013. BSTR bstrPassword,
  1014. long * plErrorCode)
  1015. {
  1016. // This implementation was stolen from the execmail.exe source code.
  1017. // Handles to MAPI32.DLL library, host name registry key, email session.
  1018. //$ FUTURE -- Cache this stuff instead of reloading the library every
  1019. // time.
  1020. HINSTANCE hLibrary;
  1021. LHANDLE hSession;
  1022. // Function pointers for MAPI calls we use.
  1023. LPMAPILOGON fnMAPILogon;
  1024. LPMAPISENDMAIL fnMAPISendMail;
  1025. LPMAPILOGOFF fnMAPILogoff;
  1026. // MAPI structures and counters.
  1027. MapiRecipDesc rgRecipDescStruct[30];
  1028. MapiMessage MessageStruct = {0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, 0, NULL};
  1029. MapiFileDesc MAPIFileDesc = {0, 0, 0, NULL, NULL, NULL};
  1030. FLAGS MAPIFlags = MAPI_NEW_SESSION;
  1031. // Pointers to email parameter strings.
  1032. char *pszToList = NULL;
  1033. char *pszCCList = NULL;
  1034. char *pszBCCList = NULL;
  1035. ULONG ulErrorCode;
  1036. if (!plErrorCode)
  1037. return E_POINTER;
  1038. ///////////////////////////////////////////////////////////////////////////
  1039. // No point going any farther if MAPI32.DLL isn't available.
  1040. hLibrary = LoadLibrary(L"MAPI32.DLL");
  1041. if (hLibrary == NULL)
  1042. {
  1043. DWORD dwError = GetLastError();
  1044. TraceTag((tagError, "Error: MAPI32.DLL not found on this machine!"));
  1045. *plErrorCode = HRESULT_FROM_WIN32(dwError);
  1046. return S_FALSE;
  1047. }
  1048. // Must convert all parameters to ANSI
  1049. ANSIString szTo(bstrTo);
  1050. ANSIString szCC(bstrCC);
  1051. ANSIString szBCC(bstrBCC);
  1052. ANSIString szSubject(bstrSubject);
  1053. ANSIString szMessage(bstrMessage);
  1054. ANSIString szAttachment(bstrAttachmentPath);
  1055. ANSIString szUsername(bstrUsername);
  1056. ANSIString szPassword(bstrPassword);
  1057. // Set up MAPI function pointers.
  1058. fnMAPILogon = (LPMAPILOGON)GetProcAddress(hLibrary, "MAPILogon");
  1059. fnMAPISendMail = (LPMAPISENDMAIL)GetProcAddress(hLibrary, "MAPISendMail");
  1060. fnMAPILogoff = (LPMAPILOGOFF)GetProcAddress(hLibrary, "MAPILogoff");
  1061. // Hook the recipient structure array into the message structure.
  1062. MessageStruct.lpRecips = rgRecipDescStruct;
  1063. // Get the default user parameters if none were specified.
  1064. if (SysStringLen(bstrUsername) == 0)
  1065. {
  1066. HKEY hkey;
  1067. WCHAR KeyPath[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles";
  1068. WCHAR Value[] = L"DefaultProfile";
  1069. DWORD buf_sz = USERPROFILESTRING_SZ;
  1070. DWORD val_type;
  1071. if( RegOpenKeyEx( HKEY_CURRENT_USER, KeyPath, 0, KEY_READ, &hkey ) == ERROR_SUCCESS )
  1072. {
  1073. if ( RegQueryValueEx( hkey, Value, NULL, &val_type, (BYTE*)UserProfileString, &buf_sz ) == ERROR_SUCCESS )
  1074. {
  1075. if ( val_type == REG_SZ )
  1076. {
  1077. szUsername.Set(UserProfileString);
  1078. }
  1079. }
  1080. RegCloseKey( hkey );
  1081. }
  1082. }
  1083. pszToList = szTo;
  1084. // Parse ToList into rgRecipDescStruct.
  1085. while (*pszToList && (MessageStruct.nRecipCount < 30))
  1086. {
  1087. // Strip leading spaces from recipient name and terminate preceding
  1088. // name string.
  1089. if (isspace(*pszToList))
  1090. {
  1091. *pszToList=0;
  1092. pszToList++;
  1093. }
  1094. // Add a name to the array and increment the number of recipients.
  1095. else
  1096. {
  1097. rgRecipDescStruct[MessageStruct.nRecipCount].ulReserved = 0;
  1098. rgRecipDescStruct[MessageStruct.nRecipCount].ulRecipClass = MAPI_TO;
  1099. rgRecipDescStruct[MessageStruct.nRecipCount].lpszName = pszToList;
  1100. rgRecipDescStruct[MessageStruct.nRecipCount].lpszAddress = NULL;
  1101. rgRecipDescStruct[MessageStruct.nRecipCount].ulEIDSize = 0;
  1102. rgRecipDescStruct[MessageStruct.nRecipCount].lpEntryID = NULL;
  1103. MessageStruct.nRecipCount++;
  1104. // Move beginning of string to next name in ToList.
  1105. do
  1106. {
  1107. pszToList++;
  1108. } while (isgraph(*pszToList));
  1109. }
  1110. }
  1111. pszCCList = szCC;
  1112. // Parse CCList into rgRecipDescStruct.
  1113. while (*pszCCList && (MessageStruct.nRecipCount < 30))
  1114. {
  1115. // Strip leading spaces from recipient name and terminate preceding
  1116. // name string.
  1117. if (isspace(*pszCCList))
  1118. {
  1119. *pszCCList=0;
  1120. pszCCList++;
  1121. }
  1122. // Add a name to the array and increment the number of recipients.
  1123. else
  1124. {
  1125. rgRecipDescStruct[MessageStruct.nRecipCount].ulReserved = 0;
  1126. rgRecipDescStruct[MessageStruct.nRecipCount].ulRecipClass = MAPI_CC;
  1127. rgRecipDescStruct[MessageStruct.nRecipCount].lpszName = pszCCList;
  1128. rgRecipDescStruct[MessageStruct.nRecipCount].lpszAddress = NULL;
  1129. rgRecipDescStruct[MessageStruct.nRecipCount].ulEIDSize = 0;
  1130. rgRecipDescStruct[MessageStruct.nRecipCount].lpEntryID = NULL;
  1131. MessageStruct.nRecipCount++;
  1132. // Move beginning of string to next name in CCList.
  1133. do
  1134. {
  1135. pszCCList++;
  1136. } while (isgraph(*pszCCList));
  1137. }
  1138. }
  1139. pszBCCList = szBCC;
  1140. // Parse BCCList into rgRecipDescStruct.
  1141. while (*pszBCCList && (MessageStruct.nRecipCount < 30))
  1142. {
  1143. // Strip leading spaces from recipient name and terminate preceding
  1144. // name string.
  1145. if (isspace(*pszBCCList))
  1146. {
  1147. *pszBCCList=0;
  1148. pszBCCList++;
  1149. }
  1150. // Add a name to the array and increment the number of recipients.
  1151. else
  1152. {
  1153. rgRecipDescStruct[MessageStruct.nRecipCount].ulReserved = 0;
  1154. rgRecipDescStruct[MessageStruct.nRecipCount].ulRecipClass = MAPI_BCC;
  1155. rgRecipDescStruct[MessageStruct.nRecipCount].lpszName = pszBCCList;
  1156. rgRecipDescStruct[MessageStruct.nRecipCount].lpszAddress = NULL;
  1157. rgRecipDescStruct[MessageStruct.nRecipCount].ulEIDSize = 0;
  1158. rgRecipDescStruct[MessageStruct.nRecipCount].lpEntryID = NULL;
  1159. MessageStruct.nRecipCount++;
  1160. // Move beginning of string to next name in BCCList.
  1161. do
  1162. {
  1163. pszBCCList++;
  1164. } while (isgraph(*pszBCCList));
  1165. }
  1166. }
  1167. if (strlen(szAttachment) > 0)
  1168. {
  1169. MAPIFileDesc.ulReserved = 0;
  1170. MAPIFileDesc.flFlags = 0;
  1171. MAPIFileDesc.nPosition = 0;
  1172. MAPIFileDesc.lpszPathName = szAttachment;
  1173. MAPIFileDesc.lpszFileName = NULL;
  1174. MAPIFileDesc.lpFileType = NULL;
  1175. MessageStruct.nFileCount = 1;
  1176. MessageStruct.lpFiles = &MAPIFileDesc;
  1177. // muck around with the message text (The attachment
  1178. // will be attached at the beginning of the mail message
  1179. // but it replaces the character at that position)
  1180. // BUGBUG -- Do we need to do this? (lylec)
  1181. //strcpy(szMessageText," \n");
  1182. }
  1183. MessageStruct.lpszSubject = szSubject;
  1184. MessageStruct.lpszNoteText = szMessage;
  1185. *plErrorCode = 0;
  1186. // Send the message!
  1187. ulErrorCode = fnMAPILogon(0L, szUsername, szPassword, MAPIFlags, 0L, &hSession);
  1188. if (ulErrorCode != SUCCESS_SUCCESS)
  1189. {
  1190. *plErrorCode = (long)ulErrorCode;
  1191. }
  1192. else
  1193. {
  1194. ulErrorCode = fnMAPISendMail(hSession, 0L, &MessageStruct, 0L, 0L);
  1195. if (ulErrorCode != SUCCESS_SUCCESS)
  1196. {
  1197. *plErrorCode = (long)ulErrorCode;
  1198. }
  1199. fnMAPILogoff(hSession, 0L, 0L, 0L);
  1200. }
  1201. FreeLibrary(hLibrary);
  1202. return S_OK;
  1203. }
  1204. HRESULT
  1205. CScriptHost::OUTPUTDEBUGSTRING(BSTR bstrMessage)
  1206. {
  1207. VERIFY_THREAD();
  1208. if (!_fIsPrimaryScript)
  1209. MessageEventPump(FALSE);
  1210. TCHAR szText[ (MSGDATABUFSIZE-1) / sizeof(TCHAR) ];
  1211. CScriptSite *site = GetSite();
  1212. const TCHAR *pszScriptName = L"";
  1213. if (site)
  1214. {
  1215. pszScriptName = _tcsrchr((LPTSTR)site->_cstrName, _T('\\'));
  1216. if (!pszScriptName)
  1217. pszScriptName = (LPTSTR)site->_cstrName;
  1218. }
  1219. int cChars = _snwprintf(szText, ARRAY_SIZE(szText), L"%.12s \t%s", pszScriptName, bstrMessage);
  1220. szText[ARRAY_SIZE(szText) - 1] = 0;
  1221. if (cChars < 0)
  1222. cChars = ARRAY_SIZE(szText);
  1223. else
  1224. cChars++;
  1225. PostToThread(_pMT,
  1226. MD_OUTPUTDEBUGSTRING,
  1227. szText,
  1228. cChars * sizeof(TCHAR));
  1229. return S_OK;
  1230. }
  1231. HRESULT
  1232. CScriptHost::UnevalString(BSTR bstrInput, BSTR *pbstrOutput)
  1233. {
  1234. int nInputLength = SysStringLen(bstrInput);
  1235. OLECHAR tmpBuf[512];
  1236. OLECHAR *pTmp = 0;
  1237. OLECHAR *pOutputBuffer;
  1238. *pbstrOutput = 0;
  1239. if (sizeof(OLECHAR) * (nInputLength * 2 + 2) > sizeof(tmpBuf))
  1240. {
  1241. pTmp = (OLECHAR *)MemAlloc(sizeof(OLECHAR) * (nInputLength * 2 + 2));
  1242. if (!pTmp)
  1243. return E_OUTOFMEMORY;
  1244. pOutputBuffer = pTmp;
  1245. }
  1246. else
  1247. {
  1248. pOutputBuffer = tmpBuf;
  1249. }
  1250. int j = 0;
  1251. pOutputBuffer[j++] = L'"';
  1252. for(OLECHAR *pInputEnd = bstrInput + nInputLength; bstrInput < pInputEnd; ++bstrInput)
  1253. {
  1254. switch(*bstrInput)
  1255. {
  1256. case L'\\':
  1257. case L'"':
  1258. case L'\'':
  1259. pOutputBuffer[j] = L'\\';
  1260. pOutputBuffer[j+1] = *bstrInput;
  1261. j += 2;
  1262. break;
  1263. case L'\n':
  1264. pOutputBuffer[j] = L'\\';
  1265. pOutputBuffer[j+1] = L'n';
  1266. j += 2;
  1267. break;
  1268. case L'\r':
  1269. pOutputBuffer[j] = L'\\';
  1270. pOutputBuffer[j+1] = L'r';
  1271. j += 2;
  1272. break;
  1273. case L'\t':
  1274. pOutputBuffer[j] = L'\\';
  1275. pOutputBuffer[j+1] = L't';
  1276. j += 2;
  1277. break;
  1278. default:
  1279. pOutputBuffer[j++] = *bstrInput;
  1280. break;
  1281. }
  1282. }
  1283. pOutputBuffer[j++] = L'"';
  1284. *pbstrOutput = SysAllocStringLen(pOutputBuffer, j);
  1285. if (pTmp)
  1286. MemFree(pTmp);
  1287. if (!*pbstrOutput)
  1288. return E_OUTOFMEMORY;
  1289. return S_OK;
  1290. }
  1291. HRESULT
  1292. CScriptHost::CopyOrAppendFile(BSTR bstrSrc,
  1293. BSTR bstrDst,
  1294. long nSrcOffset,
  1295. long nSrcLength,
  1296. VARIANT_BOOL fAppend,
  1297. long *pnSrcFilePosition)
  1298. {
  1299. HRESULT hr = S_OK;
  1300. HANDLE hDst = INVALID_HANDLE_VALUE;
  1301. HANDLE hSrcFile = INVALID_HANDLE_VALUE;
  1302. BY_HANDLE_FILE_INFORMATION fi = {0};
  1303. long nEndPos;
  1304. long nLen;
  1305. DWORD nBytesRead;
  1306. DWORD nBytesWritten;
  1307. char rgBuffer[4096];
  1308. hDst = CreateFile(
  1309. bstrDst,
  1310. GENERIC_WRITE,
  1311. FILE_SHARE_READ,
  1312. 0,
  1313. (fAppend ? OPEN_ALWAYS : CREATE_ALWAYS),
  1314. FILE_ATTRIBUTE_NORMAL,
  1315. 0);
  1316. if (hDst == INVALID_HANDLE_VALUE)
  1317. {
  1318. hr = HRESULT_FROM_WIN32(GetLastError());
  1319. goto Cleanup;
  1320. }
  1321. hSrcFile = CreateFile(bstrSrc,
  1322. GENERIC_READ,
  1323. FILE_SHARE_WRITE,
  1324. 0,
  1325. OPEN_EXISTING,
  1326. FILE_ATTRIBUTE_NORMAL,
  1327. 0);
  1328. if (hSrcFile == INVALID_HANDLE_VALUE)
  1329. {
  1330. hr = HRESULT_FROM_WIN32(GetLastError());
  1331. goto Cleanup;
  1332. }
  1333. GetFileInformationByHandle(hSrcFile, &fi);
  1334. if (fi.nFileSizeHigh != 0 || (fi.nFileSizeLow & 0x80000000) != 0)
  1335. {
  1336. hr = E_FAIL;//HRESULT_FROM_WIN32(?????);
  1337. goto Cleanup;
  1338. }
  1339. if (nSrcLength == -1)
  1340. nEndPos = (long)fi.nFileSizeLow;
  1341. else
  1342. {
  1343. if ( ((_int64)nSrcOffset + nSrcLength) > 0x7f000000)
  1344. {
  1345. hr = E_INVALIDARG;
  1346. goto Cleanup;
  1347. }
  1348. nEndPos = nSrcOffset + nSrcLength;
  1349. }
  1350. if (nEndPos > (long)fi.nFileSizeLow)
  1351. nEndPos = (long)fi.nFileSizeLow;
  1352. if (SetFilePointer(hSrcFile, nSrcOffset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
  1353. {
  1354. hr = HRESULT_FROM_WIN32(GetLastError());
  1355. goto Cleanup;
  1356. }
  1357. if (SetFilePointer(hDst, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
  1358. {
  1359. hr = HRESULT_FROM_WIN32(GetLastError());
  1360. goto Cleanup;
  1361. }
  1362. while (nSrcOffset < nEndPos)
  1363. {
  1364. nLen = nEndPos - nSrcOffset;
  1365. if (nLen > sizeof(rgBuffer))
  1366. nLen = sizeof(rgBuffer);
  1367. if (!ReadFile(hSrcFile, rgBuffer, nLen, &nBytesRead, 0))
  1368. {
  1369. hr = HRESULT_FROM_WIN32(GetLastError());
  1370. goto Cleanup;
  1371. }
  1372. if (!WriteFile(hDst, rgBuffer, nBytesRead, &nBytesWritten, 0))
  1373. {
  1374. hr = HRESULT_FROM_WIN32(GetLastError());
  1375. goto Cleanup;
  1376. }
  1377. nSrcOffset += nBytesRead;
  1378. }
  1379. if (pnSrcFilePosition)
  1380. *pnSrcFilePosition = nSrcOffset;
  1381. Cleanup:
  1382. if (hDst != INVALID_HANDLE_VALUE)
  1383. CloseHandle(hDst);
  1384. if (hSrcFile != INVALID_HANDLE_VALUE)
  1385. CloseHandle(hSrcFile);
  1386. return hr;
  1387. }
  1388. HRESULT
  1389. CScriptHost::ASSERT(VARIANT_BOOL fAssert, BSTR bstrMessage)
  1390. {
  1391. VERIFY_THREAD();
  1392. if (!_fIsPrimaryScript)
  1393. MessageEventPump(FALSE);
  1394. if (!fAssert)
  1395. {
  1396. CHAR ach[1024];
  1397. // Add name of currently executing script to the assert message.
  1398. if (!GetSite() || !GetSite()->_achPath[0])
  1399. {
  1400. ach[0] = 0;
  1401. }
  1402. else
  1403. {
  1404. // Try to chop off directory name.
  1405. TCHAR * pchName = wcsrchr(GetSite()->_achPath, _T('\\'));
  1406. if (pchName)
  1407. pchName += 1;
  1408. else
  1409. pchName = GetSite()->_achPath;
  1410. WideCharToMultiByte(
  1411. CP_ACP,
  1412. 0,
  1413. pchName,
  1414. -1,
  1415. ach,
  1416. MAX_PATH,
  1417. NULL,
  1418. NULL);
  1419. strcat(ach, ": ");
  1420. }
  1421. // Add message to the assert.
  1422. if (!bstrMessage || !*bstrMessage)
  1423. {
  1424. strcat(ach, "MTScript Script Assert");
  1425. }
  1426. else
  1427. {
  1428. WideCharToMultiByte(
  1429. CP_ACP,
  1430. 0,
  1431. bstrMessage,
  1432. -1,
  1433. &ach[strlen(ach)],
  1434. ARRAY_SIZE(ach) - MAX_PATH - 3,
  1435. NULL,
  1436. NULL);
  1437. }
  1438. #if DBG == 1
  1439. AssertSz(FALSE, ach);
  1440. #else
  1441. if (MessageBoxA(NULL, ach, "MTScript Script Assert", MB_OKCANCEL | MB_SETFOREGROUND) == IDCANCEL)
  1442. return E_FAIL;
  1443. #endif
  1444. }
  1445. return S_OK;
  1446. }
  1447. HRESULT
  1448. CScriptHost::Sleep (int nTimeout)
  1449. {
  1450. VERIFY_THREAD();
  1451. MessageEventPump(TRUE, 0, NULL, FALSE, (DWORD)nTimeout);
  1452. return S_OK;
  1453. }
  1454. HRESULT
  1455. CScriptHost::Reboot()
  1456. {
  1457. VERIFY_THREAD();
  1458. PostToThread(_pMT, MD_REBOOT);
  1459. return S_OK;
  1460. }
  1461. HRESULT
  1462. CScriptHost::NotifyScript(BSTR bstrEvent, VARIANT vData)
  1463. {
  1464. HRESULT hr = S_OK;
  1465. VARIANT *pvar;
  1466. VERIFY_THREAD();
  1467. // Check for data types which we don't support.
  1468. if ( V_ISBYREF(&vData)
  1469. || V_ISARRAY(&vData)
  1470. || V_ISVECTOR(&vData)
  1471. || V_VT(&vData) == VT_DISPATCH //$ FUTURE: Support this later
  1472. || V_VT(&vData) == VT_UNKNOWN)
  1473. {
  1474. return E_INVALIDARG;
  1475. }
  1476. if (!_pMT->_pMachine)
  1477. {
  1478. return S_OK;
  1479. }
  1480. pvar = new VARIANT[2];
  1481. VariantInit(&pvar[0]);
  1482. VariantInit(&pvar[1]);
  1483. V_VT(&pvar[0]) = VT_BSTR;
  1484. V_BSTR(&pvar[0]) = SysAllocString(bstrEvent);
  1485. VariantCopy(&pvar[1], &vData);
  1486. PostToThread(_pMT->_pMachine, MD_NOTIFYSCRIPT, &pvar, sizeof(VARIANT*));
  1487. return hr;
  1488. }
  1489. HRESULT
  1490. CScriptHost::RegisterEventSource(IDispatch *pDisp, BSTR bstrProgID)
  1491. {
  1492. HRESULT hr;
  1493. CScriptEventSink *pSink = NULL;
  1494. pSink = new CScriptEventSink(this);
  1495. if (!pSink)
  1496. return E_OUTOFMEMORY;
  1497. hr = pSink->Connect(pDisp, bstrProgID);
  1498. if (!hr)
  1499. {
  1500. _aryEvtSinks.Append(pSink);
  1501. }
  1502. else
  1503. pSink->Release();
  1504. return hr;
  1505. }
  1506. HRESULT
  1507. CScriptHost::UnregisterEventSource(IDispatch *pDisp)
  1508. {
  1509. int i;
  1510. BOOL fFound = FALSE;
  1511. for (i = 0; i < _aryEvtSinks.Size(); i++)
  1512. {
  1513. if (_aryEvtSinks[i]->IsThisYourSource(pDisp))
  1514. {
  1515. _aryEvtSinks[i]->Disconnect();
  1516. _aryEvtSinks.ReleaseAndDelete(i);
  1517. fFound = TRUE;
  1518. break;
  1519. }
  1520. }
  1521. return (fFound) ? S_OK : E_INVALIDARG;
  1522. }
  1523. HRESULT
  1524. CScriptHost::get_HostMajorVer(long *plMajorVer)
  1525. {
  1526. if (!plMajorVer)
  1527. return E_POINTER;
  1528. *plMajorVer = IConnectedMachine_lVersionMajor;
  1529. return S_OK;
  1530. }
  1531. HRESULT
  1532. CScriptHost::get_HostMinorVer(long *plMinorVer)
  1533. {
  1534. if (!plMinorVer)
  1535. return E_POINTER;
  1536. *plMinorVer = IConnectedMachine_lVersionMinor;
  1537. return S_OK;
  1538. }
  1539. HRESULT CScriptHost::get_StatusValue(long nIndex, long *pnStatus)
  1540. {
  1541. return _pMT->get_StatusValue(nIndex, pnStatus);
  1542. }
  1543. HRESULT CScriptHost::put_StatusValue(long nIndex, long nStatus)
  1544. {
  1545. return _pMT->put_StatusValue(nIndex, nStatus);
  1546. }