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.

476 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: buildscr.cpp
  7. //
  8. // Contents: Implementation of the code which talks to the MTScript engine
  9. // when doing a distributed build using the build console.
  10. //
  11. //----------------------------------------------------------------------------
  12. #include "scrproc.h"
  13. #include "build.h"
  14. #include "buildscr.h"
  15. #define INITGUID
  16. #include <guiddef.h>
  17. DEFINE_GUID(CLSID_LocalScriptedProcess, 0x854c316f,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
  18. DEFINE_GUID(IID_IScriptedProcess, 0x854c3171,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
  19. DEFINE_GUID(IID_IScriptedProcessSink, 0x854c3172,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
  20. DEFINE_GUID(CLSID_ObjectDaemon,0x854c3184,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xE4,0x39,0x1b);
  21. DEFINE_GUID(IID_IConnectedMachine,0x854c316c,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
  22. DEFINE_GUID(IID_IObjectDaemon,0x854c3183,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xE4,0x39,0x1b);
  23. #define MAX_RETRIES 2
  24. HANDLE g_hMTEvent = NULL;
  25. HANDLE g_hMTThread = NULL;
  26. DWORD g_dwMTThreadId = 0;
  27. //+---------------------------------------------------------------------------
  28. //
  29. // Function: WaitForResume
  30. //
  31. // Synopsis: Sends a "phase complete" message to the script engine and then
  32. // waits for it to tell us to resume (if specified).
  33. //
  34. // Arguments: [fPause] -- If TRUE, we wait for a resume command
  35. // [pe] -- Message to send to the script engine
  36. //
  37. //----------------------------------------------------------------------------
  38. void
  39. WaitForResume(BOOL fPause, PROC_EVENTS pe)
  40. {
  41. if (g_hMTEvent)
  42. {
  43. HANDLE aHandles[2] = { g_hMTEvent, g_hMTThread };
  44. ResetEvent(g_hMTEvent);
  45. PostThreadMessage(g_dwMTThreadId, pe, 0, 0);
  46. if (fPause)
  47. {
  48. // Wait until either the event object is signaled or the thread dies
  49. WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
  50. }
  51. }
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Function: ExitMTScriptThread
  56. //
  57. // Synopsis: Tells the thread talking to the MTScript engine to exit.
  58. //
  59. //----------------------------------------------------------------------------
  60. void
  61. ExitMTScriptThread()
  62. {
  63. if (g_hMTEvent)
  64. {
  65. PostThreadMessage(g_dwMTThreadId, PE_EXIT, 0, 0);
  66. WaitForSingleObject(g_hMTThread, INFINITE);
  67. CloseHandle(g_hMTThread);
  68. CloseHandle(g_hMTEvent);
  69. }
  70. }
  71. //+---------------------------------------------------------------------------
  72. //
  73. // Function: SendStatus
  74. //
  75. // Synopsis: Sends a status message to the MTScript engine with the
  76. // current number of errors, warnings, and completed files.
  77. //
  78. // Arguments: [pSP] -- Pointer to MTScript engine interface
  79. //
  80. //----------------------------------------------------------------------------
  81. void
  82. SendStatus(IScriptedProcess *pSP)
  83. {
  84. wchar_t achBuf[300];
  85. long lRet;
  86. static ULONG cErrorsPrev = MAXDWORD;
  87. static ULONG cWarnPrev = MAXDWORD;
  88. static ULONG cFilesPrev = MAXDWORD;
  89. ULONG cErrors = RunningTotals.NumberCompileErrors +
  90. RunningTotals.NumberLibraryErrors +
  91. RunningTotals.NumberLinkErrors +
  92. RunningTotals.NumberBinplaceErrors;
  93. ULONG cWarn = RunningTotals.NumberCompileWarnings +
  94. RunningTotals.NumberLibraryWarnings +
  95. RunningTotals.NumberLinkWarnings +
  96. RunningTotals.NumberBinplaceWarnings;
  97. ULONG cFiles = RunningTotals.NumberCompiles +
  98. RunningTotals.NumberLibraries +
  99. RunningTotals.NumberLinks;
  100. /* + RunningTotals.NumberBinplaces */;
  101. // Only send status if it's changed since last time we did it.
  102. if ( cErrors != cErrorsPrev
  103. || cWarn != cWarnPrev
  104. || cFiles != cFilesPrev)
  105. {
  106. cErrorsPrev = cErrors;
  107. cWarnPrev = cWarn;
  108. cFilesPrev = cFiles;
  109. wsprintfW(achBuf, L"errors=%d,warnings=%d,files=%d", cErrors, cWarn, cFiles);
  110. pSP->SendData(L"status", achBuf, &lRet);
  111. }
  112. }
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Function: HandleMessage
  116. //
  117. // Synopsis: Handles a message that has come across our message queue.
  118. //
  119. // Arguments: [pmsg] -- Message
  120. // [pSP] -- Pointer to MTScript engine interface
  121. //
  122. //----------------------------------------------------------------------------
  123. BOOL
  124. HandleMessage(MSG *pmsg, IScriptedProcess *pSP)
  125. {
  126. long lRet;
  127. HRESULT hr = S_OK;
  128. switch (pmsg->message)
  129. {
  130. case PE_PASS0_COMPLETE:
  131. SendStatus(pSP);
  132. hr = pSP->SendData(L"pass 0 complete", L"", &lRet);
  133. break;
  134. case PE_PASS1_COMPLETE:
  135. SendStatus(pSP);
  136. hr = pSP->SendData(L"pass 1 complete", L"", &lRet);
  137. break;
  138. case PE_PASS2_COMPLETE:
  139. SendStatus(pSP);
  140. hr = pSP->SendData(L"pass 2 complete", L"", &lRet);
  141. break;
  142. case PE_EXIT:
  143. SendStatus(pSP);
  144. hr = pSP->SendData(L"build complete", L"", &lRet);
  145. return TRUE;
  146. break;
  147. }
  148. if (hr != S_OK)
  149. {
  150. BuildErrorRaw("\nBUILD: Communication with script engine failed: %x", hr);
  151. }
  152. return (hr != S_OK) ? TRUE : FALSE;
  153. }
  154. const DWORD UPDATE_INTERVAL = 2 * 1000; // Update every 2 seconds
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Function: MTScriptThread
  158. //
  159. // Synopsis: Thread entrypoint. Initializes and then sits around
  160. // handling various events.
  161. //
  162. // Arguments: [pv] -- Not used.
  163. //
  164. //----------------------------------------------------------------------------
  165. DWORD WINAPI
  166. MTScriptThread(LPVOID pv)
  167. {
  168. HRESULT hr;
  169. IScriptedProcess * pSP = NULL;
  170. wchar_t achBuf[100];
  171. MSG msg;
  172. DWORD dwRet;
  173. CProcessSink cps;
  174. BOOL fExit = FALSE;
  175. int cRetries = 0;
  176. BuildMsg("Establishing connection with Script engine...\n");
  177. LogMsg("Establishing connection with Script engine...\n");
  178. // Force Windows to create a message queue for this thread, since we will
  179. // be communicated to via PostThreadMessage.
  180. PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
  181. // If anything fails we just quit this thread and communication with
  182. // the MTScript engine won't happen.
  183. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  184. if (hr != S_OK)
  185. {
  186. BuildErrorRaw("BUILD: CoInitializeEx failed with %x\n", hr);
  187. goto Cleanup;
  188. }
  189. hr = S_FALSE;
  190. while (hr != S_OK)
  191. {
  192. pSP = NULL;
  193. IObjectDaemon *pIObjectDaemon;
  194. hr = CoCreateInstance(CLSID_ObjectDaemon, NULL, CLSCTX_SERVER,
  195. IID_IObjectDaemon, (LPVOID*)&pIObjectDaemon);
  196. if (hr == S_OK)
  197. {
  198. IDispatch *pIDispatch;
  199. BSTR bstrProgID = SysAllocString(L"MTScript.Remote");
  200. BSTR bstrIdentity = SysAllocString(_wgetenv(L"__MTSCRIPT_ENV_IDENTITY"));
  201. hr = pIObjectDaemon->OpenInterface(bstrIdentity, bstrProgID, (BOOL)FALSE, (IDispatch**)&pIDispatch);
  202. if (hr == S_OK)
  203. {
  204. IConnectedMachine *pIConnectedMachine;
  205. hr = pIDispatch->QueryInterface(IID_IConnectedMachine, (LPVOID*)&pIConnectedMachine);
  206. if (hr == S_OK)
  207. {
  208. hr = pIConnectedMachine->CreateIScriptedProcess(GetCurrentProcessId(), (wchar_t *)_wgetenv(L"__MTSCRIPT_ENV_ID"), (IScriptedProcess **)&pSP);
  209. pIConnectedMachine->Release();
  210. }
  211. else
  212. {
  213. BuildMsg("CreateIScriptedProcess failed with %x.\n", hr);
  214. LogMsg("CreateIScriptedProcess failed with %x.\n", hr);
  215. }
  216. pIDispatch->Release();
  217. }
  218. else
  219. {
  220. BuildMsg("OpenInterface failed with %x.\n", hr);
  221. LogMsg("OpenInterface failed with %x.\n", hr);
  222. }
  223. SysFreeString(bstrProgID);
  224. SysFreeString(bstrIdentity);
  225. pIObjectDaemon->Release();
  226. }
  227. else
  228. {
  229. BuildMsg("CoCreateInstance failed with %x.\n", hr);
  230. LogMsg("CoCreateInstance failed with %x.\n", hr);
  231. }
  232. if (hr == S_OK)
  233. {
  234. hr = pSP->SetProcessSink(&cps);
  235. if (hr != S_OK)
  236. {
  237. BuildMsg("SetProcessSink failed with %x.\n", hr);
  238. LogMsg("SetProcessSink failed with %x.\n", hr);
  239. }
  240. }
  241. if (hr != S_OK)
  242. {
  243. if (cRetries >= MAX_RETRIES)
  244. {
  245. BuildErrorRaw("BUILD: FATAL: Connection to script engine could not be established. (%x)\n", hr);
  246. goto Cleanup;
  247. }
  248. if (pSP)
  249. {
  250. pSP->Release();
  251. pSP = NULL;
  252. }
  253. BuildMsg("Connection to script engine failed with %x, retries=%d...\n", hr, cRetries);
  254. LogMsg("Connection to script engine failed with %x, retries=%d...\n", hr, cRetries);
  255. Sleep(500);
  256. cRetries++;
  257. }
  258. }
  259. BuildMsg("Connection to script engine established...\n");
  260. LogMsg("Connection to script engine established...\r\n");
  261. // Tell build.c that it can continue
  262. SetEvent(g_hMTEvent);
  263. while (TRUE)
  264. {
  265. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  266. {
  267. if (HandleMessage(&msg, pSP))
  268. {
  269. fExit = TRUE;
  270. }
  271. }
  272. if (fExit)
  273. {
  274. break;
  275. }
  276. dwRet = MsgWaitForMultipleObjects(0,
  277. NULL,
  278. FALSE,
  279. UPDATE_INTERVAL,
  280. QS_ALLINPUT);
  281. if (dwRet == WAIT_OBJECT_0)
  282. {
  283. // A message is coming through on our message queue. Just loop
  284. // around.
  285. }
  286. else if (dwRet == WAIT_TIMEOUT)
  287. {
  288. SendStatus(pSP);
  289. }
  290. else
  291. {
  292. // MWFMO failed. Just bail out.
  293. break;
  294. }
  295. }
  296. Cleanup:
  297. if (pSP)
  298. {
  299. pSP->SetProcessSink(NULL);
  300. pSP->Release();
  301. }
  302. CoUninitialize();
  303. if (hr != S_OK)
  304. {
  305. g_hMTThread = NULL;
  306. }
  307. SetEvent(g_hMTEvent);
  308. return 0;
  309. }
  310. // ***********************************************************************
  311. //
  312. // CProcessSink implementation
  313. //
  314. // We hand this class to the MTScript engine so it can communicate back
  315. // to us.
  316. //
  317. // ***********************************************************************
  318. CProcessSink::CProcessSink()
  319. {
  320. _ulRefs = 1;
  321. }
  322. HRESULT
  323. CProcessSink::QueryInterface(REFIID riid, LPVOID *ppv)
  324. {
  325. if (riid == IID_IUnknown || riid == IID_IScriptedProcessSink)
  326. {
  327. *ppv = (IScriptedProcessSink*)this;
  328. }
  329. else
  330. {
  331. *ppv = NULL;
  332. return E_NOINTERFACE;
  333. }
  334. ((IUnknown *)*ppv)->AddRef();
  335. return S_OK;
  336. }
  337. ULONG
  338. CProcessSink::AddRef()
  339. {
  340. return InterlockedIncrement((long*)&_ulRefs);
  341. }
  342. ULONG
  343. CProcessSink::Release()
  344. {
  345. if (InterlockedDecrement((long*)&_ulRefs) == 0)
  346. {
  347. _ulRefs = 0xFF;
  348. delete this;
  349. return 0;
  350. }
  351. return _ulRefs;
  352. }
  353. //+---------------------------------------------------------------------------
  354. //
  355. // Member: CProcessSink::RequestExit, public
  356. //
  357. // Synopsis: Called when the MTScript engine wants us to quit. If we don't,
  358. // it will terminate us.
  359. //
  360. //----------------------------------------------------------------------------
  361. HRESULT
  362. CProcessSink::RequestExit()
  363. {
  364. // There is no easy way to tell build.exe to abort. We'll just let
  365. // MTScript terminate us.
  366. return S_OK;
  367. }
  368. //+---------------------------------------------------------------------------
  369. //
  370. // Member: CProcessSink::ReceiveData, public
  371. //
  372. // Synopsis: Called when the MTScript engine wants to send us a message.
  373. //
  374. // Arguments: [pszType] -- String giving the message
  375. // [pszData] -- String giving data associated with the message.
  376. // [plReturn] -- A place we can return a value back.
  377. //
  378. //----------------------------------------------------------------------------
  379. HRESULT
  380. CProcessSink::ReceiveData(wchar_t *pszType, wchar_t *pszData, long *plReturn)
  381. {
  382. *plReturn = 0;
  383. if (wcscmp(pszType, L"resume") == 0)
  384. {
  385. SetEvent(g_hMTEvent);
  386. }
  387. else
  388. {
  389. *plReturn = -1; // Signals an error
  390. }
  391. return S_OK;
  392. }