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.

551 lines
12 KiB

  1. // logrec.cpp, implementation of CLogRecord class
  2. // Copyright (c)1997-1999 Microsoft Corporation
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "precomp.h"
  6. #include "logrec.h"
  7. #include "persistmgr.h"
  8. #include <io.h>
  9. #include "requestobject.h"
  10. // global instance for error text lookup
  11. static CErrorInfo g_ErrorInfo;
  12. const TCHAR c_szCRLF[] = TEXT("\r\n");
  13. /*
  14. Routine Description:
  15. Name:
  16. CLogRecord::CLogRecord
  17. Functionality:
  18. This is the constructor. Pass along the parameters to the base class
  19. Virtual:
  20. No (you know that, constructor won't be virtual!)
  21. Arguments:
  22. pKeyChain - Pointer to the ISceKeyChain COM interface which is prepared
  23. by the caller who constructs this instance.
  24. pNamespace - Pointer to WMI namespace of our provider (COM interface).
  25. Passed along by the caller. Must not be NULL.
  26. pCtx - Pointer to WMI context object (COM interface). Passed along
  27. by the caller. It's up to WMI whether this interface pointer is NULL or not.
  28. Return Value:
  29. None as any constructor
  30. Notes:
  31. if you create any local members, think about initialize them here
  32. */
  33. CLogRecord::CLogRecord (
  34. IN ISceKeyChain * pKeyChain,
  35. IN IWbemServices * pNamespace,
  36. IN IWbemContext * pCtx
  37. )
  38. :
  39. CGenericClass(pKeyChain, pNamespace, pCtx)
  40. {
  41. }
  42. /*
  43. Routine Description:
  44. Name:
  45. CLogRecord::~CLogRecord
  46. Functionality:
  47. Destructor. Necessary as good C++ discipline since we have virtual functions.
  48. Virtual:
  49. Yes.
  50. Arguments:
  51. none as any destructor
  52. Return Value:
  53. None as any destructor
  54. Notes:
  55. if you create any local members, think about whether
  56. there is any need for a non-trivial destructor
  57. */
  58. CLogRecord::~CLogRecord()
  59. {
  60. }
  61. /*
  62. Routine Description:
  63. Name:
  64. CLogRecord::PutInst
  65. Functionality:
  66. Put an instance as instructed by WMI. Since this class implements
  67. Sce_ConfigurationLogRecord, upon being called to put an instance, we
  68. will write a log record into the log file (which is a property of the instance).
  69. Virtual:
  70. Yes.
  71. Arguments:
  72. pInst - COM interface pointer to the WMI class (Sce_ConfigurationLogRecord) object.
  73. pHandler - COM interface pointer for notifying WMI of any events.
  74. pCtx - COM interface pointer. This interface is just something we pass around.
  75. WMI may mandate it (not now) in the future. But we never construct
  76. such an interface and so, we just pass around for various WMI API's
  77. Return Value:
  78. Success: it must return success code (use SUCCEEDED to test). It is
  79. not guaranteed to return WBEM_NO_ERROR.
  80. Failure: Various errors may occurs. Any such error should indicate the failure of persisting
  81. the instance.
  82. Notes:
  83. Since GetProperty will return a success code (WBEM_S_RESET_TO_DEFAULT) when the
  84. requested property is not present, don't simply use SUCCEEDED or FAILED macros
  85. to test for the result of retrieving a property.
  86. */
  87. HRESULT CLogRecord::PutInst
  88. (
  89. IWbemClassObject *pInst,
  90. IWbemObjectSink *pHandler,
  91. IWbemContext *pCtx
  92. )
  93. {
  94. HRESULT hr = WBEM_E_INVALID_PARAMETER;
  95. CComBSTR bstrLogPath;
  96. CComBSTR bstrErrorLabel;
  97. CComBSTR bstrActionLabel;
  98. CComBSTR bstrAction;
  99. CComBSTR bstrCauseLabel;
  100. CComBSTR bstrErrorCause;
  101. CComBSTR bstrObjLabel;
  102. CComBSTR bstrObjDetail;
  103. CComBSTR bstrParamLabel;
  104. CComBSTR bstrParamDetail;
  105. CComBSTR bstrArea;
  106. LPWSTR tmp = NULL;
  107. LPWSTR pszLine = NULL;
  108. DWORD dwCode = 0;
  109. DWORD Len = 0;
  110. DWORD dwBytesWritten=0;
  111. HANDLE hLogFile=INVALID_HANDLE_VALUE;
  112. DWORD dwCRLF = wcslen(c_szCRLF);
  113. CComBSTR bstrErrorCode;
  114. //
  115. // CScePropertyMgr helps us to access WMI object's properties
  116. // create an instance and attach the WMI object to it.
  117. // This will always succeed.
  118. //
  119. CScePropertyMgr ScePropMgr;
  120. ScePropMgr.Attach(pInst);
  121. BOOL bDb = FALSE;
  122. //
  123. // the use of the macro SCE_PROV_IfErrorGotoCleanup cause
  124. // a "goto CleanUp;" with hr set to the return value from
  125. // the function (macro parameter)
  126. //
  127. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetExpandedPath(pLogFilePath, &bstrLogPath, &bDb));
  128. //
  129. // we will only log into a plain text file, not a database file
  130. //
  131. if ( bDb )
  132. {
  133. hr = WBEM_E_INVALID_PARAMETER;
  134. goto CleanUp;
  135. }
  136. //
  137. // retrieve all those properties, see the definition of this WMI class
  138. // inside sceprov.mof for detail.
  139. //
  140. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pLogArea, &bstrArea));
  141. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pLogErrorCode, &dwCode));
  142. if ( hr == WBEM_S_RESET_TO_DEFAULT )
  143. {
  144. dwCode = 0;
  145. }
  146. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pAction, &bstrAction));
  147. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pErrorCause, &bstrErrorCause));
  148. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pObjectDetail, &bstrObjDetail));
  149. SCE_PROV_IfErrorGotoCleanup(ScePropMgr.GetProperty(pParameterDetail, &bstrParamDetail));
  150. //
  151. // merge data into one buffer
  152. //
  153. bstrErrorLabel.LoadString(IDS_ERROR_CODE);
  154. //
  155. // get the text version of the error code
  156. //
  157. hr = g_ErrorInfo.GetErrorText(dwCode, &bstrErrorCode);
  158. //
  159. // we really can't do anything if this even fails
  160. //
  161. if (FAILED(hr))
  162. {
  163. return hr;
  164. }
  165. //
  166. // now calculate the giant buffer size!
  167. //
  168. //
  169. // 11 counts for "0xXXXXXXXX=", 1 for \t
  170. //
  171. Len = wcslen(bstrErrorLabel) + 11 + wcslen(bstrErrorCode) + 1;
  172. //
  173. // 1 for \t
  174. //
  175. Len += wcslen(bstrArea) + 1;
  176. if ( NULL != (LPCWSTR)bstrAction )
  177. {
  178. bstrActionLabel.LoadString(IDS_ACTION);
  179. //
  180. // 1 for \t
  181. //
  182. Len += dwCRLF + 1 + wcslen(bstrActionLabel) + wcslen(bstrAction);
  183. }
  184. if ( NULL != (LPCWSTR)bstrErrorCause )
  185. {
  186. bstrCauseLabel.LoadString(IDS_FAILURE_CAUSE);
  187. //
  188. // 1 for \t
  189. //
  190. Len += dwCRLF + 1 + wcslen(bstrCauseLabel) + wcslen(bstrErrorCause);
  191. }
  192. if ( NULL != (LPCWSTR)bstrObjDetail )
  193. {
  194. bstrObjLabel.LoadString(IDS_OBJECT_DETAIL);
  195. //
  196. // 1 for \t
  197. //
  198. Len += dwCRLF + 1 + wcslen(bstrObjLabel) + wcslen(bstrObjDetail);
  199. }
  200. if ( NULL != (LPCWSTR)bstrParamDetail )
  201. {
  202. bstrParamLabel.LoadString(IDS_PARAMETER_DETAIL);
  203. //
  204. // 1 for \t
  205. //
  206. Len += dwCRLF + 1 + wcslen(bstrParamLabel) + wcslen(bstrParamDetail);
  207. }
  208. //
  209. // each log will create a blank line, i.e. two c_szCRLF
  210. //
  211. Len += dwCRLF * 2;
  212. //
  213. // now, we have the length, we need a buffer of that length.
  214. // need to free, 1 for '\0'
  215. //
  216. pszLine = new WCHAR[Len + 1];
  217. if ( NULL == pszLine )
  218. {
  219. hr = WBEM_E_OUT_OF_MEMORY;
  220. goto CleanUp;
  221. }
  222. //
  223. // if we get the buffer, then, we will format various information
  224. // into this buffer to be written to the log file
  225. //
  226. //
  227. // error code will look like this: ErrorCode: 0xXXXXXXXX=ErrorText, where 0xXXXXXXXX is the code itself
  228. //
  229. swprintf(pszLine, L"%s0x%08X=%s\t", (LPCWSTR)bstrErrorLabel, dwCode, (LPCWSTR)bstrErrorCode);
  230. wcscat(pszLine, bstrArea);
  231. if (NULL != (LPCWSTR)bstrAction)
  232. {
  233. wcscat(pszLine, c_szCRLF);
  234. wcscat(pszLine, L"\t");
  235. wcscat(pszLine, bstrActionLabel);
  236. wcscat(pszLine, bstrAction);
  237. }
  238. if (NULL != (LPCWSTR)bstrErrorCause)
  239. {
  240. wcscat(pszLine, c_szCRLF);
  241. wcscat(pszLine, L"\t");
  242. wcscat(pszLine, bstrCauseLabel);
  243. wcscat(pszLine, bstrErrorCause);
  244. }
  245. if (NULL != (LPCWSTR)bstrObjDetail)
  246. {
  247. wcscat(pszLine, c_szCRLF);
  248. wcscat(pszLine, L"\t");
  249. wcscat(pszLine, bstrObjLabel);
  250. wcscat(pszLine, bstrObjDetail);
  251. }
  252. if (NULL != (LPCWSTR)bstrParamDetail)
  253. {
  254. wcscat(pszLine, c_szCRLF);
  255. wcscat(pszLine, L"\t");
  256. wcscat(pszLine, bstrParamLabel);
  257. wcscat(pszLine, bstrParamDetail);
  258. }
  259. wcscat(pszLine, c_szCRLF);
  260. wcscat(pszLine, c_szCRLF);
  261. //
  262. // now save the info to log file
  263. //
  264. hLogFile = ::CreateFile(bstrLogPath,
  265. GENERIC_WRITE,
  266. FILE_SHARE_READ,
  267. NULL,
  268. OPEN_ALWAYS,
  269. FILE_ATTRIBUTE_NORMAL,
  270. NULL);
  271. if ( INVALID_HANDLE_VALUE != hLogFile )
  272. {
  273. //
  274. // don't overwrite the old log records
  275. //
  276. SetFilePointer (hLogFile, 0, NULL, FILE_END);
  277. //
  278. // try to write. WriteFile returns 0 it fails.
  279. //
  280. if ( 0 == WriteFile (hLogFile,
  281. (LPCVOID) pszLine,
  282. Len * sizeof(WCHAR),
  283. &dwBytesWritten,
  284. NULL
  285. ) )
  286. {
  287. //
  288. // GetLastError() eeds to be translated to HRESULT.
  289. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  290. //
  291. hr = ProvDosErrorToWbemError(GetLastError());
  292. }
  293. CloseHandle( hLogFile );
  294. }
  295. else
  296. {
  297. //
  298. // GetLastError() eeds to be translated to HRESULT.
  299. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  300. //
  301. hr = ProvDosErrorToWbemError(GetLastError());
  302. }
  303. CleanUp:
  304. delete [] pszLine;
  305. return hr;
  306. }
  307. //
  308. // implementation of CErrorInfo, the error text lookup object
  309. //
  310. /*
  311. Routine Description:
  312. Name:
  313. CErrorInfo::CErrorInfo
  314. Functionality:
  315. This is the constructor. We will create the WMI IWbemStatusCodeText object here.
  316. Virtual:
  317. No (you know that, constructor won't be virtual!)
  318. Arguments:
  319. none.
  320. Return Value:
  321. None as any constructor
  322. Notes:
  323. if you create any local members, think about initialize them here
  324. */
  325. CErrorInfo::CErrorInfo ()
  326. {
  327. //
  328. // if this fails, we just won't be able to lookup error text
  329. //
  330. ::CoCreateInstance (CLSID_WbemStatusCodeText,
  331. 0, CLSCTX_INPROC_SERVER,
  332. IID_IWbemStatusCodeText,
  333. (LPVOID*)&m_srpStatusCodeText
  334. );
  335. }
  336. /*
  337. Routine Description:
  338. Name:
  339. CErrorInfo::GetErrorText
  340. Functionality:
  341. This is the HRESULT --> text translation function..
  342. Virtual:
  343. No
  344. Arguments:
  345. none.
  346. Return Value:
  347. Success: (1) whatever is returned from IWbemStatusCodeText::GetErrorCodeText if that succeeds.
  348. (2) WBEM_S_FALSE if IWbemStatusCodeText::GetErrorCodeText fails to get the text
  349. and in that case, we will simply try to give the caller the text version of
  350. the error code, something like 0x81002321
  351. Failure: WBEM_E_INVALID_PARAMETER if pbstrErrText == NULL
  352. WBEM_E_OUT_OF_MEMORY if we can't allocate the bstr.
  353. WBEM_E_NOT_AVAILABLE if our IWbemStatusCodeText object can't be created
  354. Notes:
  355. caller is responsible to release the bstr *pbstrErrText
  356. */
  357. HRESULT
  358. CErrorInfo::GetErrorText (
  359. IN HRESULT hrCode,
  360. OUT BSTR * pbstrErrText
  361. )
  362. {
  363. if (pbstrErrText == NULL)
  364. {
  365. return WBEM_E_INVALID_PARAMETER;
  366. }
  367. *pbstrErrText = NULL;
  368. HRESULT hr = WBEM_E_NOT_AVAILABLE;
  369. if (m_srpStatusCodeText)
  370. {
  371. //
  372. // IWbemStatusCodeText is to translate the HRESULT to text
  373. //
  374. hr = m_srpStatusCodeText->GetErrorCodeText(hrCode, 0, 0, pbstrErrText);
  375. }
  376. if (FAILED(hr) || *pbstrErrText == NULL)
  377. {
  378. //
  379. // we fall back to just formatting the error code
  380. //
  381. *pbstrErrText = ::SysAllocStringLen(NULL, 16);
  382. if (*pbstrErrText != NULL)
  383. {
  384. wsprintf(*pbstrErrText, L"%08x", hrCode);
  385. hr = WBEM_S_FALSE;
  386. }
  387. }
  388. return hr;
  389. }