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.

390 lines
13 KiB

  1. /********************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. PCH_Module.CPP
  5. Abstract:
  6. WBEM provider class implementation for PCH_Module class
  7. Revision History:
  8. Ghim-Sim Chua (gschua) 04/27/99
  9. - Created
  10. Jim Martin (a-jammar) 05/20/99
  11. - Populated data fields.
  12. ********************************************************************/
  13. #include "pchealth.h"
  14. #include "PCH_Module.h"
  15. #include <tlhelp32.h>
  16. /////////////////////////////////////////////////////////////////////////////
  17. // tracing stuff
  18. #ifdef THIS_FILE
  19. #undef THIS_FILE
  20. #endif
  21. static char __szTraceSourceFile[] = __FILE__;
  22. #define THIS_FILE __szTraceSourceFile
  23. #define TRACE_ID DCID_MODULE
  24. CPCH_Module MyPCH_ModuleSet (PROVIDER_NAME_PCH_MODULE, PCH_NAMESPACE) ;
  25. // Property names
  26. //===============
  27. const static WCHAR * pAddress = L"Address" ;
  28. const static WCHAR * pTimeStamp = L"TimeStamp" ;
  29. const static WCHAR * pChange = L"Change" ;
  30. const static WCHAR * pDate = L"Date" ;
  31. const static WCHAR * pDescription = L"Description" ;
  32. const static WCHAR * pManufacturer = L"Manufacturer" ;
  33. const static WCHAR * pName = L"Name" ;
  34. const static WCHAR * pPartOf = L"PartOf" ;
  35. const static WCHAR * pPath = L"Path" ;
  36. const static WCHAR * pSize = L"Size" ;
  37. const static WCHAR * pType = L"Type" ;
  38. const static WCHAR * pVersion = L"Version" ;
  39. //-----------------------------------------------------------------------------
  40. // The CModuleCollection class is used to gather all of the running modules.
  41. // They can be found from the CIM_ProcessExecutable class, as the Antecedent
  42. // property, with the following caveat: this enumeration will include
  43. // duplicate entries of the same file (it will have a copy of a DLL for each
  44. // time it's been loaded). This class will remove the duplicates, and save
  45. // a list of filenames which can then be queried.
  46. //-----------------------------------------------------------------------------
  47. class CModuleCollection
  48. {
  49. public:
  50. CModuleCollection();
  51. ~CModuleCollection();
  52. HRESULT Create(IEnumWbemClassObject * pEnum);
  53. BOOL GetInstance(DWORD dwIndex, LPWSTR * pszFile);
  54. private:
  55. struct SModule
  56. {
  57. LPWSTR m_szFilename;
  58. SModule * m_pNext;
  59. SModule(LPWSTR szFilename, SModule * pNext) : m_pNext(pNext) { m_szFilename = szFilename; }
  60. ~SModule() { delete m_szFilename; }
  61. };
  62. SModule * m_pList;
  63. SModule * m_pLastQueriedItem;
  64. DWORD m_dwLastQueriedIndex;
  65. };
  66. //-----------------------------------------------------------------------------
  67. // The constructor and destructor are simple.
  68. //-----------------------------------------------------------------------------
  69. CModuleCollection::CModuleCollection()
  70. : m_pList(NULL),
  71. m_pLastQueriedItem(NULL),
  72. m_dwLastQueriedIndex(0)
  73. {}
  74. CModuleCollection::~CModuleCollection()
  75. {
  76. TraceFunctEnter("CModuleCollection::~CModuleCollection");
  77. while (m_pList)
  78. {
  79. SModule * pNext = m_pList->m_pNext;
  80. delete m_pList;
  81. m_pList = pNext;
  82. }
  83. TraceFunctLeave();
  84. }
  85. //-----------------------------------------------------------------------------
  86. // The Create method creates the list of module names based on the enumerator
  87. // passed in (which is assumed to enumerate Antecedents in
  88. // CIM_ProcessExecutable).
  89. //-----------------------------------------------------------------------------
  90. HRESULT CModuleCollection::Create(IEnumWbemClassObject * pEnum)
  91. {
  92. TraceFunctEnter("CModuleCollection::Create");
  93. HRESULT hRes = S_OK;
  94. IWbemClassObjectPtr pObj;
  95. ULONG ulRetVal;
  96. CComVariant varValue;
  97. CComBSTR bstrFile("Antecedent");
  98. while (WBEM_S_NO_ERROR == pEnum->Next(WBEM_INFINITE, 1, &pObj, &ulRetVal))
  99. {
  100. if (FAILED(pObj->Get(bstrFile, 0, &varValue, NULL, NULL)))
  101. ErrorTrace(TRACE_ID, "Get on Antecedent field failed.");
  102. else
  103. {
  104. // We need to convert the string from a BSTR to a LPCTSTR,
  105. // and to only include the file part (without the WMI part).
  106. // So we need to scan through the string until an '=' is
  107. // found, then use the rest (minus enclosing quote marks)
  108. // as the file path.
  109. CComBSTR ccombstrValue(V_BSTR(&varValue));
  110. UINT i = 0, uLen = SysStringLen(ccombstrValue);
  111. // Scan to the '='.
  112. while (i < uLen && ccombstrValue[i] != L'=')
  113. i++;
  114. // Skip over the '=' and any quotes.
  115. while (i < uLen && (ccombstrValue[i] == L'=' || ccombstrValue[i] == L'"'))
  116. i++;
  117. // Allocate a character buffer and copy the string, converting it to
  118. // lower case (to make comparisons faster later on).
  119. LPWSTR szFilename = new WCHAR[uLen - i + 1];
  120. if (!szFilename)
  121. {
  122. ErrorTrace(TRACE_ID, "CModuleCollection::Create out of memory");
  123. throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
  124. }
  125. for (int j = 0; i < uLen; j++, i++)
  126. szFilename[j] = towlower(ccombstrValue[i]);
  127. // Terminate the string - if it ends with a quote, overwrite that with a
  128. // null character.
  129. if (j && szFilename[j - 1] == L'"')
  130. j -= 1;
  131. szFilename[j] = L'\0';
  132. // Check to see if this module is already in the list of strings.
  133. SModule * pScan = m_pList;
  134. while (pScan)
  135. {
  136. if (wcscmp(szFilename, pScan->m_szFilename) == 0)
  137. break;
  138. pScan = pScan->m_pNext;
  139. }
  140. if (pScan == NULL)
  141. {
  142. // We reached the end of the list without finding a duplicate.
  143. // Add the new string to the list of modules, which will be responsible for
  144. // deallocating the string.
  145. SModule * pNew = new SModule(szFilename, m_pList);
  146. if (!pNew)
  147. {
  148. delete [] szFilename;
  149. ErrorTrace(TRACE_ID, "CModuleCollection::Create out of memory");
  150. throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
  151. }
  152. m_pList = pNew;
  153. }
  154. else
  155. delete [] szFilename;
  156. }
  157. }
  158. // Set the queried item pointer to the start of the list.
  159. m_pLastQueriedItem = m_pList;
  160. m_dwLastQueriedIndex = 0;
  161. TraceFunctLeave();
  162. return hRes;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Get the instance of module string referenced by the index. This is stored
  166. // internally as a linked list, but we'll cache a pointer for the last
  167. // referenced dwIndex to improve performance if the dwIndex is iterated
  168. // sequentially. Return TRUE and set pszFile to point to the string if
  169. // it exists, otherwise return FALSE.
  170. //-----------------------------------------------------------------------------
  171. BOOL CModuleCollection::GetInstance(DWORD dwIndex, LPWSTR * pszFile)
  172. {
  173. TraceFunctEnter("CModuleCollection::GetInstance");
  174. // If the call is for an index less than the last queried index (which
  175. // should be rare), we need to scan from the start of the list.
  176. if (dwIndex < m_dwLastQueriedIndex)
  177. {
  178. m_dwLastQueriedIndex = 0;
  179. m_pLastQueriedItem = m_pList;
  180. }
  181. // Scan through the list by (dwIndex - m_dwLastQueriedIndex) items.
  182. while (dwIndex > m_dwLastQueriedIndex && m_pLastQueriedItem)
  183. {
  184. m_pLastQueriedItem = m_pLastQueriedItem->m_pNext;
  185. m_dwLastQueriedIndex += 1;
  186. }
  187. BOOL fResult = FALSE;
  188. if (m_pLastQueriedItem)
  189. {
  190. *pszFile = m_pLastQueriedItem->m_szFilename;
  191. fResult = TRUE;
  192. }
  193. TraceFunctLeave();
  194. return fResult;
  195. }
  196. /*****************************************************************************
  197. *
  198. * FUNCTION : CPCH_Module::EnumerateInstances
  199. *
  200. * DESCRIPTION : Returns all the instances of this class.
  201. *
  202. * INPUTS : A pointer to the MethodContext for communication with WinMgmt.
  203. * A long that contains the flags described in
  204. * IWbemServices::CreateInstanceEnumAsync. Note that the following
  205. * flags are handled by (and filtered out by) WinMgmt:
  206. * WBEM_FLAG_DEEP
  207. * WBEM_FLAG_SHALLOW
  208. * WBEM_FLAG_RETURN_IMMEDIATELY
  209. * WBEM_FLAG_FORWARD_ONLY
  210. * WBEM_FLAG_BIDIRECTIONAL
  211. *
  212. * RETURNS : WBEM_S_NO_ERROR if successful
  213. *
  214. * COMMENTS : TO DO: All instances on the machine should be returned here.
  215. * If there are no instances, return WBEM_S_NO_ERROR.
  216. * It is not an error to have no instances.
  217. *
  218. *****************************************************************************/
  219. typedef HANDLE (*CTH32)(DWORD, DWORD);
  220. HRESULT CPCH_Module::EnumerateInstances(MethodContext * pMethodContext, long lFlags)
  221. {
  222. TraceFunctEnter("CPCH_Module::EnumerateInstances");
  223. HRESULT hRes = WBEM_S_NO_ERROR;
  224. // Get the date and time
  225. SYSTEMTIME stUTCTime;
  226. GetSystemTime(&stUTCTime);
  227. // Create a toolhelp snapshot to get process information. We need to dynamically
  228. // link to the function, because it might not be present on all platforms.
  229. // The CModuleCollection class gathers a list of module names (which can then
  230. // be used to retrieve information about each file).
  231. CFileVersionInfo fileversioninfo;
  232. CModuleCollection moduleinfo;
  233. LPWSTR szFile;
  234. DWORD dwIndex;
  235. CComPtr<IEnumWbemClassObject> pEnum;
  236. hRes = ExecWQLQuery(&pEnum, CComBSTR("SELECT Antecedent FROM CIM_ProcessExecutable"));
  237. if (FAILED(hRes))
  238. goto END;
  239. hRes = moduleinfo.Create(pEnum);
  240. if (FAILED(hRes))
  241. goto END;
  242. // Iterate through all of the module instances.
  243. for (dwIndex = 0; moduleinfo.GetInstance(dwIndex, &szFile); dwIndex++)
  244. {
  245. if (!szFile)
  246. continue;
  247. CInstancePtr pInstance(CreateNewInstance(pMethodContext), false);
  248. // Set the change and timestamp fields to "Snapshot" and the current time.
  249. if (!pInstance->SetDateTime(pTimeStamp, WBEMTime(stUTCTime)))
  250. ErrorTrace(TRACE_ID, "SetDateTime on Timestamp field failed.");
  251. if (!pInstance->SetCHString(pChange, L"Snapshot"))
  252. ErrorTrace(TRACE_ID, "SetCHString on Change field failed.");
  253. // Using the filename, get the CIM_DataFile object.
  254. CComPtr<IWbemClassObject> pFileObj;
  255. CComBSTR ccombstrValue(szFile);
  256. if (SUCCEEDED(GetCIMDataFile(ccombstrValue, &pFileObj, TRUE)))
  257. {
  258. // Using the CIM_DataFile object, copy over the appropriate properties.
  259. CopyProperty(pFileObj, L"Version", pInstance, pVersion);
  260. CopyProperty(pFileObj, L"FileSize", pInstance, pSize);
  261. CopyProperty(pFileObj, L"CreationDate", pInstance, pDate);
  262. CopyProperty(pFileObj, L"Name", pInstance, pPath);
  263. CopyProperty(pFileObj, L"EightDotThreeFileName", pInstance, pName);
  264. CopyProperty(pFileObj, L"Manufacturer", pInstance, pManufacturer);
  265. }
  266. else
  267. {
  268. CComBSTR bstr;
  269. VARIANT var;
  270. WCHAR *pwsz;
  271. // parse the file path to get the name out of it...
  272. // the name should obviously be the last thing on the path, so
  273. // search back from the end until we find a '\'. At that point,
  274. // we've got the filename...
  275. pwsz = ccombstrValue.m_str + SysStringLen(ccombstrValue.m_str) - 1;
  276. while(pwsz >= ccombstrValue.m_str)
  277. {
  278. if (*pwsz == L'\\')
  279. {
  280. pwsz++;
  281. break;
  282. }
  283. pwsz--;
  284. }
  285. bstr = pwsz;
  286. VariantInit(&var);
  287. V_VT(&var) = VT_BSTR;
  288. V_BSTR(&var) = bstr.m_str;
  289. if (pInstance->SetVariant(pName, var) == FALSE)
  290. ErrorTrace(TRACE_ID, "SetVariant on name field failed.");
  291. }
  292. if (SUCCEEDED(fileversioninfo.QueryFile(szFile, TRUE)))
  293. {
  294. if (!pInstance->SetCHString(pDescription, fileversioninfo.GetDescription()))
  295. ErrorTrace(TRACE_ID, "SetCHString on description field failed.");
  296. if (!pInstance->SetCHString(pPartOf, fileversioninfo.GetProduct()))
  297. ErrorTrace(TRACE_ID, "SetCHString on partof field failed.");
  298. }
  299. hRes = pInstance->Commit();
  300. if (FAILED(hRes))
  301. ErrorTrace(TRACE_ID, "Commit on Instance failed.");
  302. }
  303. END:
  304. TraceFunctLeave();
  305. return hRes;
  306. }