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.

457 lines
12 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: AUCltCatalog.cpp
  6. //
  7. // Creator: PeterWi
  8. //
  9. // Purpose: Client AU Catalog Functions
  10. //
  11. //=======================================================================
  12. #include "pch.h"
  13. #include "iuprogress.h"
  14. #include "AUEventMsgs.h"
  15. //=======================================================================
  16. //
  17. // CInstallCallback::QueryInterface
  18. //
  19. //=======================================================================
  20. STDMETHODIMP CInstallCallback::QueryInterface(REFIID riid, void **ppvObject)
  21. {
  22. if ( (riid == __uuidof(IUnknown)) || (riid == IID_IProgressListener) )
  23. {
  24. *ppvObject = this;
  25. AddRef();
  26. }
  27. else
  28. {
  29. *ppvObject = NULL;
  30. return E_NOINTERFACE;
  31. }
  32. return S_OK;
  33. }
  34. //=======================================================================
  35. //
  36. // CInstallCallback::AddRef
  37. //
  38. //=======================================================================
  39. STDMETHODIMP_(ULONG) CInstallCallback::AddRef(void)
  40. {
  41. return InterlockedIncrement(&m_refs);;
  42. }
  43. //=======================================================================
  44. //
  45. // CInstallCallback::Release
  46. //
  47. //=======================================================================
  48. STDMETHODIMP_(ULONG) CInstallCallback::Release(void)
  49. {
  50. return InterlockedDecrement(&m_refs);
  51. }
  52. //=======================================================================
  53. //
  54. // CInstallCallback::OnItemStart
  55. //
  56. //=======================================================================
  57. STDMETHODIMP CInstallCallback::OnItemStart(
  58. IN BSTR /*bstrUuidOperation*/,
  59. IN BSTR bstrXmlItem,
  60. OUT LONG *plCommandRequest)
  61. {
  62. DEBUGMSG("InstallProgressListener::OnItemStart(%S)", bstrXmlItem);
  63. *plCommandRequest = 0;
  64. return S_OK;
  65. }
  66. //=======================================================================
  67. //
  68. // CInstallCallback::OnProgress
  69. //
  70. //=======================================================================
  71. STDMETHODIMP CInstallCallback::OnProgress(
  72. IN BSTR /*bstrUuidOperation*/,
  73. IN VARIANT_BOOL fItemCompleted,
  74. IN BSTR bstrProgress,
  75. OUT LONG *plCommandRequest)
  76. {
  77. DEBUGMSG("InstallProgressListener::OnProgress(%S), %s",
  78. bstrProgress, (VARIANT_TRUE == fItemCompleted) ? "completed" : "ongoing");
  79. *plCommandRequest = 0;
  80. if ( fItemCompleted )
  81. {
  82. SendMessage(ghCurrentDialog, AUMSG_INSTALL_PROGRESS, 0, 0);
  83. }
  84. return S_OK;
  85. }
  86. //=======================================================================
  87. //
  88. // CInstallCallback::OnOperationComplete
  89. //
  90. //=======================================================================
  91. HRESULT LogEventToServer(
  92. IUpdates *pUpdates,
  93. WORD wType,
  94. WORD wCategory,
  95. DWORD dwEventID,
  96. DWORD dwItemCount,
  97. BSTR *pbstrItems);
  98. STDMETHODIMP CInstallCallback::OnOperationComplete(
  99. /* [in] */ BSTR bstrUuidOperation,
  100. /* [in] */ BSTR bstrXmlItems)
  101. {
  102. DEBUGMSG("InstallProgressListener::OnOperationComplete() for %S", bstrUuidOperation);
  103. HRESULT hr;
  104. #ifdef DBG
  105. LOGXMLFILE(INSTALLRESULTS_FILE, bstrXmlItems);
  106. #endif
  107. // determine if reboot needed
  108. IXMLDOMDocument *pxmlInstallResult = NULL;
  109. IXMLDOMNodeList *pItemStatuses = NULL;
  110. BSTR *pbstrItemsSucceeded = NULL;
  111. BSTR *pbstrItemsFailed = NULL;
  112. BSTR *pbstrItemsNeedReboot = NULL;
  113. IXMLDOMNode *pItemStatus = NULL;
  114. IXMLDOMNode *pChild = NULL;
  115. BSTR bstrTitle = NULL;
  116. BSTR bstrStatus = NULL;
  117. DWORD dwNumOfItemsSucceeded = 0;
  118. DWORD dwNumOfItemsFailed = 0;
  119. DWORD dwNumOfItemsNeedReboot = 0;
  120. IUpdates *pUpdates = NULL;
  121. BOOL fCoInit = FALSE;
  122. BSTR bstrItemStatusXPath = SysAllocString(L"items/itemStatus");
  123. BSTR bstrTitleXPath = SysAllocString(L"description/descriptionText/title");
  124. BSTR bstrItemStatusNode = SysAllocString(L"installStatus");
  125. BSTR bstrValueAttribute = SysAllocString(L"value");
  126. BSTR bstrNeedsRebootAttribute = SysAllocString(L"needsReboot");
  127. if (NULL == bstrItemStatusXPath || NULL == bstrTitleXPath || NULL == bstrItemStatusNode || NULL == bstrValueAttribute || NULL == bstrNeedsRebootAttribute)
  128. {
  129. hr = E_OUTOFMEMORY;
  130. goto CleanUp;
  131. }
  132. if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
  133. {
  134. DEBUGMSG("InstallProgressListener::OnOperationComplete() CoInitialize failed (%#lx)", hr);
  135. goto CleanUp;
  136. }
  137. fCoInit = TRUE;
  138. if ( FAILED(hr = LoadXMLDoc(bstrXmlItems, &pxmlInstallResult)) )
  139. {
  140. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to LoadXMLDoc() failed (%#lx)", hr);
  141. pxmlInstallResult = NULL;
  142. goto CleanUp;
  143. }
  144. if (FAILED(hr = pxmlInstallResult->selectNodes(bstrItemStatusXPath, &pItemStatuses)) )
  145. {
  146. DEBUGMSG("InstallProgressListener::OnOperationComplete() fail to select node");
  147. pItemStatuses = NULL;
  148. goto CleanUp;
  149. }
  150. long lLen;
  151. if (FAILED(hr = pItemStatuses->get_length(&lLen)))
  152. {
  153. DEBUGMSG("InstallProgressListener::OnOperationComplete() fail to get count of item statuses");
  154. goto CleanUp;
  155. }
  156. if (0 >= lLen)
  157. {
  158. DEBUGMSG("InstallProgressListener::OnOperationComplete() no item statuses found");
  159. hr = E_INVALIDARG;
  160. goto CleanUp;
  161. }
  162. if (NULL == (pbstrItemsSucceeded = (BSTR *) malloc(sizeof(BSTR) * lLen)) ||
  163. NULL == (pbstrItemsFailed = (BSTR *) malloc(sizeof(BSTR) * lLen)) ||
  164. NULL == (pbstrItemsNeedReboot = (BSTR *) malloc(sizeof(BSTR) * lLen)))
  165. {
  166. DEBUGMSG("InstallProgressListener::OnOperationComplete() failed to alloc memory for BSTR *'s");
  167. hr = E_OUTOFMEMORY;
  168. goto CleanUp;
  169. }
  170. for (long index = 0; index < lLen; index++)
  171. {
  172. if (S_OK != (hr = pItemStatuses->get_item(index, &pItemStatus)))
  173. {
  174. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to get_item() failed (%#lx)", hr);
  175. pItemStatus = NULL;
  176. if (S_FALSE == hr)
  177. {
  178. hr = E_FAIL;
  179. }
  180. goto CleanUp;
  181. }
  182. if (S_OK != (hr = pItemStatus->selectSingleNode(bstrTitleXPath, &pChild)))
  183. {
  184. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to selectSingleNode() failed (%#lx)", hr);
  185. pChild = NULL;
  186. if (S_FALSE == hr)
  187. {
  188. hr = E_INVALIDARG;
  189. }
  190. goto CleanUp;
  191. }
  192. if (S_OK != (hr = GetText(pChild, &bstrTitle)))
  193. {
  194. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetText() failed (%#lx)", hr);
  195. bstrTitle = NULL;
  196. if (S_FALSE == hr)
  197. {
  198. hr = E_INVALIDARG;
  199. }
  200. goto CleanUp;
  201. }
  202. pChild->Release();
  203. pChild = NULL;
  204. if (S_OK != (hr = pItemStatus->selectSingleNode(bstrItemStatusNode, &pChild)))
  205. {
  206. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to selectSingleNode() failed (%#lx)", hr);
  207. pChild = NULL;
  208. if (S_FALSE == hr)
  209. {
  210. hr = E_INVALIDARG;
  211. }
  212. goto CleanUp;
  213. }
  214. if (S_OK != (hr = GetAttribute(pChild, bstrValueAttribute, &bstrStatus)))
  215. {
  216. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetAttribute(..., \"value\", ...) failed (%#lx)", hr);
  217. bstrStatus = NULL;
  218. if (S_FALSE == hr)
  219. {
  220. hr = E_INVALIDARG;
  221. }
  222. goto CleanUp;
  223. }
  224. if (CSTR_EQUAL == WUCompareStringI(bstrStatus, L"COMPLETE"))
  225. {
  226. BOOL fReboot;
  227. if (S_OK != (hr = GetAttribute(pChild, bstrNeedsRebootAttribute, &fReboot)))
  228. {
  229. DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetAttribute(..., \"needsReboot\", ...) failed (%#lx)", hr);
  230. if (S_FALSE == hr)
  231. {
  232. hr = E_INVALIDARG;
  233. }
  234. goto CleanUp;
  235. }
  236. if (fReboot)
  237. {
  238. pbstrItemsNeedReboot[dwNumOfItemsNeedReboot++] = bstrTitle;
  239. gpClientCatalog->m_fReboot = TRUE;
  240. }
  241. pbstrItemsSucceeded[dwNumOfItemsSucceeded++] = bstrTitle;
  242. // Now pbstrItemsSucceeded is responsible to free the BSTR.
  243. }
  244. else if (CSTR_EQUAL == WUCompareStringI(bstrStatus, L"FAILED"))
  245. {
  246. pbstrItemsFailed[dwNumOfItemsFailed++] = bstrTitle;
  247. // Now pbstrItemsFailed is responsible to free the BSTR.
  248. }
  249. SysFreeString(bstrStatus);
  250. bstrStatus = NULL;
  251. pChild->Release();
  252. pChild = NULL;
  253. bstrTitle = NULL;
  254. }
  255. if (FAILED(hr = CoCreateInstance(__uuidof(Updates),
  256. NULL,
  257. CLSCTX_LOCAL_SERVER,
  258. IID_IUpdates,
  259. (LPVOID*)&pUpdates)))
  260. {
  261. DEBUGMSG("LogEventToServer failed to get Updates object (%#lx)", hr);
  262. goto CleanUp;
  263. }
  264. if (0 < dwNumOfItemsSucceeded)
  265. {
  266. DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items was successfully installed", dwNumOfItemsSucceeded);
  267. LogEventToServer(
  268. pUpdates,
  269. EVENTLOG_INFORMATION_TYPE,
  270. IDS_MSG_Installation,
  271. IDS_MSG_InstallationSuccessful,
  272. dwNumOfItemsSucceeded,
  273. pbstrItemsSucceeded);
  274. }
  275. if (0 < dwNumOfItemsFailed)
  276. {
  277. DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items failed to install", dwNumOfItemsFailed);
  278. LogEventToServer(
  279. pUpdates,
  280. EVENTLOG_ERROR_TYPE,
  281. IDS_MSG_Installation,
  282. IDS_MSG_InstallationFailure,
  283. dwNumOfItemsFailed,
  284. pbstrItemsFailed);
  285. }
  286. if (0 < dwNumOfItemsNeedReboot)
  287. {
  288. DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items was installed and require reboot", dwNumOfItemsNeedReboot);
  289. AUOPTION auopt;
  290. DWORD dwNoAutoReboot = 0;
  291. (void)GetRegDWordValue(REG_AUNOAUTOREBOOTWITHLOGGEDONUSERS, &dwNoAutoReboot, AUREGKEY_HKLM_DOMAIN_POLICY);
  292. DEBUGMSG("WUAUCLT NoAutoReboot key is %d", dwNoAutoReboot);
  293. if (SUCCEEDED(hr = pUpdates->get_Option(&auopt)) &&
  294. (AUOPTION_SCHEDULED == auopt.dwOption) &&
  295. (0 == dwNoAutoReboot))
  296. {
  297. LogEventToServer(
  298. pUpdates,
  299. EVENTLOG_INFORMATION_TYPE,
  300. IDS_MSG_Installation,
  301. IDS_MSG_RestartNeeded_Scheduled,
  302. dwNumOfItemsNeedReboot,
  303. pbstrItemsNeedReboot);
  304. }
  305. else
  306. {
  307. LogEventToServer(
  308. pUpdates,
  309. EVENTLOG_INFORMATION_TYPE,
  310. IDS_MSG_Installation,
  311. IDS_MSG_RestartNeeded_Unscheduled,
  312. dwNumOfItemsNeedReboot,
  313. pbstrItemsNeedReboot);
  314. }
  315. }
  316. CleanUp:
  317. SafeFreeBSTR(bstrItemStatusXPath);
  318. SafeFreeBSTR(bstrTitleXPath);
  319. SafeFreeBSTR(bstrItemStatusNode);
  320. SafeFreeBSTR(bstrValueAttribute);
  321. SafeFreeBSTR(bstrNeedsRebootAttribute);
  322. SafeRelease(pUpdates);
  323. SysFreeString(bstrStatus);
  324. SysFreeString(bstrTitle);
  325. SafeRelease(pChild);
  326. SafeRelease(pItemStatus);
  327. SafeFree(pbstrItemsNeedReboot);
  328. if (NULL != pbstrItemsFailed)
  329. {
  330. while(dwNumOfItemsFailed > 0)
  331. {
  332. SysFreeString(pbstrItemsFailed[--dwNumOfItemsFailed]);
  333. }
  334. free(pbstrItemsFailed);
  335. }
  336. if (NULL != pbstrItemsSucceeded)
  337. {
  338. while(dwNumOfItemsSucceeded > 0)
  339. {
  340. SysFreeString(pbstrItemsSucceeded[--dwNumOfItemsSucceeded]);
  341. }
  342. free(pbstrItemsSucceeded);
  343. }
  344. SafeRelease(pItemStatuses);
  345. SafeRelease(pxmlInstallResult);
  346. if (fCoInit)
  347. {
  348. CoUninitialize();
  349. }
  350. DEBUGMSG("InstallProgressListener::OnOperationComplete() ends");
  351. return hr;
  352. }
  353. HRESULT LogEventToServer(
  354. IUpdates *pUpdates,
  355. WORD wType,
  356. WORD wCategory,
  357. DWORD dwEventID,
  358. DWORD dwItemCount,
  359. BSTR *pbstrItems)
  360. {
  361. DEBUGMSG("LogEventToServer");
  362. HRESULT hr;
  363. SAFEARRAY *psa;
  364. SAFEARRAYBOUND bound[1] = { dwItemCount, 0};
  365. if (NULL == (psa = SafeArrayCreate(VT_BSTR, 1, bound)))
  366. {
  367. DEBUGMSG("LogEventToServer failed to create safearray");
  368. hr = E_OUTOFMEMORY;
  369. goto CleanUp;
  370. }
  371. BSTR *pbstrElements;
  372. if (S_OK != (hr = SafeArrayAccessData(psa, (void **)&pbstrElements)))
  373. {
  374. DEBUGMSG("LogEventToServer failed to access savearray date (%#lx)", hr);
  375. goto CleanUp;
  376. }
  377. for ( DWORD i = 0; i < dwItemCount; i++ )
  378. {
  379. if (NULL == (pbstrElements[i] = SysAllocString(pbstrItems[i])))
  380. {
  381. DEBUGMSG("LogEventToServer failed to allocate BSTR memory");
  382. hr = E_OUTOFMEMORY;
  383. break;
  384. }
  385. }
  386. if (S_OK != (hr = SafeArrayUnaccessData(psa)))
  387. {
  388. DEBUGMSG("LogEventToServer failed to unaccess safearray data (%#lx)", hr);
  389. }
  390. if (FAILED(hr))
  391. {
  392. goto CleanUp;
  393. }
  394. VARIANT varItems;
  395. varItems.vt = VT_ARRAY | VT_BSTR;
  396. varItems.parray = psa;
  397. hr = pUpdates->LogEvent(wType, wCategory, dwEventID, varItems);
  398. if (FAILED(hr))
  399. {
  400. DEBUGMSG("LogEventToServer failed to call pUpdates->LogEvent (%#lx)", hr);
  401. }
  402. CleanUp:
  403. if (NULL != psa)
  404. {
  405. (void) SafeArrayDestroy(psa);
  406. }
  407. return hr;
  408. }