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.

484 lines
11 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 2001-2002 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: AUEventLog.cpp
  6. //
  7. // Creator: DChow
  8. //
  9. // Purpose: Event Logging class
  10. //
  11. //=======================================================================
  12. #include "pch.h"
  13. extern HINSTANCE g_hInstance;
  14. extern AUCatalog *gpAUcatalog;
  15. const TCHAR c_tszSourceKey[] = _T("SYSTEM\\CurrentControlSet\\Services\\Eventlog\\System\\Automatic Updates");
  16. CAUEventLog::CAUEventLog(HINSTANCE hInstance)
  17. : m_hEventLog(NULL), m_ptszListItemFormat(NULL)
  18. {
  19. const DWORD c_dwLen = 64;
  20. LPTSTR ptszToken = NULL;
  21. if (NULL != (m_ptszListItemFormat = (LPTSTR) malloc(sizeof(TCHAR) * c_dwLen)) &&
  22. 0 != LoadString(
  23. hInstance,
  24. IDS_EVT_LISTITEMFORMAT,
  25. m_ptszListItemFormat,
  26. c_dwLen) &&
  27. NULL != (ptszToken = StrStr(m_ptszListItemFormat, _T("%lS"))) &&
  28. EnsureValidSource() &&
  29. NULL != (m_hEventLog = RegisterEventSource(NULL, _T("Automatic Updates"))))
  30. {
  31. // bug 492897: WUAU: W2K: Event log error for installation failure
  32. // does not show the package that failed. CombineItems() calls
  33. // StringCchPrintfEx() which in turn calls _sntprintf(). _sntprintf
  34. // calls wvsprintf(). Compiled with USE_VCRT=1, the %lS placeholder
  35. // in the format string will be replaced under Win2K by only the first
  36. // character of the intended string, contrary to MSDN. It doesn't
  37. // happen if the placeholder is %ls, %ws or %wS, or if the running
  38. // platform is WinXP or .Net Server. To get around the problem
  39. // without using an unsafe function, we choose to replace %lS in the
  40. // format string from resource with %ls.
  41. // We should move the fix to the resource string when we can.
  42. ptszToken[2] = _T('s'); // Convert %lS into %ls
  43. }
  44. else
  45. {
  46. AUASSERT(FALSE);
  47. SafeFreeNULL(m_ptszListItemFormat);
  48. }
  49. }
  50. CAUEventLog::~CAUEventLog()
  51. {
  52. if (NULL != m_hEventLog)
  53. {
  54. DeregisterEventSource(m_hEventLog);
  55. }
  56. SafeFree(m_ptszListItemFormat);
  57. }
  58. // Assume no NULL in the pbstrItems and pptszMsgParams arrays.
  59. BOOL CAUEventLog::LogEvent(
  60. WORD wType,
  61. WORD wCategory,
  62. DWORD dwEventID,
  63. UINT nNumOfItems,
  64. BSTR *pbstrItems,
  65. WORD wNumOfMsgParams,
  66. LPTSTR *pptszMsgParams) const
  67. {
  68. if (NULL == m_hEventLog || NULL == m_ptszListItemFormat)
  69. {
  70. return FALSE;
  71. }
  72. BOOL fRet = FALSE;
  73. LPTSTR ptszItemList = NULL;
  74. LPTSTR *pptszAllMsgParams = pptszMsgParams;
  75. WORD wNumOfAllMsgParams = wNumOfMsgParams;
  76. if (0 < nNumOfItems)
  77. {
  78. wNumOfAllMsgParams++;
  79. if (NULL == (ptszItemList = CombineItems(nNumOfItems, pbstrItems)))
  80. {
  81. goto CleanUp;
  82. }
  83. if (0 < wNumOfMsgParams)
  84. {
  85. if (NULL == (pptszAllMsgParams = (LPTSTR *) malloc(sizeof(LPTSTR) * wNumOfAllMsgParams)))
  86. {
  87. goto CleanUp;
  88. }
  89. for (INT i=0; i<wNumOfMsgParams; i++)
  90. {
  91. pptszAllMsgParams[i] = pptszMsgParams[i];
  92. }
  93. pptszAllMsgParams[i] = ptszItemList;
  94. }
  95. else
  96. {
  97. pptszAllMsgParams = &ptszItemList;
  98. }
  99. }
  100. fRet = ReportEvent(
  101. m_hEventLog,
  102. wType,
  103. wCategory,
  104. dwEventID,
  105. NULL,
  106. wNumOfAllMsgParams,
  107. 0,
  108. (LPCTSTR *) pptszAllMsgParams,
  109. NULL);
  110. CleanUp:
  111. if (0 < nNumOfItems)
  112. {
  113. if (0 < wNumOfMsgParams)
  114. {
  115. SafeFree(pptszAllMsgParams);
  116. }
  117. SafeFree(ptszItemList);
  118. }
  119. return fRet;
  120. }
  121. BOOL CAUEventLog::LogEvent(
  122. WORD wType,
  123. WORD wCategory,
  124. DWORD dwEventID,
  125. SAFEARRAY *psa) const
  126. {
  127. DEBUGMSG("CAUEvetLog::LogEvent(VARIANT version)");
  128. long lItemCount, i = 0;
  129. HRESULT hr;
  130. // similar check should have been done in Update::LogEvent()
  131. /* if (NULL == psa)
  132. {
  133. hr = E_INVALIDARG;
  134. goto CleanUp;
  135. }
  136. VARTYPE vt;
  137. if (FAILED(hr = SafeArrayGetVartype(psa, &vt)))
  138. {
  139. DEBUGMSG("CAUEvetLog::LogEvent(VARIANT version) failed to get safearray type (%#lx)", hr);
  140. goto CleanUp;
  141. }
  142. if (VT_BSTR != vt)
  143. {
  144. DEBUGMSG("CAUEvetLog::LogEvent(VARIANT version) invalid element type of safearray (%#lx)", vt);
  145. goto CleanUp;
  146. }
  147. */
  148. if (FAILED(hr = SafeArrayGetUBound(psa, 1, &lItemCount)))
  149. {
  150. DEBUGMSG("CAUEventLog::LogEvent(VARIANT version) failed to get upper bound (%#lx)", hr);
  151. goto CleanUp;
  152. }
  153. lItemCount++;
  154. BSTR *pbstrItems = NULL;
  155. if (NULL == (pbstrItems = (BSTR *) malloc(sizeof(BSTR) * lItemCount)))
  156. {
  157. DEBUGMSG("CAUEventLog::LogEvent(VARIANT version) out of memory");
  158. goto CleanUp;
  159. }
  160. BOOL fRet = FALSE;
  161. while (i < lItemCount)
  162. {
  163. long dex = i;
  164. if (FAILED(hr = SafeArrayGetElement(psa, &dex, &pbstrItems[i])))
  165. {
  166. DEBUGMSG("CAUEventLog::LogEvent(VARIANT version) SafeArrayGetElement failed (%#lx)", hr);
  167. goto CleanUp;
  168. }
  169. i++;
  170. }
  171. fRet = LogEvent(
  172. wType,
  173. wCategory,
  174. dwEventID,
  175. lItemCount,
  176. pbstrItems);
  177. CleanUp:
  178. if (NULL != pbstrItems)
  179. {
  180. while(i > 0)
  181. {
  182. SysFreeString(pbstrItems[--i]);
  183. }
  184. free(pbstrItems);
  185. }
  186. DEBUGMSG("CAUEventLog::LogEvent(VARIANT version) ends");
  187. return fRet;
  188. }
  189. // The caller is responsible for freeing the return value if this function succeeds.
  190. LPTSTR CAUEventLog::CombineItems(UINT nNumOfItems, BSTR *pbstrItems) const
  191. {
  192. DEBUGMSG("CombineItems");
  193. if (NULL != m_ptszListItemFormat && NULL != pbstrItems && 0 < nNumOfItems)
  194. {
  195. // Estimate buffer size
  196. size_t cchBufferLen = 1; // 1 for the terminating NULL
  197. size_t cchListItemFormatLen = lstrlen(m_ptszListItemFormat);
  198. for (UINT i=0; i<nNumOfItems; i++)
  199. {
  200. if (0 < i)
  201. {
  202. cchBufferLen += 2; // for line feed and carriage return (i.e. _T('\n'))
  203. }
  204. cchBufferLen += cchListItemFormatLen + SysStringLen(pbstrItems[i]);
  205. }
  206. LPTSTR ptszBuffer;
  207. cchBufferLen = min(cchBufferLen, 0x8000); // String limit for ReportEvent
  208. if (NULL != (ptszBuffer = (LPTSTR) malloc(sizeof(TCHAR) * cchBufferLen)))
  209. {
  210. LPTSTR ptszDest = ptszBuffer;
  211. for (i = 0;;)
  212. {
  213. if (FAILED(StringCchPrintfEx(
  214. ptszDest,
  215. cchBufferLen,
  216. &ptszDest,
  217. &cchBufferLen,
  218. MISTSAFE_STRING_FLAGS,
  219. m_ptszListItemFormat, // uses %ls; so okay w/ BSTR (UNICODE)
  220. pbstrItems[i++])))
  221. {
  222. DEBUGMSG("CAUEventLog::CombineItems() call to StringCchPrintfEx() failed");
  223. return ptszBuffer;
  224. }
  225. if (i == nNumOfItems)
  226. {
  227. return ptszBuffer;
  228. }
  229. if (cchBufferLen <= 1)
  230. {
  231. DEBUGMSG("CAUEventLog::CombineItems() insufficient buffer for newline");
  232. return ptszBuffer;
  233. }
  234. *ptszDest++ = _T('\n');
  235. *ptszDest = _T('\0');
  236. cchBufferLen--;
  237. }
  238. }
  239. }
  240. return NULL;
  241. }
  242. BOOL CAUEventLog::EnsureValidSource()
  243. {
  244. HKEY hKey;
  245. DWORD dwDisposition;
  246. if (ERROR_SUCCESS != RegCreateKeyEx(
  247. HKEY_LOCAL_MACHINE, // root key
  248. c_tszSourceKey, // subkey
  249. 0, // reserved
  250. NULL, // class name
  251. REG_OPTION_NON_VOLATILE, // option
  252. KEY_QUERY_VALUE | KEY_SET_VALUE, // security
  253. NULL, // security attribute
  254. &hKey,
  255. &dwDisposition))
  256. {
  257. return FALSE;
  258. }
  259. BOOL fRet = TRUE;
  260. if (REG_OPENED_EXISTING_KEY == dwDisposition)
  261. {
  262. (void) RegCloseKey(hKey);
  263. }
  264. else
  265. {
  266. DWORD dwCategoryCount = 2; //fixcode: should it be hardcoded?
  267. // DWORD dwDisplayNameID = IDS_SERVICENAME;
  268. DWORD dwTypesSupported =
  269. EVENTLOG_ERROR_TYPE |
  270. EVENTLOG_WARNING_TYPE |
  271. EVENTLOG_INFORMATION_TYPE;
  272. const TCHAR c_tszWUAUENG_DLL[] = _T("%SystemRoot%\\System32\\wuaueng.dll");
  273. if (ERROR_SUCCESS != RegSetValueEx(
  274. hKey,
  275. _T("CategoryCount"), // value name
  276. 0, // reserved
  277. REG_DWORD, // type
  278. (BYTE*) &dwCategoryCount, // data
  279. sizeof(dwCategoryCount)) || // size
  280. ERROR_SUCCESS != RegSetValueEx(
  281. hKey,
  282. _T("CategoryMessageFile"),
  283. 0,
  284. REG_EXPAND_SZ,
  285. (BYTE*) c_tszWUAUENG_DLL,
  286. sizeof(c_tszWUAUENG_DLL)) || // not ARRAYSIZE
  287. // ERROR_SUCCESS != RegSetValueEx(
  288. // hKey,
  289. // _T("DisplayNameFile"),
  290. // 0,
  291. // REG_EXPAND_SZ,
  292. // (BYTE*) c_tszWUAUENG_DLL,
  293. // sizeof(c_tszWUAUENG_DLL)) || // not ARRAYSIZE
  294. // ERROR_SUCCESS != RegSetValueEx(
  295. // hKey,
  296. // _T("DisplayNameID"),
  297. // 0,
  298. // REG_DWORD,
  299. // (BYTE*) &dwDisplayNameID,
  300. // sizeof(dwDisplayNameID)) ||
  301. ERROR_SUCCESS != RegSetValueEx(
  302. hKey,
  303. _T("EventMessageFile"),
  304. 0,
  305. REG_EXPAND_SZ,
  306. (BYTE*) c_tszWUAUENG_DLL,
  307. sizeof(c_tszWUAUENG_DLL)) || // not ARRAYSIZE
  308. ERROR_SUCCESS != RegSetValueEx(
  309. hKey,
  310. _T("TypesSupported"),
  311. 0,
  312. REG_DWORD,
  313. (BYTE*) &dwTypesSupported,
  314. sizeof(dwTypesSupported)))
  315. {
  316. fRet = FALSE;
  317. }
  318. if (ERROR_SUCCESS != RegCloseKey(hKey))
  319. {
  320. fRet = FALSE;
  321. }
  322. }
  323. return fRet;
  324. }
  325. void LogEvent_ItemList(
  326. WORD wType,
  327. WORD wCategory,
  328. DWORD dwEventID,
  329. WORD wNumOfMsgParams,
  330. LPTSTR *pptszMsgParams)
  331. {
  332. AUCatalogItemList &itemList = gpAUcatalog->m_ItemList;
  333. UINT nNumOfItems = itemList.GetNumSelected();
  334. if (0 < nNumOfItems)
  335. {
  336. BSTR *pbstrItems = (BSTR *) malloc(sizeof(BSTR) * nNumOfItems);
  337. if (NULL != pbstrItems)
  338. {
  339. CAUEventLog aueventlog(g_hInstance);
  340. UINT j = 0;
  341. for (UINT i=0; i<itemList.Count(); i++)
  342. {
  343. AUCatalogItem &item = itemList[i];
  344. if (item.fSelected())
  345. {
  346. pbstrItems[j++] = item.bstrTitle();
  347. }
  348. }
  349. aueventlog.LogEvent(
  350. wType,
  351. wCategory,
  352. dwEventID,
  353. nNumOfItems,
  354. pbstrItems,
  355. wNumOfMsgParams,
  356. pptszMsgParams);
  357. free(pbstrItems);
  358. }
  359. else
  360. {
  361. DEBUGMSG("LogEvent_ItemList() failed to allocate memory for pbstrItems");
  362. }
  363. }
  364. else
  365. {
  366. DEBUGMSG("LogEvent_ItemList() no item in gpAUcatalog is selected!");
  367. }
  368. }
  369. void LogEvent_ScheduledInstall(void)
  370. {
  371. TCHAR tszScheduledDate[64];
  372. TCHAR tszScheduledTime[40];
  373. AUFILETIME auftSchedInstallDate;
  374. SYSTEMTIME stScheduled;
  375. DEBUGMSG("LogEvent_ScheduledInstall");
  376. gpState->GetSchedInstallDate(auftSchedInstallDate);
  377. //fixcode: any need to use DATE_LTRREADING or DATE_RTLREADING?
  378. if (FileTimeToSystemTime(&auftSchedInstallDate.ft, &stScheduled))
  379. {
  380. if (0 != GetDateFormat(
  381. LOCALE_SYSTEM_DEFAULT,
  382. LOCALE_NOUSEROVERRIDE | DATE_LONGDATE,
  383. &stScheduled,
  384. NULL,
  385. tszScheduledDate,
  386. ARRAYSIZE(tszScheduledDate)))
  387. {
  388. if (Hours2LocalizedString(
  389. &stScheduled,
  390. tszScheduledTime,
  391. ARRAYSIZE(tszScheduledTime)))
  392. {
  393. LPTSTR pptszMsgParams[2];
  394. pptszMsgParams[0] = tszScheduledDate;
  395. pptszMsgParams[1] = tszScheduledTime;
  396. LogEvent_ItemList(
  397. EVENTLOG_INFORMATION_TYPE,
  398. IDS_MSG_Installation,
  399. IDS_MSG_InstallReady_Scheduled,
  400. 2,
  401. pptszMsgParams);
  402. }
  403. #ifdef DBG
  404. else
  405. {
  406. DEBUGMSG("LogEvent_ScheduledInstall() call to Hours2LocalizedString() failed");
  407. }
  408. #endif
  409. }
  410. #ifdef DBG
  411. else
  412. {
  413. DEBUGMSG("LogEvent_ScheduledInstall() call to GetDateFormatW() failed (%#lx)", GetLastError());
  414. }
  415. #endif
  416. }
  417. #ifdef DBG
  418. else
  419. {
  420. DEBUGMSG("LogEvent_ScheduledInstall() call to FileTimeToSystemTime() failed (%#lx)", GetLastError());
  421. }
  422. #endif
  423. }