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.

335 lines
8.8 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: proccomm.cxx
  7. //
  8. // Contents: Implementation of the CProcessComm class
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "headers.hxx"
  12. DeclareTag(tagProcComm, "MTScript", "IScriptedProcess communication");
  13. CProcessComm::CProcessComm(CMTScript *pMT)
  14. {
  15. _ulRefs = 1;
  16. _pMT = pMT;
  17. Assert(_pSink == NULL);
  18. Assert(_pSH == NULL);
  19. Assert(_pProc == NULL);
  20. TraceTag((tagProcComm, "CProcessComm this(%x)", this));
  21. }
  22. CProcessComm::~CProcessComm()
  23. {
  24. TraceTag((tagProcComm, "%p: Destroyed this(%x)", _pProc, this));
  25. if (_pProc)
  26. {
  27. _pProc->SetProcComm(NULL);
  28. }
  29. ReleaseInterface(_pSink);
  30. ReleaseInterface(_pSH);
  31. ReleaseInterface(_pProc);
  32. }
  33. HRESULT
  34. CProcessComm::QueryInterface(REFIID iid, void **ppv)
  35. {
  36. if (iid == IID_IUnknown || iid == IID_IScriptedProcess)
  37. {
  38. *ppv = (IScriptedProcess *)this;
  39. }
  40. else
  41. {
  42. *ppv = NULL;
  43. return E_NOINTERFACE;
  44. }
  45. ((IUnknown *)*ppv)->AddRef();
  46. return S_OK;
  47. }
  48. //+---------------------------------------------------------------------------
  49. //
  50. // Member: CProcessComm::SetProcessID, public
  51. //
  52. // Synopsis: Called by the remote process to tell us who it is. We use
  53. // the information to match it with the CProcessThread and
  54. // CScriptHost object that created it.
  55. //
  56. // Arguments: [lProcessID] -- Process ID of the calling process
  57. // [pszEnvID] -- Value of the __MTSCRIPT_ENV_ID environment
  58. // variable.
  59. //
  60. // Returns: S_OK, E_INVALIDARG if a match could not be made.
  61. //
  62. //----------------------------------------------------------------------------
  63. STDMETHODIMP
  64. CProcessComm::SetProcessID(long lProcessID, wchar_t *pszEnvID)
  65. {
  66. CProcessThread **ppProc;
  67. int cProcs;
  68. long lEnvID;
  69. wchar_t *pch;
  70. if (!pszEnvID)
  71. {
  72. return E_INVALIDARG;
  73. }
  74. if (_pProc)
  75. {
  76. TraceTag((tagProcComm, "%p: Got duplicate call to SetProcessID! (id=%d)", _pProc, lProcessID));
  77. return E_UNEXPECTED;
  78. }
  79. lEnvID = wcstol(pszEnvID, &pch, 10);
  80. LOCK_LOCALS(_pMT);
  81. for (ppProc = _pMT->_aryProcesses, cProcs = _pMT->_aryProcesses.Size();
  82. cProcs;
  83. ppProc++, cProcs--)
  84. {
  85. if ((*ppProc)->IsOwner(lProcessID, lEnvID))
  86. {
  87. break;
  88. }
  89. }
  90. if (cProcs == 0)
  91. {
  92. return E_INVALIDARG;
  93. }
  94. // We don't allow more than one process to connect to a single
  95. // CProcessThread. This could happen if more than one child process of
  96. // the one we launched with RunLocalCommand tries to connect. All but the
  97. // first one will get an error back.
  98. if ((*ppProc)->GetProcComm())
  99. {
  100. TraceTag((tagProcComm, "%p: Got duplicate call to SetProcessID! (id=%d)", *ppProc, lProcessID));
  101. return E_UNEXPECTED;
  102. }
  103. _pProc = *ppProc;
  104. _pProc->AddRef();
  105. _pSH = _pProc->ScriptHost();
  106. _pSH->AddRef();
  107. _pProc->SetProcComm(this);
  108. TraceTag((tagProcComm, "Proc:%p, this:%p: Received SetProcessID call: %d, %ls", _pProc, this, lProcessID, pszEnvID));
  109. _pMT->PostToThread(_pSH, MD_PROCESSCONNECTED, &_pProc, sizeof(CProcessComm*));
  110. return S_OK;
  111. }
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Member: CProcessComm::SendData, public
  115. //
  116. // Synopsis: Called by the remote process when it wants to fire an event
  117. // into the script.
  118. //
  119. // Arguments: [pszType] -- String giving name of data
  120. // [pszData] -- String giving data
  121. // [plReturn] -- Return value from event handler
  122. //
  123. // Returns: HRESULT
  124. //
  125. // Notes: This uses the same data structures as CMachine::Exec and is
  126. // basically the same code.
  127. //
  128. //----------------------------------------------------------------------------
  129. STDMETHODIMP
  130. CProcessComm::SendData(wchar_t * pszType,
  131. wchar_t * pszData,
  132. long * plReturn)
  133. {
  134. // We create an event object for each call on this method. While this
  135. // may have a cost, it makes this method thread-safe. If we cached an
  136. // event object then we would have to synchronize access to that event
  137. // object which could be even more expensive.
  138. MACHPROC_EVENT_DATA med;
  139. MACHPROC_EVENT_DATA * pmed;
  140. VARIANT vRet;
  141. VARIANT vLong;
  142. HRESULT hr = S_OK;
  143. TraceTag((tagProcComm, "%p: SendData call received: (%ls, %ls)", _pProc, pszType, pszData));
  144. VariantInit(&vRet);
  145. VariantInit(&vLong);
  146. if (!_pSH)
  147. {
  148. return E_UNEXPECTED;
  149. }
  150. if (!plReturn)
  151. {
  152. return E_INVALIDARG;
  153. }
  154. med.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  155. if (med.hEvent == NULL)
  156. {
  157. return HRESULT_FROM_WIN32(GetLastError());
  158. }
  159. med.bstrCmd = SysAllocString(pszType);
  160. med.bstrParams = SysAllocString(pszData);
  161. med.dwProcId = _pProc->ProcId();
  162. med.pvReturn = &vRet;
  163. med.dwGITCookie = 0;
  164. med.hrReturn = S_OK;
  165. pmed = &med;
  166. _pMT->PostToThread(_pSH,
  167. MD_PROCESSDATA,
  168. (LPVOID)&pmed,
  169. sizeof(MACHPROC_EVENT_DATA*));
  170. // We can do WaitForSingleObject because we are in OLE's multi-threaded
  171. // apartment and don't need to handle messages from our event loop.
  172. WaitForSingleObject(med.hEvent, INFINITE);
  173. if (med.hrReturn != S_OK)
  174. {
  175. hr = med.hrReturn;
  176. goto Cleanup;
  177. }
  178. if (VariantChangeType(&vLong, &vRet, 0, VT_I4) != S_OK)
  179. {
  180. *plReturn = -1;
  181. }
  182. else
  183. {
  184. *plReturn = V_I4(&vLong);
  185. }
  186. Cleanup:
  187. VariantClear(&vRet);
  188. VariantClear(&vLong);
  189. SysFreeString(med.bstrCmd);
  190. SysFreeString(med.bstrParams);
  191. CloseHandle(med.hEvent);
  192. TraceTag((tagProcComm, "%p: SendData is returning %x", _pProc, hr));
  193. return hr;
  194. }
  195. //+---------------------------------------------------------------------------
  196. //
  197. // Member: CProcessComm::SetExitCode, public
  198. //
  199. // Synopsis: Sets the exit code which will be given to the script for
  200. // this process. This will override the actual exit code of
  201. // the process.
  202. //
  203. // Arguments: [lExitCode] -- New exit code.
  204. //
  205. //----------------------------------------------------------------------------
  206. STDMETHODIMP
  207. CProcessComm::SetExitCode(long lExitCode)
  208. {
  209. if (!_pProc)
  210. {
  211. return E_UNEXPECTED;
  212. }
  213. TraceTag((tagProcComm, "%p: Process set exit code of %d", _pProc, lExitCode));
  214. _pProc->SetExitCode((DWORD)lExitCode);
  215. return S_OK;
  216. }
  217. //+---------------------------------------------------------------------------
  218. //
  219. // Member: CProcessComm::SetProcessSink, public
  220. //
  221. // Synopsis: Sets the sink interface so the script can call back into
  222. // the remote process.
  223. //
  224. // Arguments: [pSink] -- Sink interface
  225. //
  226. // Returns: HRESULT
  227. //
  228. // Notes: Clear the sink by calling SetProcessSink with NULL before
  229. // shutting down.
  230. //
  231. //----------------------------------------------------------------------------
  232. STDMETHODIMP
  233. CProcessComm::SetProcessSink(IScriptedProcessSink *pSink)
  234. {
  235. ReleaseInterface(_pSink);
  236. _pSink = pSink;
  237. TraceTag((tagProcComm, "%p: Received new process sink (%p)", _pProc, pSink));
  238. if (pSink)
  239. {
  240. pSink->AddRef();
  241. }
  242. return S_OK;
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Member: CProcessComm::SendToProcess, public
  247. //
  248. // Synopsis: Sends a command to the remote process as requested by the
  249. // script engine.
  250. //
  251. // Arguments: [pmed] -- Pointer to cross-thread data structure.
  252. //
  253. //----------------------------------------------------------------------------
  254. void
  255. CProcessComm::SendToProcess(MACHPROC_EVENT_DATA *pmed)
  256. {
  257. long lReturn = 0;
  258. HRESULT hr = S_OK;
  259. TraceTag((tagProcComm, "%p: Making call to ReceiveData. Params=(%ls, %ls)",
  260. _pProc, pmed->bstrCmd, pmed->bstrParams));
  261. if (_pSink)
  262. {
  263. hr = _pSink->ReceiveData(pmed->bstrCmd, pmed->bstrParams, &lReturn);
  264. }
  265. V_VT(pmed->pvReturn) = VT_I4;
  266. V_I4(pmed->pvReturn) = lReturn;
  267. TraceTag((tagProcComm, "%p: Call to ReceiveData returned %x", _pProc, hr));
  268. pmed->hrReturn = hr;
  269. SetEvent(pmed->hEvent);
  270. return;
  271. }