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.

1419 lines
46 KiB

  1. //***************************************************************************
  2. //
  3. // COPYPASTE.CPP
  4. //
  5. // Module: HEALTHMON SERVER AGENT
  6. //
  7. // Purpose: Copying and pasting code below.
  8. //
  9. // Copyright (c)2000 Microsoft Corporation, All Rights Reserved
  10. //
  11. //***************************************************************************
  12. #pragma warning (disable: 4786) // exceeds 255 chars in browser info
  13. #define _WIN32_DCOM
  14. #include "global.h"
  15. #include "system.h"
  16. #define ASSERT MY_ASSERT
  17. #define TRACE(x) MY_OUTPUT(x, 4)
  18. #include <comdef.h>
  19. #include <wbemcli.h>
  20. #include "SafeArray.h"
  21. #include "StringMap.h"
  22. // smart pointers for common WMI types
  23. _COM_SMARTPTR_TYPEDEF(IWbemLocator, __uuidof(IWbemLocator));
  24. _COM_SMARTPTR_TYPEDEF(IWbemServices, __uuidof(IWbemServices));
  25. _COM_SMARTPTR_TYPEDEF(IWbemClassObject, __uuidof(IWbemClassObject));
  26. _COM_SMARTPTR_TYPEDEF(IWbemQualifierSet, __uuidof(IWbemQualifierSet));
  27. _COM_SMARTPTR_TYPEDEF(IWbemObjectSink, __uuidof(IWbemObjectSink));
  28. _COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, __uuidof(IEnumWbemClassObject));
  29. // a bunch of constant strings. Enables us to change class names without a lot of cut
  30. // and paste
  31. static const _bstr_t bstrLocalHealthMonNamespace(L"\\\\.\\ROOT\\CIMV2\\MicrosoftHealthMonitor");
  32. static const _bstr_t bstrHealthMonNamespace(L"ROOT\\CIMV2\\MicrosoftHealthMonitor");
  33. static const _bstr_t bstrBaseConfigurationPath(L"MicrosoftHM_Configuration");
  34. static const _bstr_t bstrFilterToConsumerBindingClassPath(L"__FilterToConsumerBinding");
  35. static const _bstr_t bstrEventConsumerClassPath(L"__EventConsumer");
  36. static const _bstr_t bstrEventFilterClassPath(L"__EventFilter");
  37. static const _bstr_t bstrActionAssocClassPath(L"MicrosoftHM_ConfigurationActionAssociation");
  38. static const _bstr_t bstrActionConfigurationClassPath(L"MicrosoftHM_ActionConfiguration");
  39. static const _bstr_t bstrTopPath(L"MicrosoftHM_SystemConfiguration.GUID=\"{@}\"");
  40. static const _bstr_t bstrTopGUID(L"{@}");
  41. static const _bstr_t bstrConfigurationAssocClassPath(L"MicrosoftHM_ConfigurationAssociation");
  42. static const _bstr_t bstrThresholdConfigurationClassPath(L"MicrosoftHM_ThresholdConfiguration");
  43. static const _bstr_t bstrDataCollectorConfigurationClassPath(L"MicrosoftHM_DataCollectorConfiguration");
  44. static const _bstr_t bstrDataGroupConfigurationClassPath(L"MicrosoftHM_DataGroupConfiguration");
  45. static const _bstr_t bstrSystemConfigurationClassPath(L"MicrosoftHM_SystemConfiguration");
  46. static const _bstr_t strLanguage(L"WQL");
  47. static const _bstr_t MOFFileHeader1(
  48. L"////////////////////////////////////////////////////////\n"
  49. L"// Automatically generated Health Monitor MOF dump\n"
  50. L"// Parent Root = "
  51. );
  52. static const _bstr_t MOFFileHeader2(
  53. L"\n"
  54. L"////////////////////////////////////////////////////////\n"
  55. L"\n"
  56. L"#pragma autorecover\n"
  57. L"#pragma namespace(\"\\\\\\\\.\\\\ROOT\\\\CIMV2\\\\MicrosoftHealthMonitor\")\n"
  58. L"\n"
  59. L"\n");
  60. // get a BSTR-valued property
  61. static HRESULT GetStringProperty (IWbemClassObject* pObj,
  62. LPCWSTR lpszPropName,
  63. _bstr_t& bstr)
  64. {
  65. _variant_t var;
  66. CHECK_ERROR (pObj->Get(lpszPropName, 0, &var, NULL, NULL));
  67. if (V_VT(&var) != VT_BSTR)
  68. {
  69. CHECK_ERROR (E_INVALIDARG); // bad data type. should never happen
  70. }
  71. CHECK_ERROR (SafeAssign (bstr, var));
  72. return S_OK;
  73. }
  74. static HRESULT GetUint32Property (IWbemClassObject* pObj,
  75. LPCWSTR lpszPropName,
  76. DWORD& val)
  77. {
  78. _variant_t var;
  79. CHECK_ERROR (pObj->Get(lpszPropName, 0, &var, NULL, NULL));
  80. if (V_VT(&var) != VT_I4)
  81. {
  82. CHECK_ERROR (E_INVALIDARG); // bad data type. should never happen
  83. }
  84. val = V_I4(&var);
  85. return S_OK;
  86. }
  87. // get a BSTR-valued property
  88. static HRESULT PutStringProperty (IWbemClassObject* pObj,
  89. LPCWSTR lpszPropName,
  90. const _bstr_t& bstr)
  91. {
  92. _variant_t var;
  93. CHECK_ERROR (SafeAssign (var, bstr));
  94. CHECK_ERROR (pObj->Put(lpszPropName, 0, &var, NULL));
  95. return S_OK;
  96. }
  97. static HRESULT CompareInstances (IWbemClassObject* pObj1, IWbemClassObject* pObj2, bool& bMatch)
  98. {
  99. // compare all the properties of these two instances
  100. if (pObj1 == NULL || pObj2 == NULL)
  101. return WBEM_E_INVALID_PARAMETER;
  102. HRESULT hr = S_OK;
  103. CHECK_ERROR (pObj1->BeginEnumeration (WBEM_FLAG_NONSYSTEM_ONLY));
  104. while (TRUE)
  105. {
  106. // get property.
  107. BSTR bstrVal;
  108. hr = pObj1->Next(0, &bstrVal, NULL, NULL, NULL );
  109. if (hr == WBEM_S_NO_MORE_DATA)
  110. break; // BREAK OUT!!!! We're done.
  111. else if (FAILED (hr))
  112. break;
  113. _bstr_t bstrName(bstrVal, false); // false for attach and auto-free
  114. _variant_t var1, var2;
  115. CIMTYPE eType1, eType2;
  116. if (pObj1->Get(bstrName, 0, &var1, &eType1, NULL))
  117. break;
  118. if (pObj2->Get(bstrName, 0, &var2, &eType2, NULL))
  119. break;
  120. if (eType1 != eType2)
  121. {
  122. bMatch = false; // differnet CIM types
  123. break;
  124. }
  125. else if (var1 != var2)
  126. {
  127. bMatch = false; // differnet values
  128. break;
  129. }
  130. }
  131. if (FAILED (hr))
  132. {
  133. pObj1->EndEnumeration (); // clean up just in case
  134. CHECK_ERROR (hr);
  135. }
  136. CHECK_ERROR (pObj1->EndEnumeration ());
  137. bMatch = true;
  138. return WBEM_S_NO_ERROR;
  139. }
  140. // Same as Clone(), but works across machine boundaries. Clone()
  141. // only works on local instances.
  142. static HRESULT CopyInstance (IWbemServicesPtr& WMI,
  143. IWbemClassObjectPtr& pObj1,
  144. IWbemClassObjectPtr& pObj2)
  145. {
  146. // first, get the class so that we can spawn a new instance
  147. _bstr_t bstrClass;
  148. IWbemClassObjectPtr smartpClass;
  149. CHECK_ERROR (GetStringProperty(pObj1, L"__CLASS", bstrClass));
  150. CHECK_ERROR (WMI->GetObject (bstrClass,
  151. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  152. NULL,
  153. &smartpClass,
  154. NULL));
  155. CHECK_ERROR (smartpClass->SpawnInstance (0, &pObj2));
  156. HRESULT hr = S_OK;
  157. CHECK_ERROR (pObj1->BeginEnumeration (WBEM_FLAG_NONSYSTEM_ONLY));
  158. while (TRUE)
  159. {
  160. // get property name
  161. BSTR bstrVal;
  162. hr = pObj1->Next(0, &bstrVal, NULL, NULL, NULL );
  163. if (hr == WBEM_S_NO_MORE_DATA)
  164. break; // BREAK OUT!!!! We're done.
  165. else if (FAILED (hr))
  166. break;
  167. _bstr_t bstrName(bstrVal, false); // false for attach and auto-free
  168. // get the property on one and copy to the other
  169. _variant_t var;
  170. CIMTYPE eType1;
  171. if (FAILED(hr = pObj1->Get(bstrName, 0, &var, &eType1, NULL)))
  172. break;
  173. if (FAILED(hr = pObj2->Put(bstrName, 0, &var, 0)))
  174. break;
  175. }
  176. if (FAILED (hr))
  177. {
  178. pObj1->EndEnumeration (); // clean up just in case
  179. CHECK_ERROR (hr);
  180. }
  181. CHECK_ERROR (pObj1->EndEnumeration ());
  182. return WBEM_S_NO_ERROR;
  183. }
  184. //
  185. // escape a string so that it's OK to put in an object path
  186. //
  187. static HRESULT WmiPathEscape (LPCWSTR pszPath, _bstr_t& ResultPath)
  188. {
  189. // first, allocate a string twice as big. (escaping never exceeds 2x size)
  190. BSTR bstr = ::SysAllocStringLen (NULL, wcslen(pszPath)*2);
  191. if (bstr == NULL)
  192. CHECK_ERROR (E_OUTOFMEMORY);
  193. WCHAR *pDest = bstr;
  194. for (LPCWSTR pSrc = pszPath; *pSrc; pSrc++)
  195. {
  196. if (*pSrc == L'\"' || *pSrc == L'\\')
  197. {
  198. *pDest++ = L'\\';
  199. }
  200. *pDest++ = *pSrc; // unescaped char
  201. }
  202. *pDest++ = 0; // null-terminate
  203. CHECK_ERROR (SafeAssign(ResultPath, bstr));
  204. ::SysFreeString(bstr); // free this now that copy is made
  205. return S_OK;
  206. }
  207. static HRESULT GetAssociationPath (_bstr_t& strAssocPath,
  208. LPCWSTR szAssocClass,
  209. LPCWSTR szInstance1Role,
  210. LPCWSTR szInstance1Path,
  211. LPCWSTR szInstance2Role,
  212. LPCWSTR szInstance2Path)
  213. {
  214. try
  215. {
  216. // first, escape the object paths so that they can be encased in
  217. // other object paths
  218. _bstr_t bstrInstance1Path, bstrInstance2Path;
  219. CHECK_ERROR (WmiPathEscape(szInstance1Path, bstrInstance1Path))
  220. CHECK_ERROR (WmiPathEscape(szInstance2Path, bstrInstance2Path))
  221. // now construct the association path
  222. strAssocPath = szAssocClass;
  223. strAssocPath += L".";
  224. strAssocPath += szInstance1Role;
  225. strAssocPath += L"=\"";
  226. strAssocPath += bstrInstance1Path;
  227. strAssocPath += L"\",";
  228. strAssocPath += szInstance2Role;
  229. strAssocPath += L"=\"";
  230. strAssocPath += bstrInstance2Path;
  231. strAssocPath += L"\"";
  232. }
  233. catch (_com_error e)
  234. {
  235. CHECK_ERROR (e.Error());
  236. }
  237. return S_OK;
  238. }
  239. // OK, it's an action. There are four instances:
  240. // This method saves them all.
  241. // a) The ConfigurationActionAssication, between the HM object and the action
  242. // b) the action configuration itself
  243. // c) The event filter
  244. // d) the event consumer
  245. // e) the filter-to-consumer binding
  246. static HRESULT AddActionOtherInstances (
  247. SafeArrayOneDimWbemClassObject& saInstances,
  248. int& nArrayIndex,
  249. IWbemClassObjectPtr& smartpParent,
  250. IWbemServices* WMI
  251. )
  252. {
  253. IWbemClassObjectPtr smartpFilter, smartpConsumer, smartpFilterToConsumerBinding;
  254. HRESULT hr;
  255. ULONG nRet;
  256. // First, build paths for the filter & consumer
  257. _bstr_t bstrActionGUID, bstrConsumerPath, bstrFilterPath;
  258. CHECK_ERROR(GetStringProperty(smartpParent, L"GUID", bstrActionGUID));
  259. CHECK_ERROR(GetStringProperty(smartpParent, L"EventConsumer", bstrConsumerPath));
  260. try
  261. {
  262. // The Filter
  263. bstrFilterPath = L"__EventFilter.Name=\"";
  264. bstrFilterPath += bstrActionGUID;
  265. bstrFilterPath += "\"";
  266. }
  267. catch (_com_error e)
  268. {
  269. CHECK_ERROR (e.Error()); // out of memory
  270. }
  271. // ok, now that we've got the paths, let's get the objects themselves
  272. CHECK_ERROR (WMI->GetObject (bstrConsumerPath,
  273. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  274. NULL,
  275. &smartpConsumer,
  276. NULL));
  277. CHECK_ERROR (WMI->GetObject (bstrFilterPath,
  278. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  279. NULL,
  280. &smartpFilter,
  281. NULL));
  282. // Now query to get the Filter To Consumer Binding
  283. _bstr_t strQueryFTCB;
  284. try
  285. {
  286. strQueryFTCB = L"REFERENCES OF {";
  287. strQueryFTCB += bstrFilterPath;
  288. strQueryFTCB += "} WHERE ResultClass = ";
  289. strQueryFTCB += bstrFilterToConsumerBindingClassPath;
  290. }
  291. catch (_com_error e)
  292. {
  293. CHECK_ERROR (e.Error()); // out of memory
  294. }
  295. // now get the Filter-to-consumer binding from WMI.
  296. // note that this must return a valid instance or it's an error!
  297. IEnumWbemClassObjectPtr pEnumFTCB;
  298. CHECK_ERROR (WMI->ExecQuery (strLanguage, strQueryFTCB, 0, NULL, &pEnumFTCB));
  299. hr = pEnumFTCB->Next(5000, 1, &smartpFilterToConsumerBinding, &nRet);
  300. if (FAILED(hr))
  301. CHECK_ERROR (hr); // either S_FALSE (none found) or error
  302. if (hr == WBEM_S_TIMEDOUT)
  303. CHECK_ERROR (RPC_E_TIMEOUT); // it timed out. bad!
  304. if (hr != WBEM_S_NO_ERROR)
  305. CHECK_ERROR (E_FAIL); // no associations found. bad!
  306. // now add'em to the array
  307. CHECK_ERROR (saInstances.SafePutElement(nArrayIndex++, smartpConsumer));
  308. CHECK_ERROR (saInstances.SafePutElement(nArrayIndex++, smartpFilter));
  309. CHECK_ERROR (saInstances.SafePutElement(nArrayIndex++, smartpFilterToConsumerBinding));
  310. return S_OK;
  311. }
  312. static HRESULT BuildInstancesArray (
  313. SafeArrayOneDimWbemClassObject& saInstances,
  314. int& nArrayIndex,
  315. IWbemClassObjectPtr& smartpParent,
  316. IWbemServices* WMI,
  317. bool bCopyActionsOnly = false, // only copy the actions; nothing more
  318. bool bFirstTime = true // recursion?
  319. )
  320. {
  321. ULONG nRet;
  322. HRESULT hr;
  323. ASSERT (smartpParent != NULL);
  324. _bstr_t bstrParentPath;
  325. CHECK_ERROR (GetStringProperty (smartpParent, L"__RELPATH", bstrParentPath));
  326. // Next, deal with children. Depending on what kind of
  327. // configuration class this is, we respond differently
  328. _bstr_t bstrClass;
  329. bool bCanHaveChildren = false;
  330. if (bCopyActionsOnly)
  331. {
  332. bCanHaveChildren = true; // get all the actions
  333. }
  334. else
  335. {
  336. CHECK_ERROR (GetStringProperty(smartpParent,L"__CLASS", bstrClass));
  337. // first time through, we need to store the parent object before we
  338. // recurse to find kids
  339. if (bFirstTime)
  340. {
  341. // if it's an action, store the filter, binding, etc.
  342. // note that we need to store these first, as the
  343. // agent needs to have the configuration show up last.
  344. if (!_wcsicmp (bstrClass, bstrActionConfigurationClassPath))
  345. {
  346. CHECK_ERROR (AddActionOtherInstances (saInstances,
  347. nArrayIndex,
  348. smartpParent,
  349. WMI ));
  350. }
  351. // store the top instance
  352. CHECK_ERROR (saInstances.SafePutElement (nArrayIndex++, smartpParent));
  353. }
  354. if (!_wcsicmp (bstrClass, bstrActionConfigurationClassPath) ||
  355. !_wcsicmp (bstrClass, bstrThresholdConfigurationClassPath))
  356. {
  357. // it's a threshold or action. There are never children.
  358. return WBEM_S_NO_ERROR;
  359. }
  360. else
  361. {
  362. // it may have children. below we will recurse to handle children
  363. bCanHaveChildren = true;
  364. }
  365. }
  366. if (bCanHaveChildren)
  367. {
  368. // build the apppropriate queries to fetch the associators for
  369. // this parent object. Note that there is a weird syntax for the
  370. // ASSOCIATORS OF and REFERENCES OF queries which combines query
  371. // clauses without using AND. See the WMI SDK descripion of
  372. // REFERENCES OF for more details.
  373. _bstr_t bstrQueryChildren;
  374. try
  375. {
  376. // all the actions
  377. if (bCopyActionsOnly)
  378. {
  379. bstrQueryChildren = "SELECT * FROM ";
  380. bstrQueryChildren += bstrActionConfigurationClassPath;
  381. }
  382. else
  383. {
  384. // all the associations referencing us
  385. bstrQueryChildren = L"REFERENCES OF {";
  386. bstrQueryChildren += bstrParentPath;
  387. bstrQueryChildren += "} WHERE ResultClass = ";
  388. bstrQueryChildren += bstrConfigurationAssocClassPath;
  389. bstrQueryChildren += " Role = ParentPath";
  390. }
  391. }
  392. catch (_com_error e)
  393. {
  394. CHECK_ERROR (e.Error()); // out of memory
  395. }
  396. IEnumWbemClassObjectPtr pEnum;
  397. if (FAILED (hr = WMI->ExecQuery (strLanguage, bstrQueryChildren, 0, NULL, &pEnum)))
  398. {
  399. // TRACE (L"%s\n", (LPCTSTR) bstrQueryChildren);
  400. if (hr != WBEM_E_NOT_FOUND) // notfound is OK-- there may be no children. We're done.
  401. {
  402. CHECK_ERROR (hr);
  403. }
  404. }
  405. else // everything is OK. now enumerate
  406. {
  407. _bstr_t bstrParentPath, bstrChildPath;
  408. IWbemClassObjectPtr smartpAssocInstance, smartpInstance;
  409. for ( hr = pEnum->Next(5000, 1, &smartpAssocInstance, &nRet);
  410. SUCCEEDED(hr) && hr == WBEM_S_NO_ERROR;
  411. hr = pEnum->Next(5000, 1, &smartpAssocInstance, &nRet))
  412. {
  413. // if we are just getting the actions,
  414. if (bCopyActionsOnly)
  415. {
  416. // if it's an action, store the filter, binding, etc.
  417. // note that we need to store these first, as the
  418. // agent needs to have the configuration show up last.
  419. CHECK_ERROR (AddActionOtherInstances (saInstances,
  420. nArrayIndex,
  421. smartpAssocInstance,
  422. WMI ));
  423. // store the instance.
  424. CHECK_ERROR (saInstances.SafePutElement (nArrayIndex++, smartpAssocInstance));
  425. }
  426. else
  427. { // not only the actions
  428. _variant_t var;
  429. // now get the configuration instance that this association
  430. // instance actually points to
  431. CHECK_ERROR (GetStringProperty(smartpAssocInstance,
  432. L"ChildPath",
  433. bstrChildPath));
  434. CHECK_ERROR (WMI->GetObject (bstrChildPath,
  435. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  436. NULL,
  437. &smartpInstance,
  438. NULL));
  439. // If it's an action, store the other subinstances as well
  440. // note that we need to store the subinstances first, as the
  441. // agent needs to have the configuration show up last.
  442. CHECK_ERROR (GetStringProperty(smartpInstance,L"__CLASS", bstrClass));
  443. if (!_wcsicmp (bstrClass, bstrActionConfigurationClassPath))
  444. {
  445. CHECK_ERROR (AddActionOtherInstances (saInstances,
  446. nArrayIndex,
  447. smartpInstance,
  448. WMI ));
  449. }
  450. // store the instance.
  451. CHECK_ERROR (saInstances.SafePutElement (nArrayIndex++, smartpInstance));
  452. // now put the association in the array
  453. CHECK_ERROR (saInstances.SafePutElement(nArrayIndex++, smartpAssocInstance));
  454. // now recurse to deal with *this* object's children
  455. // note that actions and thresholds have no kids
  456. if (_wcsicmp (bstrClass, bstrActionConfigurationClassPath) != 0 &&
  457. _wcsicmp (bstrClass, bstrThresholdConfigurationClassPath) != 0)
  458. {
  459. CHECK_ERROR (BuildInstancesArray (saInstances,
  460. nArrayIndex,
  461. smartpInstance,
  462. WMI,
  463. false // recursion!
  464. ));
  465. }
  466. }
  467. }
  468. if (hr == WBEM_S_TIMEDOUT)
  469. CHECK_ERROR (RPC_E_TIMEOUT); // it timed out. bad!
  470. CHECK_ERROR (hr);
  471. }
  472. }
  473. return WBEM_S_NO_ERROR;
  474. }
  475. enum EGuidType {GUID_PLAIN, GUID_PATH, GUID_QUERY};
  476. static HRESULT ReGuidOneProperty (IWbemClassObjectPtr& pObj,
  477. LPCWSTR wszPropName,
  478. StringToStringMap& GuidMap,
  479. EGuidType eType)
  480. {
  481. // get the current value of the property from WMI
  482. _variant_t var;
  483. CIMTYPE CimType;
  484. CHECK_ERROR (pObj->Get(wszPropName, 0, &var, &CimType, NULL));
  485. if (var.vt != VT_BSTR)
  486. {
  487. ASSERT (FALSE);
  488. return E_FAIL; // bad type of prop!
  489. }
  490. // OK, now pull out the BSTR and remove it from the variant
  491. _bstr_t bstrCurrentPropValue(var.bstrVal, false);
  492. var.Detach();
  493. // now locate the GUID in the string
  494. LPCWSTR pGuidStr;
  495. WCHAR szGUID[39]; // enough space to fit a GUID in Unicode
  496. switch (eType)
  497. {
  498. case GUID_PLAIN:
  499. pGuidStr = bstrCurrentPropValue;
  500. ASSERT (CimType == CIM_STRING);
  501. break;
  502. case GUID_PATH:
  503. pGuidStr = wcschr ((LPWSTR)bstrCurrentPropValue, L'{');
  504. ASSERT (CimType == CIM_REFERENCE);
  505. break;
  506. case GUID_QUERY:
  507. pGuidStr = wcschr ((LPWSTR)bstrCurrentPropValue, L'{');
  508. ASSERT (CimType == CIM_STRING);
  509. break;
  510. }
  511. if (pGuidStr == NULL)
  512. {
  513. ASSERT (FALSE);
  514. return E_FAIL; // corrupt WMI value!
  515. }
  516. LPCWSTR pEndBracket = wcschr (pGuidStr, '}');
  517. if (pEndBracket == NULL)
  518. {
  519. ASSERT (FALSE);
  520. return E_FAIL; // corrupt WMI value!
  521. }
  522. else if (pEndBracket - pGuidStr == 2 && pGuidStr[1] == '@')
  523. {
  524. return S_OK; // it's the system configuration instance.
  525. // No need to re-guid.
  526. }
  527. else if (pEndBracket - pGuidStr != 37 )
  528. {
  529. ASSERT (FALSE);
  530. return E_FAIL; // corrupt WMI value!
  531. }
  532. ASSERT (pGuidStr[0] == '{');
  533. ASSERT (pGuidStr[37] == '}');
  534. // now move the string into temp storage
  535. wcsncpy (szGUID, pGuidStr, 38);
  536. szGUID[38] = 0;
  537. // have we seen this one?
  538. _bstr_t bstrGuidNew;
  539. bool bFound;
  540. CHECK_ERROR (GuidMap.Find (szGUID, bstrGuidNew, bFound));
  541. if (bFound)
  542. {
  543. // OK, we found this GUID there already. Use the preset
  544. // replacement GUID
  545. wcsncpy ((LPWSTR) pGuidStr, bstrGuidNew, 38);
  546. }
  547. else
  548. {
  549. // we haven't already seen this. Generate a new GUID, add it
  550. // to the map
  551. CGuidString strNewGuid;
  552. GuidMap.Add (szGUID, strNewGuid);
  553. wcsncpy ((LPWSTR) pGuidStr, strNewGuid, 38);
  554. }
  555. // OK, now we have a BSTR with the new GUID.
  556. CHECK_ERROR (PutStringProperty (pObj, wszPropName, bstrCurrentPropValue));
  557. return S_OK;
  558. }
  559. // walk through the array looking for GUID's. When we find a GUID,
  560. // we will check a mapping table to see if it is already mapped to another
  561. // GUID. If it is, we will replace it and move on through the list. If
  562. // it isn't in the table, we will generate a new GUID, replace the
  563. // one already there, and store the new GUID in the table
  564. static HRESULT ReGuid(SafeArrayOneDimWbemClassObject& saInstances,
  565. StringToStringMap& aGuidMap )
  566. {
  567. HRESULT hr;
  568. for ( int i = 0, nLen = saInstances.GetSize(); i < nLen; i++)
  569. {
  570. IWbemClassObjectPtr pObj;
  571. CHECK_ERROR (saInstances.GetElement(i, &pObj));
  572. ASSERT (pObj != NULL);
  573. // now check the class of this object. Depending on the class type,
  574. _bstr_t bstrClass, bstrPath;
  575. CHECK_ERROR (GetStringProperty (pObj, L"__RELPATH", bstrPath))
  576. CHECK_ERROR (GetStringProperty (pObj, L"__CLASS", bstrClass));
  577. // now re-guid the appropriate properties
  578. if (!_wcsicmp(bstrClass, bstrActionConfigurationClassPath))
  579. {
  580. hr = ReGuidOneProperty (pObj, L"GUID", aGuidMap, GUID_PLAIN);
  581. hr = ReGuidOneProperty (pObj, L"EventConsumer", aGuidMap, GUID_PATH);
  582. }
  583. else if (pObj->InheritsFrom(bstrBaseConfigurationPath)==S_OK)
  584. {
  585. // it's a configuration class, but not action config. Use the GUID property
  586. hr = ReGuidOneProperty (pObj, L"GUID", aGuidMap, GUID_PLAIN);
  587. }
  588. else if (pObj->InheritsFrom(bstrEventConsumerClassPath)==S_OK)
  589. {
  590. hr = ReGuidOneProperty (pObj, L"Name", aGuidMap, GUID_PLAIN);
  591. }
  592. else if (pObj->InheritsFrom(L"__EventFilter")==S_OK)
  593. {
  594. hr = ReGuidOneProperty (pObj, L"Name", aGuidMap, GUID_PLAIN);
  595. hr = ReGuidOneProperty (pObj, L"Query", aGuidMap, GUID_QUERY);
  596. }
  597. else if (!_wcsicmp(bstrClass, bstrFilterToConsumerBindingClassPath))
  598. {
  599. hr = ReGuidOneProperty (pObj, L"Consumer", aGuidMap, GUID_PATH);
  600. hr = ReGuidOneProperty (pObj, L"Filter", aGuidMap, GUID_PATH);
  601. }
  602. else if (!_wcsicmp(bstrClass, bstrActionAssocClassPath))
  603. {
  604. hr = ReGuidOneProperty (pObj, L"ParentPath", aGuidMap, GUID_PATH);
  605. hr = ReGuidOneProperty (pObj, L"ChildPath", aGuidMap, GUID_PATH);
  606. hr = ReGuidOneProperty (pObj, L"EventFilter", aGuidMap, GUID_PATH);
  607. hr = ReGuidOneProperty (pObj, L"Query", aGuidMap, GUID_QUERY);
  608. }
  609. else if (!_wcsicmp(bstrClass, bstrConfigurationAssocClassPath))
  610. {
  611. hr = ReGuidOneProperty (pObj, L"ParentPath", aGuidMap, GUID_PATH);
  612. hr = ReGuidOneProperty (pObj, L"ChildPath", aGuidMap, GUID_PATH);
  613. }
  614. else
  615. {
  616. ASSERT (FALSE); // should never happen. it's an invalid class.
  617. }
  618. CHECK_ERROR (hr);
  619. }
  620. return S_OK;
  621. }
  622. //
  623. // Detect all actions with duplicate names between the clipboard and the target
  624. // Fill up a GUID map with the dupes
  625. //
  626. static HRESULT FillActionGuidMap( SafeArrayOneDimWbemClassObject& saInstances,
  627. StringToStringMap& ActionNameToGuidMap,
  628. StringToStringMap& GuidMap)
  629. {
  630. for ( int i = 0, nLen = saInstances.GetSize(); i < nLen; i++)
  631. {
  632. IWbemClassObjectPtr pObj;
  633. CHECK_ERROR (saInstances.GetElement(i, &pObj));
  634. ASSERT (pObj != NULL);
  635. _bstr_t bstrClass, bstrPath;
  636. CHECK_ERROR (GetStringProperty (pObj, L"__CLASS", bstrClass));
  637. // now re-guid the appropriate properties
  638. if (_wcsicmp(bstrClass, bstrActionConfigurationClassPath) != 0)
  639. continue; // we only care about actions!
  640. _bstr_t bstrGuidCurrentAction, bstrName;
  641. bool bFound = false;
  642. CHECK_ERROR (GetStringProperty(pObj, L"Name", bstrName));
  643. CHECK_ERROR (ActionNameToGuidMap.Find(bstrName, bstrGuidCurrentAction, bFound));
  644. if (bFound)
  645. {
  646. // there's a duplicate! We'll store a mapping of the GUID in
  647. // the clipboard's instance to the duplicate action GUID.
  648. _bstr_t bstrGUID;
  649. CHECK_ERROR (GetStringProperty (pObj, L"GUID", bstrGUID));
  650. CHECK_ERROR (GuidMap.Add(bstrGUID, bstrGuidCurrentAction));
  651. }
  652. }
  653. return S_OK;
  654. }
  655. static HRESULT Copy(LPTSTR szSourceComputer,
  656. LPTSTR szGUID,
  657. bstr_t& bstrParentGUID, // [out]
  658. SafeArrayOneDimWbemClassObject& saInstances,
  659. CSystem& System)
  660. {
  661. // impersonate the caller. Important since we're now calling into
  662. // WMI and need to make sure caller is allowed
  663. CHECK_ERROR(CoImpersonateClient());
  664. _bstr_t bstrNamespace = L"\\\\";
  665. bstrNamespace += szSourceComputer;
  666. bstrNamespace += L"\\";
  667. bstrNamespace += bstrHealthMonNamespace;
  668. IWbemServicesPtr WMI = g_pIWbemServices;
  669. // IWbemLocatorPtr WMILocator;
  670. // IWbemServicesPtr WMI;
  671. // CHECK_ERROR (WMILocator.CreateInstance(__uuidof(WbemLocator),NULL));
  672. // CHECK_ERROR (WMILocator->ConnectServer (bstrNamespace,
  673. // NULL, NULL, NULL, 0, NULL, NULL,
  674. // &WMI));
  675. _bstr_t bstrPath;
  676. try
  677. {
  678. bstrPath = bstrBaseConfigurationPath;
  679. bstrPath += L".GUID=\"";
  680. bstrPath += szGUID;
  681. bstrPath += L"\"";
  682. }
  683. catch (_com_error e)
  684. {
  685. CHECK_ERROR (e.Error()); // out of memory
  686. }
  687. IWbemClassObjectPtr smartpObj;
  688. HRESULT hr = WMI->GetObject (bstrPath,
  689. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  690. NULL,
  691. &smartpObj,
  692. NULL);
  693. if (hr == WBEM_E_NOT_FOUND)
  694. {
  695. return WBEM_E_NOT_FOUND; // it's not there
  696. }
  697. CHECK_ERROR (hr);
  698. // if it's a single action, then we fake the parent to be the system instance
  699. // same if it's the entire system that we're copying
  700. _bstr_t bstrClass;
  701. CHECK_ERROR (GetStringProperty(smartpObj, L"__CLASS", bstrClass));
  702. if (!_wcsicmp (bstrClass, bstrActionConfigurationClassPath)
  703. || !_wcsicmp (bstrClass, bstrSystemConfigurationClassPath))
  704. {
  705. try
  706. {
  707. bstrParentGUID = bstrTopGUID;
  708. }
  709. catch (_com_error e)
  710. {
  711. CHECK_ERROR (e.Error()); // out of memory
  712. }
  713. }
  714. else
  715. {
  716. // build the query to find our parent
  717. _bstr_t bstrParentQuery;
  718. try
  719. {
  720. bstrParentQuery = L"ASSOCIATORS OF {";
  721. bstrParentQuery += bstrPath;
  722. bstrParentQuery += L"} WHERE";
  723. bstrParentQuery += L" ResultRole = ParentPath";
  724. }
  725. catch (_com_error e)
  726. {
  727. CHECK_ERROR (e.Error()); // out of memory
  728. }
  729. // now exec the query to fetch the parent
  730. ULONG nRet;
  731. IEnumWbemClassObjectPtr pEnumParent;
  732. IWbemClassObjectPtr smartpParent;
  733. CHECK_ERROR (WMI->ExecQuery (strLanguage, bstrParentQuery, 0, NULL, &pEnumParent));
  734. hr = pEnumParent->Next(5000, 1, &smartpParent, &nRet);
  735. if (FAILED(hr))
  736. CHECK_ERROR (hr);
  737. if (hr == WBEM_S_TIMEDOUT)
  738. CHECK_ERROR (RPC_E_TIMEOUT); // it timed out. bad!
  739. if (hr != WBEM_S_NO_ERROR)
  740. CHECK_ERROR (E_FAIL); // no parent found. bad!
  741. CHECK_ERROR (GetStringProperty(smartpParent, L"GUID", bstrParentGUID));
  742. }
  743. // now actually go get the array
  744. int nArrayIndex = 0;
  745. CHECK_ERROR (saInstances.Clear());
  746. CHECK_ERROR (saInstances.Create());
  747. // now build an array of all the instances underneath this one
  748. CHECK_ERROR (BuildInstancesArray (saInstances,
  749. nArrayIndex,
  750. smartpObj,
  751. WMI));
  752. // now, if this was the entire system that we were copying, copy the
  753. // unattached actions as well.
  754. if (!_wcsicmp (bstrClass, bstrSystemConfigurationClassPath))
  755. {
  756. // now add all the actions to the array
  757. CHECK_ERROR (BuildInstancesArray (saInstances,
  758. nArrayIndex,
  759. smartpObj,
  760. WMI,
  761. true));
  762. }
  763. CHECK_ERROR (saInstances.Resize(nArrayIndex));
  764. return S_OK;
  765. }
  766. // the input is an array of instances to be added, in order. Add them.
  767. // Note that actions will be compared to actions currently on the box.
  768. static HRESULT Paste(LPCTSTR pszTargetComputer,
  769. LPCTSTR pszTargetParentGUID,
  770. LPCTSTR pszOriginalComputer,
  771. LPCTSTR pszOriginalParentGUID,
  772. SAFEARRAY* psa,
  773. BOOL bForceReplace,
  774. CSystem& System)
  775. {
  776. // impersonate the caller. Important since we're now calling into
  777. // WMI and need to make sure caller is allowed
  778. CHECK_ERROR(CoImpersonateClient());
  779. _bstr_t bstrNamespace = L"\\\\";
  780. bstrNamespace += pszTargetComputer;
  781. bstrNamespace += L"\\";
  782. bstrNamespace += bstrHealthMonNamespace;
  783. TCHAR szComputerName[1024];
  784. DWORD dwSize = 1024;
  785. ::GetComputerName(szComputerName, &dwSize);
  786. if (!_wcsicmp(szComputerName, pszTargetComputer))
  787. pszTargetComputer = L".";
  788. if (!_wcsicmp(szComputerName, pszOriginalComputer))
  789. pszOriginalComputer = L".";
  790. IWbemServicesPtr WMI = g_pIWbemServices;
  791. HRESULT hr;
  792. // Commented-out code below was used when we were not part of the agent.
  793. // IWbemLocatorPtr WMILocator;
  794. // IWbemServicesPtr WMI;
  795. // CHECK_ERROR (WMILocator.CreateInstance(__uuidof(WbemLocator),NULL));
  796. // CHECK_ERROR (WMILocator->ConnectServer (bstrNamespace,
  797. // NULL, NULL, NULL, 0, NULL, NULL,
  798. // &WMI));
  799. // if we didn't create the array, then don't
  800. // bother proceeding
  801. VARIANT varSA;
  802. varSA.vt = VT_ARRAY | VT_UNKNOWN;
  803. varSA.parray = psa;
  804. if (!SafeArrayOneDimWbemClassObject::IsValid(varSA))
  805. CHECK_ERROR (E_INVALIDARG);
  806. // since we know that it's one of ours, and because our SafeArray wrapper
  807. // is the same length as a regular safe array, we can cast it.
  808. SafeArrayOneDimWbemClassObject& saInstancesOriginal = (SafeArrayOneDimWbemClassObject&)varSA;
  809. // if we're pasting in the same parent, then the behavior should
  810. // match Windows, where you add a " (2)" to the name and make a copy
  811. bool bPasteOnSameMachine = !_wcsicmp (pszTargetComputer,pszOriginalComputer);
  812. bool bPasteInSameFolder = bPasteOnSameMachine &&
  813. !_wcsicmp (pszTargetParentGUID, pszOriginalParentGUID);
  814. _bstr_t bstrParentRelPath;
  815. try
  816. {
  817. bstrParentRelPath = bstrBaseConfigurationPath;
  818. bstrParentRelPath += L".GUID=\"";
  819. bstrParentRelPath += pszTargetParentGUID;
  820. bstrParentRelPath += L"\"";
  821. }
  822. catch (_com_error e)
  823. {
  824. CHECK_ERROR (e.Error()); // out of memory
  825. }
  826. // Pasting Algorithm
  827. // ==========================================================
  828. // 1. If child with same name already exists in parent: If bOverwrite = TRUE,
  829. // delete the other guy. If bOverwrite = FALSE, return an error.
  830. // 2. If actions with same name but *different* contents already exists in parent:
  831. // If bOverwrite = TRUE, delete the other actions. If bOverwrite = FALSE,
  832. // return an error.
  833. // 3. If actions with same name and *same* contents already exists in parent,
  834. // reassign the to-be-pasted GUID's to match the target.
  835. // 4. Now simply Put each member of the array.
  836. //===========================================================
  837. // fetch this parent instance
  838. IWbemClassObjectPtr smartpParentInstance;
  839. CHECK_ERROR (WMI->GetObject (bstrParentRelPath,
  840. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  841. NULL,
  842. &smartpParentInstance,
  843. NULL));
  844. // get the full, normalized path
  845. CHECK_ERROR (GetStringProperty(smartpParentInstance, L"__RELPATH", bstrParentRelPath));
  846. // First, get the top instance of the array. This is the parent
  847. IWbemClassObjectPtr smartpTopInstance;
  848. CHECK_ERROR (saInstancesOriginal.GetElement (0, &smartpTopInstance));
  849. int nTopIndex = 0;
  850. // now get the name of that top instance
  851. _bstr_t bstrTopInstanceName, bstrTopInstanceClass;
  852. CHECK_ERROR (GetStringProperty(smartpTopInstance, L"__CLASS", bstrTopInstanceClass));
  853. if (bstrTopInstanceClass == bstrSystemConfigurationClassPath)
  854. {
  855. // we cannot (yet) paste the entire system
  856. CHECK_ERROR (E_INVALIDARG);
  857. }
  858. // now see if we're only copying actions-- which will be the case if an
  859. // action (or the filter, binding, etc.) is first on the list of instances
  860. // coming back from the Copy command.
  861. // BUGBUG: need to do something better than simply looking for the string
  862. // "Consumer" below-- not all event consumers will contain that string!
  863. bool bIsActionTopInstance =
  864. bstrTopInstanceClass == bstrActionConfigurationClassPath
  865. || bstrTopInstanceClass == bstrFilterToConsumerBindingClassPath
  866. || wcsstr ((LPCTSTR) bstrTopInstanceClass, L"Consumer") != NULL
  867. || bstrTopInstanceClass == bstrEventFilterClassPath;
  868. if (bIsActionTopInstance)
  869. {
  870. // we need to find the name of the action. But the action is not on top-- it could
  871. // be any of the top 4 instances (action config, filter, consumer or binding). So go look.
  872. // we've already checked the zeroth, so we can start at 1.
  873. for (int i = 1; i < 4; i++)
  874. {
  875. CHECK_ERROR (saInstancesOriginal.GetElement (i, &smartpTopInstance));
  876. CHECK_ERROR (GetStringProperty(smartpTopInstance, L"__CLASS", bstrTopInstanceClass));
  877. if (bstrTopInstanceClass == bstrActionConfigurationClassPath)
  878. {
  879. // found it! we will get the name
  880. nTopIndex = i;
  881. break;
  882. }
  883. }
  884. if (i == 4)
  885. {
  886. CHECK_ERROR (E_INVALIDARG); // uh-oh. the instance array was corrupted.
  887. }
  888. }
  889. // finally, get the name of the instance
  890. CHECK_ERROR (GetStringProperty(smartpTopInstance, L"Name", bstrTopInstanceName));
  891. // Build a query to look for siblings in the new parent
  892. _bstr_t bstrQueryChildren;
  893. try
  894. {
  895. if (bIsActionTopInstance)
  896. {
  897. // for actions, there is no parent. Just list all actions
  898. bstrQueryChildren = L"SELECT * FROM MicrosoftHM_ActionConfiguration";
  899. }
  900. else
  901. {
  902. // first, make a query for get kids of this parent
  903. bstrQueryChildren = L"ASSOCIATORS OF {";
  904. bstrQueryChildren += bstrParentRelPath;
  905. bstrQueryChildren += L"} WHERE";
  906. bstrQueryChildren += L" ResultRole = ChildPath";
  907. }
  908. }
  909. catch (_com_error e)
  910. {
  911. CHECK_ERROR (e.Error()); // out of memory
  912. }
  913. // now execute this query. Look for siblings with matching (i.e. conflicting) names
  914. StringToStringMap TopLevelNameConflictMap;
  915. _bstr_t bstrConflictGUID;
  916. IEnumWbemClassObjectPtr pEnum;
  917. // TRACE (L"%s\n", (LPCTSTR) bstrQueryChildren);
  918. if (FAILED (hr = WMI->ExecQuery (strLanguage, bstrQueryChildren, 0, NULL, &pEnum)))
  919. {
  920. // TRACE (L"%s\n", (LPCTSTR) bstrQueryChildren);
  921. if (hr != WBEM_E_NOT_FOUND) // notfound is OK-- there may be no children. We're done.
  922. {
  923. CHECK_ERROR (hr);
  924. }
  925. }
  926. else
  927. {
  928. _bstr_t bstrChildName;
  929. IWbemClassObjectPtr smartpInstance;
  930. ULONG nRet;
  931. for ( hr = pEnum->Next(5000, 1, &smartpInstance, &nRet);
  932. SUCCEEDED(hr) && hr == WBEM_S_NO_ERROR;
  933. hr = pEnum->Next(5000, 1, &smartpInstance, &nRet))
  934. {
  935. _bstr_t bstrChildName, bstrChildClass;
  936. CHECK_ERROR (GetStringProperty(smartpInstance, L"Name", bstrChildName));
  937. CHECK_ERROR (GetStringProperty(smartpInstance, L"__CLASS", bstrChildClass));
  938. // if this child is an action, then the only case where we care about
  939. // conflicts is in the top-level. Otherwise, the actions are not really
  940. // "children" (they're just associated via the ConfigActionAssociation class)
  941. // so we can ignore them. But if this is an action as the
  942. // top instance, you bet we want to check for conflicts!
  943. if (!bIsActionTopInstance && (bstrChildClass == bstrActionConfigurationClassPath))
  944. continue;
  945. // store this for later, in case we have to rename the top item.
  946. if (bPasteInSameFolder)
  947. CHECK_ERROR(TopLevelNameConflictMap.Add(bstrChildName, L"NotUsed"));
  948. // check for conflict
  949. if (!_wcsicmp (bstrChildName, bstrTopInstanceName))
  950. {
  951. CHECK_ERROR (GetStringProperty(smartpInstance, L"GUID", bstrConflictGUID));
  952. if (!bPasteInSameFolder)
  953. {
  954. // uh, oh. We have a name conflict. Depending on whether the
  955. // user wants to perform any overwrites, we will either have to
  956. // delete the conflicting one or return an error.
  957. if (bForceReplace)
  958. {
  959. TRACE(L"Paste: Instance Name Conflict. We will delete the conflicting one");
  960. break;
  961. }
  962. else
  963. {
  964. TRACE(L"Paste: Instance Name Conflict. Returning an error.");
  965. return WBEM_E_ALREADY_EXISTS;
  966. }
  967. }
  968. }
  969. }
  970. if (hr == WBEM_S_TIMEDOUT)
  971. CHECK_ERROR (RPC_E_TIMEOUT); // it timed out. bad!
  972. CHECK_ERROR (hr);
  973. }
  974. // OK, Now build a map of the names of actions already on the target
  975. // and their GUID's
  976. try
  977. {
  978. bstrQueryChildren = L"SELECT * FROM ";
  979. bstrQueryChildren += bstrActionConfigurationClassPath;
  980. }
  981. catch (_com_error e)
  982. {
  983. CHECK_ERROR (e.Error()); // out of memory
  984. }
  985. // we will store a hashtable of mapping action names to their
  986. // GUID's. This will help us in re-GUIDing and in identifying conflicts.
  987. StringToStringMap ActionNameToGuidMap;
  988. // now execute this query
  989. if (FAILED (hr = WMI->ExecQuery (strLanguage, bstrQueryChildren, 0, NULL, &pEnum)))
  990. {
  991. // TRACE (L"%s\n", (LPCTSTR) bstrQueryChildren);
  992. if (hr != WBEM_E_NOT_FOUND) // notfound is OK-- there may be no children. We're done.
  993. {
  994. CHECK_ERROR (hr);
  995. }
  996. }
  997. else
  998. {
  999. _bstr_t bstrChildName;
  1000. IWbemClassObjectPtr smartpInstance;
  1001. ULONG nRet;
  1002. for ( hr = pEnum->Next(5000, 1, &smartpInstance, &nRet);
  1003. SUCCEEDED(hr) && hr == WBEM_S_NO_ERROR;
  1004. hr = pEnum->Next(5000, 1, &smartpInstance, &nRet))
  1005. {
  1006. _bstr_t bstrActionName, bstrActionGUID;
  1007. CHECK_ERROR (GetStringProperty(smartpInstance, L"Name", bstrActionName));
  1008. CHECK_ERROR (GetStringProperty(smartpInstance, L"GUID", bstrActionGUID));
  1009. CHECK_ERROR (ActionNameToGuidMap.Add(bstrActionName, bstrActionGUID));
  1010. }
  1011. }
  1012. // OK, now we will make a copy of the array.
  1013. bool bAlreadyFound = false;
  1014. SafeArrayOneDimWbemClassObject saInstancesNew;
  1015. CHECK_ERROR (saInstancesNew.Create());
  1016. for (int i = 0, nLen = saInstancesOriginal.GetSize(); i < nLen; i++)
  1017. {
  1018. IWbemClassObjectPtr smartpInstance;
  1019. CHECK_ERROR (saInstancesOriginal.GetElement (i, &smartpInstance));
  1020. // make a copy & store it. Note that it's a no-no to take instances
  1021. // from one machine and PutInstance them on another machine-- they will
  1022. // fail intermittently. So we in turn do a "manual clone" here to
  1023. // spawn the instance locally and copy the properties one by one
  1024. // On the same machine, it's faster and more efficient to use Clone(),
  1025. // so we do.
  1026. IWbemClassObjectPtr smartpNewInstance;
  1027. if (bPasteOnSameMachine)
  1028. {
  1029. CHECK_ERROR (smartpInstance->Clone(&smartpNewInstance));
  1030. }
  1031. else
  1032. {
  1033. CHECK_ERROR (CopyInstance (WMI, smartpInstance, smartpNewInstance));
  1034. }
  1035. CHECK_ERROR (saInstancesNew.SafePutElement(i, smartpNewInstance));
  1036. // reassign, considering that we're re-GUIDing it
  1037. if (i == nTopIndex)
  1038. smartpTopInstance = smartpNewInstance;
  1039. /*
  1040. if (!bAlreadyFound)
  1041. {
  1042. // get name, GUID, and class
  1043. _bstr_t bstrClass;
  1044. CHECK_ERROR (GetStringProperty(smartpNewInstance, "__CLASS", &bstrClass);
  1045. // if it's action-related, see if it's already there
  1046. if (!_wcsicmp(bstrFilterToConsumerBindingClassPath, bstrClass)
  1047. || !_wcsicmp(bstrEventConsumerClassPath, bstrClass)
  1048. || !_wcsicmp(bstrActionAssocClassPath, bstrClass)
  1049. || !_wcsicmp(bstrActionConfigurationClassPath, bstrClass) )
  1050. {
  1051. CHECK_ERROR (GetStringProperty(smartpNewInstance, "Name", &bstrActionName);
  1052. _bstr_t bstrGuidNew, bstrName;
  1053. bool bFound;
  1054. CHECK_ERROR (GetStringProperty(pObj, L"Name", bstrName));
  1055. CHECK_ERROR (GuidMap.Find(bstrName, bstrGuidNew, bFound));
  1056. if (bFound)
  1057. {
  1058. }
  1059. }
  1060. */
  1061. }
  1062. // trim the new array
  1063. CHECK_ERROR (saInstancesNew.Resize(nLen));
  1064. // now find all the actions we're associated to, compare their names
  1065. // to actions on the target machine, and fill up a hashtable map
  1066. // with the list of conflicts. Note that if this is just one action that
  1067. // we're copying locally, there's no need to look for conflicts because
  1068. // we're renaming the action anyway.
  1069. StringToStringMap GuidMap;
  1070. if (! (bIsActionTopInstance && bPasteInSameFolder) )
  1071. {
  1072. CHECK_ERROR (FillActionGuidMap(saInstancesNew, ActionNameToGuidMap, GuidMap));
  1073. int nDuplicateCount = GuidMap.GetSize();
  1074. if (nDuplicateCount > 0 && !bPasteOnSameMachine)
  1075. {
  1076. // uh, oh. We have a name conflict. Depending on whether the
  1077. // user wants to perform any overwrites, we will either have to
  1078. // delete the conflicting one or return an error.
  1079. if (bForceReplace)
  1080. {
  1081. TRACE(L"Paste: Action Name Conflict. We will delete the conflicting one");
  1082. }
  1083. else
  1084. {
  1085. TRACE(L"Paste: Action Name Conflict. Returning an error.");
  1086. return WBEM_E_ALREADY_EXISTS;
  1087. }
  1088. }
  1089. }
  1090. // Now, let's change all the GUID's (except for the actions
  1091. // that we'll be replacing, as above).
  1092. CHECK_ERROR (ReGuid (saInstancesNew, GuidMap));
  1093. // Now, let's see if I need to rename the top-level item to
  1094. // resolve name conflicts
  1095. if ((LPCWSTR)bstrConflictGUID != NULL)
  1096. {
  1097. if (bPasteInSameFolder)
  1098. {
  1099. // if we get here, we're renaming our top item to avoid
  1100. // a name conflict, just like Explorer does
  1101. i = 2;
  1102. bool bFound = true;
  1103. _bstr_t bstrName;
  1104. do
  1105. {
  1106. // compose a name, like Foo (2), Foo (3), etc. like explorer does
  1107. WCHAR szNumber[20];
  1108. bstrName = bstrTopInstanceName;
  1109. bstrName += L" (";
  1110. bstrName += _itow (i++, szNumber, 10);
  1111. bstrName += L")";
  1112. _bstr_t NotUsed;
  1113. CHECK_ERROR (TopLevelNameConflictMap.Find(bstrName, NotUsed, bFound));
  1114. } while (bFound);
  1115. // when we get to here, we've found a free name
  1116. CHECK_ERROR (PutStringProperty(smartpTopInstance, L"Name", bstrName));
  1117. }
  1118. else if (! bIsActionTopInstance)
  1119. {
  1120. // we're almost there. Now we need to delete the top-level item on the
  1121. // target, if present, to make room for us. Use the delete method.
  1122. // note that we *do not* go through this codepath for actions, because
  1123. // for actions we will just lay down a new action, with the same GUID,
  1124. // right over the old one. If we actually did call delete (via the agent)
  1125. // the agent would clobber all the action assocations, whereas we want to
  1126. // keep them there and have the new action just fall right into place
  1127. IWbemClassObjectPtr smartpSystemClass, smartpInParamsClass,
  1128. smartpInParamsInstance, smartpResults;
  1129. // impersonate the caller. Important since we're now calling into
  1130. // WMI and need to make sure caller is allowed
  1131. CHECK_ERROR(CoImpersonateClient());
  1132. // BUGBUG: For next release, we need to think about how to provide
  1133. // safer functionality here, so that we don't actually delete the
  1134. // target until we've successfully added the new stuff
  1135. // until then, just delete the conflict
  1136. CHECK_ERROR(System.FindAndDeleteByGUID(bstrConflictGUID));
  1137. /*
  1138. // now that this code lives inside the agent, there's no need to call
  1139. // an external method on the agent. It's much easier-- just call
  1140. // the FindAndDeleteByGUID function on the system class!
  1141. // get the system class
  1142. CHECK_ERROR (WMI->GetObject (bstrSystemConfigurationClassPath,
  1143. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  1144. NULL,
  1145. &smartpSystemClass,
  1146. NULL));
  1147. // get the delete method in-params "class"
  1148. CHECK_ERROR (smartpSystemClass->GetMethod (L"Delete", 0, &smartpInParamsClass, NULL));
  1149. CHECK_ERROR (smartpInParamsClass->SpawnInstance (0, &smartpInParamsInstance));
  1150. CHECK_ERROR (PutStringProperty(smartpInParamsInstance, L"TargetGUID", bstrTopInstanceGUID));
  1151. CHECK_ERROR (WMI->ExecMethod(bstrSystemConfigurationClassPath,
  1152. L"Delete",
  1153. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  1154. NULL,
  1155. smartpInParamsInstance,
  1156. &smartpResults,
  1157. NULL));
  1158. DWORD dwReturnValue;
  1159. CHECK_ERROR (GetUint32Property (smartpResults, L"ReturnValue", dwReturnValue));
  1160. CHECK_ERROR (dwReturnValue);
  1161. */
  1162. }
  1163. }
  1164. // Now we need to compute the association to link the new instances up to the
  1165. // parent instance. This should get the agent to pick up the change and set
  1166. // all the balls in motion. Note that actions don't require parent associations--
  1167. // actions are just global instances available everywhere.
  1168. IWbemClassObjectPtr smartpAssocInstance;
  1169. if (! bIsActionTopInstance)
  1170. {
  1171. IWbemClassObjectPtr smartpAssocClass;
  1172. _bstr_t bstrParentPath, bstrTopInstancePath, bstrTopInstanceRelPath;
  1173. CHECK_ERROR (GetStringProperty(smartpTopInstance, L"__RELPATH", bstrTopInstanceRelPath));
  1174. try
  1175. {
  1176. bstrParentPath = bstrLocalHealthMonNamespace
  1177. + L":"
  1178. + bstrParentRelPath;
  1179. bstrTopInstancePath = bstrLocalHealthMonNamespace
  1180. + L":"
  1181. + bstrTopInstanceRelPath;
  1182. }
  1183. catch (_com_error e)
  1184. {
  1185. CHECK_ERROR (e.Error());
  1186. }
  1187. // now create the association
  1188. CHECK_ERROR (WMI->GetObject (bstrConfigurationAssocClassPath,
  1189. WBEM_FLAG_RETURN_WBEM_COMPLETE,
  1190. NULL,
  1191. &smartpAssocClass,
  1192. NULL));
  1193. CHECK_ERROR(smartpAssocClass->SpawnInstance(0, &smartpAssocInstance));
  1194. CHECK_ERROR(PutStringProperty(smartpAssocInstance, L"ParentPath", bstrParentPath));
  1195. CHECK_ERROR(PutStringProperty(smartpAssocInstance, L"ChildPath", bstrTopInstancePath));
  1196. }
  1197. // Whew! Finally, we're ready to paste the new items. Let 'er rip!
  1198. for (i = 0, nLen = saInstancesNew.GetSize(); i < nLen; i++)
  1199. {
  1200. IWbemClassObjectPtr smartpInstance;
  1201. CHECK_ERROR (saInstancesNew.GetElement (i, &smartpInstance));
  1202. _bstr_t bstrClass, bstrPath;
  1203. CHECK_ERROR (GetStringProperty(smartpInstance, L"__RELPATH", bstrPath));
  1204. CHECK_ERROR (GetStringProperty(smartpInstance, L"__CLASS", bstrClass));
  1205. // If the user is pasting on the same machine, there's no need to write
  1206. // actions, since we will simply use associations to the same actions.
  1207. // The one exception is if we're pasting a single action (which will
  1208. // result in a new action being laid down).
  1209. if (bPasteOnSameMachine && ! bIsActionTopInstance)
  1210. {
  1211. if (!_wcsicmp(bstrFilterToConsumerBindingClassPath, bstrClass)
  1212. || !_wcsicmp(bstrEventConsumerClassPath, bstrClass)
  1213. || !_wcsicmp(bstrEventFilterClassPath, bstrClass)
  1214. || !_wcsicmp(bstrActionConfigurationClassPath, bstrClass) )
  1215. {
  1216. continue; // skip if it's an action
  1217. }
  1218. }
  1219. // TODO: as an optmization, we should consider not laying down
  1220. // multiple copies of the same action. WMI should handle our saves as
  1221. // simple instance modification events, but it would speed things up
  1222. // to filter out multiple copies of actions.
  1223. // impersonate the caller. Important since we're now calling into
  1224. // WMI and need to make sure caller is allowed
  1225. CHECK_ERROR(CoImpersonateClient());
  1226. // finally, lay down the new instance!
  1227. HRESULT hr = WMI->PutInstance(smartpInstance,
  1228. WBEM_FLAG_RETURN_WBEM_COMPLETE | WBEM_FLAG_CREATE_OR_UPDATE,
  1229. NULL,
  1230. NULL);
  1231. if (hr == WBEM_E_ACCESS_DENIED)
  1232. {
  1233. // we may have trouble overwriting action instances when those
  1234. // were created by another user. But since admin users should
  1235. // be able to override this restriction, and only admins can
  1236. // use HM in this release, I think that we're OK.
  1237. // BUGBUG: in future HM releases, we should consider deleting
  1238. // old action instances if the SID's are different from ours.
  1239. }
  1240. if (FAILED(hr))
  1241. {
  1242. CHECK_ERROR (hr);
  1243. }
  1244. if (i == 0 && (bool) smartpAssocInstance)
  1245. {
  1246. // now that we've stored the top-level parent, let's add the association
  1247. // to the parent. There's a bug in the rest of the agent that it won't
  1248. // pick up action associations unless the parent instance is already
  1249. // associated. Hopefully this will be fixed, but until then we'll link up
  1250. // the new top instance right at first.
  1251. CHECK_ERROR(WMI->PutInstance(smartpAssocInstance,
  1252. WBEM_FLAG_RETURN_WBEM_COMPLETE | WBEM_FLAG_CREATE_OR_UPDATE,
  1253. NULL,
  1254. NULL));
  1255. }
  1256. //BUGBUG: shouldn't lay down anything that's already there and the same as us!
  1257. //BUGBUG: before calling it a conflict, must compare properties!
  1258. }
  1259. return S_OK;
  1260. }
  1261. // Below are the actual entry points for the old agent code
  1262. // to call the new copy & paste functionality
  1263. HRESULT CSystem::AgentPaste(LPTSTR pszTargetGUID,
  1264. SAFEARRAY* psa,
  1265. LPTSTR pszOriginalSystem,
  1266. LPTSTR pszOriginalParentGUID,
  1267. BOOL bForceReplace)
  1268. {
  1269. HRESULT hr = Paste(L".", pszTargetGUID, pszOriginalSystem,
  1270. pszOriginalParentGUID, psa, bForceReplace, *this);
  1271. // BUGBUG: the agent returns the HRESULT of the Paste back
  1272. // through the __ReturnValue of the method, not through WMI
  1273. // errors. This is bad-- needs to be changed.
  1274. if (hr == WBEM_E_ALREADY_EXISTS)
  1275. return 2; // 2 is what console recognizes here.
  1276. else if (FAILED(hr))
  1277. return hr;
  1278. else
  1279. return 0;
  1280. }
  1281. HRESULT CSystem::AgentCopy(LPTSTR pszGUID,
  1282. SAFEARRAY** ppsa,
  1283. LPTSTR *pszOriginalParentGUID)
  1284. {
  1285. SafeArrayOneDimWbemClassObject sa;
  1286. CHECK_ERROR (sa.Create());
  1287. _bstr_t bstrParentGUID;
  1288. // now call the underlying copy routine
  1289. HRESULT hr = Copy(L".", pszGUID, bstrParentGUID, sa, *this);
  1290. CHECK_ERROR (hr);
  1291. VARIANT var = sa.Detach();
  1292. *ppsa = var.parray;
  1293. // copy the BSTR into a new[] string, as the caller expects.
  1294. // should really use a smart pointer or _bstr_t instead....
  1295. TCHAR* p = new TCHAR[bstrParentGUID.length()+1];
  1296. if (p == NULL)
  1297. CHECK_ERROR (E_OUTOFMEMORY);
  1298. wcscpy (p, bstrParentGUID);
  1299. *pszOriginalParentGUID = p;
  1300. return hr;
  1301. }