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.

548 lines
19 KiB

  1. /********************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. PCH_OLERegistration.CPP
  5. Abstract:
  6. WBEM provider class implementation for PCH_OLERegistration class
  7. Revision History:
  8. Ghim-Sim Chua (gschua) 04/27/99
  9. - Created
  10. Jim Martin (a-jammar) 05/14/99
  11. - Gathering data.
  12. ********************************************************************/
  13. #include "pchealth.h"
  14. #include "PCH_OLERegistration.h"
  15. /////////////////////////////////////////////////////////////////////////////
  16. // tracing stuff
  17. #ifdef THIS_FILE
  18. #undef THIS_FILE
  19. #endif
  20. static char __szTraceSourceFile[] = __FILE__;
  21. #define THIS_FILE __szTraceSourceFile
  22. #define TRACE_ID DCID_OLEREGISTRATION
  23. CPCH_OLERegistration MyPCH_OLERegistrationSet (PROVIDER_NAME_PCH_OLEREGISTRATION, PCH_NAMESPACE) ;
  24. // Property names
  25. //===============
  26. const static WCHAR * pCategory = L"Category" ;
  27. const static WCHAR * pTimeStamp = L"TimeStamp" ;
  28. const static WCHAR * pChange = L"Change" ;
  29. const static WCHAR * pDate = L"Date" ;
  30. const static WCHAR * pDescription = L"Description" ;
  31. const static WCHAR * pObject = L"Object" ;
  32. const static WCHAR * pProgramFile = L"ProgramFile" ;
  33. const static WCHAR * pSize = L"Size" ;
  34. const static WCHAR * pVersion = L"Version" ;
  35. //-----------------------------------------------------------------------------
  36. // The COLERegItem class encapsulates a single OLE Registration item, and is
  37. // used to build a linked list of items. Note that the constructor is private,
  38. // since the only way one of these is created is by the friend class
  39. // COLEItemCollection.
  40. //-----------------------------------------------------------------------------
  41. #define CATEGORY_LEN 9
  42. #define DESCRIPTION_LEN 128
  43. #define OBJECT_LEN 128
  44. #define PROGRAM_LEN MAX_PATH
  45. class COLEItemCollection;
  46. class COLERegItem
  47. {
  48. friend class COLEItemCollection;
  49. private:
  50. TCHAR m_szCategory[CATEGORY_LEN];
  51. TCHAR m_szDescription[DESCRIPTION_LEN];
  52. TCHAR m_szObject[OBJECT_LEN];
  53. TCHAR m_szProgramFile[PROGRAM_LEN];
  54. public:
  55. LPCTSTR GetCategory() { return m_szCategory; };
  56. LPCTSTR GetDescription() { return m_szDescription; };
  57. LPCTSTR GetObject() { return m_szObject; };
  58. LPCTSTR GetProgramFile() { return m_szProgramFile; };
  59. private:
  60. COLERegItem();
  61. COLERegItem * m_pNext;
  62. };
  63. COLERegItem::COLERegItem()
  64. {
  65. m_szCategory[0] = _T('\0');
  66. m_szDescription[0] = _T('\0');
  67. m_szObject[0] = _T('\0');
  68. m_szProgramFile[0] = _T('\0');
  69. m_pNext = NULL;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // The COLEItemCollection class is used to gather all of the OLE Registration
  73. // items (from the registry and INI file) when the object is constructed. The
  74. // object is then used to iterate all of the items, returning COLERegItem
  75. // pointers for each item found.
  76. //-----------------------------------------------------------------------------
  77. class COLEItemCollection
  78. {
  79. public:
  80. COLEItemCollection();
  81. ~COLEItemCollection();
  82. BOOL GetInstance(DWORD dwIndex, COLERegItem ** ppoleitem);
  83. private:
  84. BOOL UpdateFromRegistry();
  85. BOOL UpdateFromINIFile();
  86. BOOL AddOLERegItem(LPCSTR szCategory, LPCSTR szDescription, LPCSTR szObject, LPCSTR szProgramFile);
  87. COLERegItem * m_pItemList;
  88. COLERegItem * m_pLastQueriedItem;
  89. DWORD m_dwLastQueriedIndex;
  90. };
  91. //-----------------------------------------------------------------------------
  92. // Build the internal list of OLE registration items. This is done by looking
  93. // in the registry and in the INI file. Also set the m_pLastQueriedItem pointer
  94. // to the first item in the list (this cached pointer is used to improve
  95. // indexed lookup speed for iterated indices).
  96. //
  97. // The destructor just deletes the list.
  98. //-----------------------------------------------------------------------------
  99. COLEItemCollection::COLEItemCollection() : m_pItemList(NULL), m_dwLastQueriedIndex(0)
  100. {
  101. TraceFunctEnter("COLEItemCollection::COLEItemCollection");
  102. // If UpdateFromRegistry fails, it would be because there isn't enough memory
  103. // to create more list items, so don't bother calling UpdateFromINIFile.
  104. if (UpdateFromRegistry())
  105. UpdateFromINIFile();
  106. m_pLastQueriedItem = m_pItemList;
  107. TraceFunctLeave();
  108. }
  109. COLEItemCollection::~COLEItemCollection()
  110. {
  111. TraceFunctEnter("COLEItemCollection::~COLEItemCollection");
  112. while (m_pItemList)
  113. {
  114. COLERegItem * pNext = m_pItemList->m_pNext;
  115. delete m_pItemList;
  116. m_pItemList = pNext;
  117. }
  118. TraceFunctLeave();
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Get the instance of COLERegItem referenced by the index. This is stored
  122. // internally as a linked list, but we'll cache a pointer for the last
  123. // referenced dwIndex to improve performance if the dwIndex is iterated
  124. // sequentially. Return TRUE and set ppoleitem to point to the instance if
  125. // it exists, otherwise return FALSE.
  126. //-----------------------------------------------------------------------------
  127. BOOL COLEItemCollection::GetInstance(DWORD dwIndex, COLERegItem ** ppoleitem)
  128. {
  129. TraceFunctEnter("COLEItemCollection::GetInstance");
  130. // If the call is for an index less than the last queried index (which
  131. // should be rare), we need to scan from the start of the list.
  132. if (dwIndex < m_dwLastQueriedIndex)
  133. {
  134. m_dwLastQueriedIndex = 0;
  135. m_pLastQueriedItem = m_pItemList;
  136. }
  137. // Scan through the list by (dwIndex - m_dwLastQueriedIndex) items.
  138. while (dwIndex > m_dwLastQueriedIndex && m_pLastQueriedItem)
  139. {
  140. m_pLastQueriedItem = m_pLastQueriedItem->m_pNext;
  141. m_dwLastQueriedIndex += 1;
  142. }
  143. BOOL fResult = FALSE;
  144. if (m_pLastQueriedItem)
  145. {
  146. *ppoleitem = m_pLastQueriedItem;
  147. fResult = TRUE;
  148. }
  149. TraceFunctLeave();
  150. return fResult;
  151. }
  152. //-----------------------------------------------------------------------------
  153. // Insert a new item in the COLERegItem linked list.
  154. //-----------------------------------------------------------------------------
  155. BOOL COLEItemCollection::AddOLERegItem(LPCSTR szCategory, LPCSTR szDescription, LPCSTR szObject, LPCSTR szProgramFile)
  156. {
  157. TraceFunctEnter("COLEItemCollection::AddOLERegItem");
  158. BOOL fReturn = FALSE;
  159. COLERegItem * pNewNode = new COLERegItem;
  160. if (pNewNode)
  161. {
  162. _tcsncpy(pNewNode->m_szCategory, szCategory, CATEGORY_LEN);
  163. _tcsncpy(pNewNode->m_szDescription, szDescription, DESCRIPTION_LEN);
  164. _tcsncpy(pNewNode->m_szObject, szObject, OBJECT_LEN);
  165. _tcsncpy(pNewNode->m_szProgramFile, szProgramFile, PROGRAM_LEN);
  166. pNewNode->m_pNext = m_pItemList;
  167. m_pItemList = pNewNode;
  168. fReturn = TRUE;
  169. }
  170. else
  171. {
  172. ErrorTrace(TRACE_ID, "COLEItemCollection::AddOLERegItem out of memory.");
  173. throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
  174. }
  175. TraceFunctLeave();
  176. return fReturn;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // This method retrieves OLE object information from the registry and adds
  180. // it to the list of objects. Note - this code is essentially lifted from the
  181. // source code for the OLE Registration OCX in MSInfo 4.10.
  182. //
  183. // Changes were made to remove MFC dependencies.
  184. //-----------------------------------------------------------------------------
  185. BOOL COLEItemCollection::UpdateFromRegistry()
  186. {
  187. TraceFunctEnter("COLEItemCollection::UpdateFromRegistry");
  188. BOOL fReturn = TRUE;
  189. // Fill in the information for the array of items. We do this by
  190. // looking in the registry under the HKEY_CLASSES_ROOT key and
  191. // enumerating all of the subkeys there.
  192. TCHAR szCLSID[MAX_PATH];
  193. TCHAR szObjectKey[OBJECT_LEN];
  194. TCHAR szServer[PROGRAM_LEN];
  195. TCHAR szTemp[MAX_PATH];
  196. TCHAR szDescription[DESCRIPTION_LEN];
  197. DWORD dwSize, dwType;
  198. FILETIME filetime;
  199. HKEY hkeyObject, hkeyServer, hkeyTest, hkeyCLSID, hkeySearch;
  200. BOOL bInsertInList;
  201. for (DWORD dwIndex = 0; TRUE; dwIndex++)
  202. {
  203. dwSize = OBJECT_LEN;
  204. if (RegEnumKeyEx(HKEY_CLASSES_ROOT, dwIndex, szObjectKey, &dwSize, NULL, NULL, NULL, &filetime) != ERROR_SUCCESS)
  205. break;
  206. // Open the key for this object (we'll be using it a lot).
  207. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szObjectKey, 0, KEY_READ, &hkeyObject))
  208. continue;
  209. // Now we need to figure out if this subkey refers to an OLE object which
  210. // we want to put into the list. Our first test is to see if there is
  211. // a "NotInsertable" key under it. If there is, we skip this object.
  212. if (ERROR_SUCCESS == RegOpenKeyEx(hkeyObject, _T("NotInsertable"), 0, KEY_READ, &hkeyTest))
  213. {
  214. RegCloseKey(hkeyTest);
  215. continue;
  216. }
  217. // The next test is to look for a CLSID. If there isn't one, then we
  218. // will skip this object.
  219. if (ERROR_SUCCESS != RegOpenKeyEx(hkeyObject, _T("CLSID"), 0, KEY_READ, &hkeyCLSID))
  220. {
  221. RegCloseKey(hkeyObject);
  222. continue;
  223. }
  224. dwSize = MAX_PATH * sizeof(TCHAR);
  225. if (ERROR_SUCCESS != RegQueryValueEx(hkeyCLSID, _T(""), NULL, &dwType, (LPBYTE) szCLSID, &dwSize))
  226. {
  227. RegCloseKey(hkeyObject);
  228. RegCloseKey(hkeyCLSID);
  229. continue;
  230. }
  231. RegCloseKey(hkeyCLSID);
  232. // The next check is for a subkey called "protocol\StdFileEditing\server".
  233. // If it is present, then this object should be inserted into the list.
  234. bInsertInList = FALSE;
  235. strcpy(szTemp, szObjectKey);
  236. strcat(szTemp, "\\protocol\\StdFileEditing\\server");
  237. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkeyServer) == ERROR_SUCCESS)
  238. {
  239. // Get the name of the server.
  240. dwSize = MAX_PATH * sizeof(TCHAR);
  241. if (RegQueryValueEx(hkeyServer, "", NULL, &dwType, (LPBYTE) szServer, &dwSize) != ERROR_SUCCESS || szServer[0] == '\0')
  242. {
  243. RegCloseKey(hkeyObject);
  244. RegCloseKey(hkeyServer);
  245. continue;
  246. }
  247. bInsertInList = TRUE;
  248. RegCloseKey(hkeyServer);
  249. }
  250. // There's still another chance for this little fella to make it into the
  251. // list. If the object is insertable (i.e. it has an "Insertable" key) and
  252. // it a server can be found under HKEY_CLASSES_ROOT\CLSID\<clsid> key, then
  253. // it makes it into the list.
  254. if (!bInsertInList)
  255. {
  256. // First, make sure the object is insertable.
  257. if (RegOpenKeyEx(hkeyObject, "Insertable", 0, KEY_READ, &hkeyTest) == ERROR_SUCCESS)
  258. {
  259. // There are four places to look for a server. We'll check for 32-bit
  260. // servers first. When we've found one, use that server name and
  261. // stop the search.
  262. TCHAR * aszServerKeys[] = { _T("LocalServer32"), _T("InProcServer32"), _T("LocalServer"), _T("InProcServer"), _T("")};
  263. for (int iServer = 0; *aszServerKeys[iServer] && !bInsertInList; iServer++)
  264. {
  265. _tcscpy(szTemp, _T("CLSID\\"));
  266. _tcscat(szTemp, szCLSID);
  267. _tcscat(szTemp, _T("\\"));
  268. _tcscat(szTemp, aszServerKeys[iServer]);
  269. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkeySearch) == ERROR_SUCCESS)
  270. {
  271. dwSize = PROGRAM_LEN * sizeof(TCHAR);
  272. if (RegQueryValueEx(hkeySearch, _T(""), NULL, &dwType, (LPBYTE) szServer, &dwSize) == ERROR_SUCCESS && szServer[0] != '\0')
  273. bInsertInList = TRUE;
  274. RegCloseKey(hkeySearch);
  275. }
  276. }
  277. }
  278. RegCloseKey(hkeyTest);
  279. }
  280. if (bInsertInList)
  281. {
  282. // Get the description of the object. This can be found under the
  283. // objects key as the default value.
  284. dwSize = DESCRIPTION_LEN * sizeof(TCHAR);
  285. if (ERROR_SUCCESS != RegQueryValueEx(hkeyObject, "", NULL, &dwType, (LPBYTE) szDescription, &dwSize))
  286. szDescription[0] = _T('\0');
  287. // Create a new OLE registration item entry. This might throw a memory exception,
  288. // so close the hkeyObject handle first.
  289. RegCloseKey(hkeyObject);
  290. if (!AddOLERegItem(_T("REGISTRY"), szDescription, szObjectKey, szServer))
  291. {
  292. fReturn = FALSE;
  293. goto END;
  294. }
  295. }
  296. else
  297. RegCloseKey(hkeyObject);
  298. }
  299. END:
  300. TraceFunctLeave();
  301. return fReturn;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // This method retrieves OLE object information from the INI file(s) and adds
  305. // it to the list of objects. Note - this code is essentially lifted from the
  306. // source code for the OLE Registration OCX in MSInfo 4.10.
  307. //
  308. // Changes were made to remove MFC dependencies.
  309. //-----------------------------------------------------------------------------
  310. BOOL COLEItemCollection::UpdateFromINIFile()
  311. {
  312. TraceFunctEnter("COLEItemCollection::UpdateFromINIFile");
  313. TCHAR szProgram[PROGRAM_LEN];
  314. TCHAR szDescription[DESCRIPTION_LEN];
  315. LPTSTR szBuffer;
  316. LPTSTR szEntry;
  317. LPTSTR szScan;
  318. TCHAR szData[MAX_PATH * 2];
  319. BOOL fReturn = TRUE;
  320. int i;
  321. szBuffer = new TCHAR[2048];
  322. if (szBuffer == NULL)
  323. throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
  324. if (GetProfileString(_T("embedding"), NULL, _T("\0\0"), szBuffer, 2048) <= 2)
  325. {
  326. fReturn = FALSE;
  327. goto END;
  328. }
  329. szEntry = szBuffer;
  330. while (*szEntry != 0)
  331. {
  332. if (GetProfileString(_T("embedding"), szEntry, _T("\0\0"), szData, MAX_PATH * 2) > 1)
  333. {
  334. // Parse out the components of the string we retrieved. The string
  335. // should be formed as "primary desc, registry desc, program, format".
  336. szScan = szData;
  337. i = _tcscspn(szScan, _T(","));
  338. _tcsncpy(szDescription, szScan, (i < DESCRIPTION_LEN - 1) ? i : DESCRIPTION_LEN - 1);
  339. szDescription[(i < DESCRIPTION_LEN - 1) ? i : DESCRIPTION_LEN - 1] = _T('\0');
  340. szScan += i + 1;
  341. szScan += _tcscspn(szScan, _T(",")) + 1; // skip registry
  342. i = _tcscspn(szScan, _T(","));
  343. _tcsncpy(szProgram, szScan, (i < PROGRAM_LEN - 1) ? i : PROGRAM_LEN - 1);
  344. szProgram[(i < PROGRAM_LEN - 1) ? i : PROGRAM_LEN - 1] = _T('\0');
  345. szScan += i + 1;
  346. // Create a new OLE registration item entry. This might throw an exception.
  347. try
  348. {
  349. if (!AddOLERegItem(_T("INIFILE"), szDescription, szEntry, szProgram))
  350. {
  351. fReturn = FALSE;
  352. goto END;
  353. }
  354. }
  355. catch (...)
  356. {
  357. if (szBuffer)
  358. delete [] szBuffer;
  359. throw;
  360. }
  361. }
  362. szEntry += lstrlen(szEntry) + 1;
  363. }
  364. END:
  365. if (szBuffer)
  366. delete [] szBuffer;
  367. TraceFunctLeave();
  368. return fReturn;
  369. }
  370. /*****************************************************************************
  371. *
  372. * FUNCTION : CPCH_OLERegistration::EnumerateInstances
  373. *
  374. * DESCRIPTION : Returns all the instances of this class.
  375. *
  376. * INPUTS : A pointer to the MethodContext for communication with WinMgmt.
  377. * A long that contains the flags described in
  378. * IWbemServices::CreateInstanceEnumAsync. Note that the following
  379. * flags are handled by (and filtered out by) WinMgmt:
  380. * WBEM_FLAG_DEEP
  381. * WBEM_FLAG_SHALLOW
  382. * WBEM_FLAG_RETURN_IMMEDIATELY
  383. * WBEM_FLAG_FORWARD_ONLY
  384. * WBEM_FLAG_BIDIRECTIONAL
  385. *
  386. * RETURNS : WBEM_S_NO_ERROR if successful
  387. *
  388. * COMMENTS : TO DO: All instances on the machine should be returned here.
  389. * If there are no instances, return WBEM_S_NO_ERROR.
  390. * It is not an error to have no instances.
  391. *
  392. *****************************************************************************/
  393. HRESULT CPCH_OLERegistration::EnumerateInstances(MethodContext * pMethodContext, long lFlags)
  394. {
  395. TraceFunctEnter("CPCH_OLERegistration::EnumerateInstances");
  396. HRESULT hRes = WBEM_S_NO_ERROR;
  397. // Get the date and time
  398. SYSTEMTIME stUTCTime;
  399. GetSystemTime(&stUTCTime);
  400. // The COLEItemCollection class gathers data about the OLE registration objects when it's
  401. // constructed. We can get info for each individual object using it's GetInstance
  402. // pointer, which gives us a pointer to a COLERegItem object.
  403. COLEItemCollection olereginfo;
  404. COLERegItem * poleitem;
  405. for (DWORD dwIndex = 0; olereginfo.GetInstance(dwIndex, &poleitem); dwIndex++)
  406. {
  407. CInstancePtr pInstance(CreateNewInstance(pMethodContext), false);
  408. // Set the change and timestamp fields to "Snapshot" and the current time.
  409. if (!pInstance->SetDateTime(pTimeStamp, WBEMTime(stUTCTime)))
  410. ErrorTrace(TRACE_ID, "SetDateTime on Timestamp field failed.");
  411. if (!pInstance->SetCHString(pChange, L"Snapshot"))
  412. ErrorTrace(TRACE_ID, "SetCHString on Change field failed.");
  413. // Set each of the other fields to the values we found when we retrieved
  414. // the OLE objects from the registry and INI files.
  415. if (!pInstance->SetCHString(pCategory, poleitem->GetCategory()))
  416. ErrorTrace(TRACE_ID, "SetCHString on Category field failed.");
  417. if (!pInstance->SetCHString(pDescription, poleitem->GetDescription()))
  418. ErrorTrace(TRACE_ID, "SetCHString on Description field failed.");
  419. if (!pInstance->SetCHString(pProgramFile, poleitem->GetProgramFile()))
  420. ErrorTrace(TRACE_ID, "SetCHString on ProgramFile field failed.");
  421. if (!pInstance->SetCHString(pObject, poleitem->GetObject()))
  422. ErrorTrace(TRACE_ID, "SetCHString on Object field failed.");
  423. LPCSTR szFile = poleitem->GetProgramFile();
  424. if (szFile && szFile[0])
  425. {
  426. CComPtr<IWbemClassObject> pFileObj;
  427. CComBSTR ccombstrValue(szFile);
  428. if (SUCCEEDED(GetCIMDataFile(ccombstrValue, &pFileObj)))
  429. {
  430. // Using the CIM_DataFile object, copy over the appropriate properties.
  431. CopyProperty(pFileObj, L"Version", pInstance, pVersion);
  432. CopyProperty(pFileObj, L"FileSize", pInstance, pSize);
  433. CopyProperty(pFileObj, L"CreationDate", pInstance, pDate);
  434. }
  435. }
  436. hRes = pInstance->Commit();
  437. if (FAILED(hRes))
  438. ErrorTrace(TRACE_ID, "Commit on Instance failed.");
  439. }
  440. TraceFunctLeave();
  441. return hRes;
  442. }