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.

857 lines
22 KiB

  1. /*++
  2. Copyright (C) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. PERFCACH.CPP
  5. Abstract:
  6. Containes some classes which are used to cache NT performance data.
  7. History:
  8. a-davj 15-DEC-95 Created.
  9. --*/
  10. #include "precomp.h"
  11. #include <wbemidl.h>
  12. #include "perfcach.h"
  13. #include <winperf.h>
  14. #include <tchar.h>
  15. //***************************************************************************
  16. //
  17. // BOOL CIndicyList::SetUse
  18. //
  19. // DESCRIPTION:
  20. //
  21. // Indicates that an object type has just been used. If the object
  22. // is already on the list, then its last accessed time is updated. New
  23. // object types are added to the list
  24. //
  25. // PARAMETERS:
  26. //
  27. // iObj Number. The acutally translates to the object number
  28. // that perf monitor uses to identify objects.
  29. //
  30. // RETURN VALUE:
  31. //
  32. // always TRUE unless it was a new entry and there isnt enough memory
  33. // to add.
  34. //***************************************************************************
  35. BOOL CIndicyList::SetUse(
  36. IN int iObj)
  37. {
  38. int iNumEntries, iCnt;
  39. // Go Through list and determine if there is an entry
  40. Entry * pCurr;
  41. iNumEntries = Entries.Size();
  42. for(iCnt = 0; iCnt < iNumEntries; iCnt++)
  43. {
  44. pCurr = (Entry *)Entries.GetAt(iCnt);
  45. if(iObj == pCurr->iObject) // found it!
  46. break;
  47. }
  48. if(iCnt < iNumEntries)
  49. {
  50. // Found the entry. Set its last used to to the
  51. // present unless it is a permanent entry
  52. if(pCurr->dwLastUsed != PERMANENT)
  53. pCurr->dwLastUsed = GetCurrentTime();
  54. return TRUE;
  55. }
  56. else
  57. // Entry not found, add to list
  58. return bAdd(iObj,GetCurrentTime());
  59. }
  60. //***************************************************************************
  61. //
  62. // BOOL CIndicyList::bItemInList
  63. //
  64. // DESCRIPTION:
  65. //
  66. // Checks if an item is in the list.
  67. //
  68. // PARAMETERS:
  69. //
  70. // iObj Number. The acutally translates to the object number
  71. // that perf monitor uses to identify objects.
  72. //
  73. // RETURN VALUE:
  74. //
  75. // TRUE if the item is in the list
  76. //
  77. //***************************************************************************
  78. BOOL CIndicyList::bItemInList(
  79. IN int iObj)
  80. {
  81. int iNumEntries, iCnt;
  82. // Go Through list and determine if the entry is there
  83. Entry * pCurr;
  84. iNumEntries = Entries.Size();
  85. for(iCnt = 0; iCnt < iNumEntries; iCnt++)
  86. {
  87. pCurr = (Entry *)Entries.GetAt(iCnt);
  88. if(iObj == pCurr->iObject) // found it!
  89. return TRUE;
  90. }
  91. return FALSE;
  92. }
  93. //***************************************************************************
  94. //
  95. // BOOL CIndicyList::bAdd
  96. //
  97. // DESCRIPTION:
  98. //
  99. // Adds an object type to the list
  100. //
  101. // PARAMETERS:
  102. //
  103. // iObj Number. The acutally translates to the object number
  104. // that perf monitor uses to identify objects.
  105. // dwTime Current system time
  106. //
  107. // RETURN VALUE:
  108. //
  109. // Returns TRUE if OK.
  110. //
  111. //***************************************************************************
  112. BOOL CIndicyList::bAdd(
  113. IN int iObj,
  114. IN DWORD dwTime)
  115. {
  116. Entry * pNew = new Entry;
  117. if(pNew == NULL)
  118. return FALSE;
  119. pNew->iObject = iObj;
  120. pNew->dwLastUsed = dwTime;
  121. int iRet = Entries.Add(pNew);
  122. if(iRet != CFlexArray::no_error)
  123. {
  124. delete pNew;
  125. return FALSE;
  126. }
  127. return TRUE;
  128. }
  129. //***************************************************************************
  130. //
  131. // void CIndicyList::PruneOld
  132. //
  133. // DESCRIPTION:
  134. //
  135. // Looks at the entries in the list and removes any that have
  136. // not been used in a long time.
  137. //
  138. //***************************************************************************
  139. void CIndicyList::PruneOld(void)
  140. {
  141. Entry * pCurr;
  142. int iNumEntries, iCnt;
  143. DWORD dwCurr = GetCurrentTime();
  144. iNumEntries = Entries.Size();
  145. for(iCnt = iNumEntries-1; iCnt >= 0; iCnt--)
  146. {
  147. pCurr = (Entry *)Entries.GetAt(iCnt);
  148. if(pCurr->dwLastUsed != PERMANENT)
  149. if((dwCurr - pCurr->dwLastUsed) > MAX_UNUSED_KEEP)
  150. {
  151. Entries.RemoveAt(iCnt);
  152. delete pCurr;
  153. }
  154. }
  155. // Entries.FreeExtra();
  156. }
  157. //***************************************************************************
  158. //
  159. // LPCTSTR CIndicyList::pGetAll
  160. //
  161. // DESCRIPTION:
  162. //
  163. // Returns a pointer to a string containing the numbers of all the objects
  164. // on the list. For example, if the list had objects 2,4, and 8; then
  165. // the string "2 4 8" would be retrieved. Null is returned if there
  166. // isnt enough memory.
  167. //
  168. // RETURN VALUE:
  169. //
  170. // see description
  171. //
  172. //***************************************************************************
  173. LPCTSTR CIndicyList::pGetAll(void)
  174. {
  175. int iNumEntries, iCnt;
  176. Entry * pCurr;
  177. // Go Through list and add each object number to the string
  178. sAll.Empty();
  179. iNumEntries = Entries.Size();
  180. for(iCnt = 0; iCnt < iNumEntries; iCnt++)
  181. {
  182. TCHAR pTemp[20];
  183. pCurr = (Entry *)Entries.GetAt(iCnt);
  184. sAll += _itot(pCurr->iObject,pTemp,10);
  185. if(iCnt < iNumEntries-1)
  186. sAll += TEXT(" ");
  187. }
  188. return sAll;
  189. }
  190. //***************************************************************************
  191. //
  192. // CIndicyList & CIndicyList::operator =
  193. //
  194. // DESCRIPTION:
  195. //
  196. // Supports the assignment of one CIndicyList object to another
  197. //
  198. // PARAMETERS:
  199. //
  200. // from Value to copy
  201. //
  202. // RETURN VALUE:
  203. //
  204. // reterence the "this" object
  205. //***************************************************************************
  206. CIndicyList & CIndicyList::operator = (
  207. CIndicyList & from)
  208. {
  209. int iNumEntries, iCnt;
  210. Entry * pCurr;
  211. // Free existing list
  212. FreeAll();
  213. iNumEntries = from.Entries.Size();
  214. for(iCnt = 0; iCnt < iNumEntries; iCnt++)
  215. {
  216. pCurr = (Entry *)from.Entries.GetAt(iCnt);
  217. bAdd(pCurr->iObject, pCurr->dwLastUsed);
  218. }
  219. return *this;
  220. }
  221. //***************************************************************************
  222. //
  223. // void CIndicyList::FreeAll
  224. //
  225. // DESCRIPTION:
  226. //
  227. // Purpose: Clears out the list and frees memory.
  228. //
  229. //***************************************************************************
  230. void CIndicyList::FreeAll(void)
  231. {
  232. int iNumEntries, iCnt;
  233. // Go Through list and determine if there is an entry
  234. Entry * pCurr;
  235. // delete each object in the list.
  236. iNumEntries = Entries.Size();
  237. for(iCnt = 0; iCnt < iNumEntries; iCnt++)
  238. {
  239. pCurr = (Entry *)Entries.GetAt(iCnt);
  240. delete pCurr;
  241. }
  242. Entries.Empty();
  243. }
  244. //***************************************************************************
  245. //
  246. // DWORD PerfBuff::Read
  247. //
  248. // DESCRIPTION:
  249. //
  250. // Read the perf monitor data.
  251. //
  252. // PARAMETERS:
  253. //
  254. // hKey Registry key for perf mon data
  255. // iObj Number. The acutally translates to the object number
  256. // that perf monitor uses to identify objects.
  257. // bInitial Set to TRUE for first call
  258. //
  259. // RETURN VALUE:
  260. //
  261. // 0 All is well
  262. // WBEM_E_OUT_OF_MEMORY
  263. //
  264. //***************************************************************************
  265. DWORD PerfBuff::Read(
  266. IN HKEY hKey,
  267. IN int iObj,
  268. IN BOOL bInitial)
  269. {
  270. DWORD dwRet;
  271. LPCTSTR pRequest;
  272. // Make sure there is a data buffer
  273. if(dwSize == 0)
  274. {
  275. pData = new char[INITIAL_ALLOCATION];
  276. if(pData == NULL)
  277. return WBEM_E_OUT_OF_MEMORY;
  278. dwSize = INITIAL_ALLOCATION;
  279. }
  280. hKeyLastRead = hKey; // record the key that was used
  281. // Make sure that the desired object is in the list of
  282. // objects to be retrieved. Also set pRequest to the string that will
  283. // be passed to retrieve the perf counter block. An initial read is done
  284. // in order to establish the list of permanent object types which are
  285. // always to be retrived and that includes the standard "global" types
  286. // such as memory, processor, disk, etc.
  287. if(!bInitial)
  288. {
  289. if(!List.SetUse(iObj))
  290. return WBEM_E_OUT_OF_MEMORY;
  291. List.PruneOld();
  292. pRequest = List.pGetAll();
  293. if(pRequest == NULL)
  294. return WBEM_E_OUT_OF_MEMORY;
  295. }
  296. else
  297. pRequest = TEXT("Global");
  298. // Read the data. Note that the read may be retried if the data
  299. // block needs to be expanded
  300. do
  301. {
  302. DWORD dwTempSize, dwType;
  303. dwTempSize = dwSize;
  304. try
  305. {
  306. dwRet = RegQueryValueEx (hKey,pRequest,NULL,&dwType,
  307. (BYTE *)pData,&dwTempSize);
  308. }
  309. catch(...)
  310. {
  311. delete pData;
  312. return WBEM_E_FAILED;
  313. }
  314. if(dwRet == ERROR_MORE_DATA)
  315. {
  316. delete pData;
  317. dwSize += 5000;
  318. pData = new char[dwSize];
  319. if(pData == NULL)
  320. {
  321. dwSize = 0;
  322. return WBEM_E_OUT_OF_MEMORY;
  323. }
  324. }
  325. } while (dwRet == ERROR_MORE_DATA);
  326. // Set the age of the data
  327. if(dwRet == ERROR_SUCCESS)
  328. {
  329. PERF_DATA_BLOCK * pBlock = (PERF_DATA_BLOCK *)pData;
  330. PerfTime = *(LONGLONG UNALIGNED *)(&pBlock->PerfTime);
  331. PerfTime100nSec = *(LONGLONG UNALIGNED *)(&pBlock->PerfTime100nSec);
  332. PerfFreq = *(LONGLONG UNALIGNED *)(&pBlock->PerfFreq);
  333. dwBuffLastRead = GetCurrentTime();
  334. }
  335. else
  336. dwBuffLastRead = 0;
  337. // If this was an initial read of the default objects, add all the
  338. // default objects to the list as permanent entries
  339. if(bInitial && dwRet == ERROR_SUCCESS)
  340. {
  341. int iIndex;
  342. PERF_DATA_BLOCK * pBlock = (PERF_DATA_BLOCK * )pData;
  343. PPERF_OBJECT_TYPE pObj;
  344. pObj = (PPERF_OBJECT_TYPE)((PBYTE)pBlock + pBlock->HeaderLength);
  345. for(iIndex = 0; iIndex < (int)pBlock->NumObjectTypes; iIndex++)
  346. {
  347. //todo, check for errors on add.
  348. if(!List.bAdd((int)pObj->ObjectNameTitleIndex,PERMANENT))
  349. return WBEM_E_OUT_OF_MEMORY;
  350. pObj = (PPERF_OBJECT_TYPE)((PBYTE)pObj + pObj->TotalByteLength);
  351. }
  352. }
  353. return dwRet;
  354. }
  355. //***************************************************************************
  356. //
  357. // LPSTR PerfBuff::Get
  358. //
  359. // DESCRIPTION:
  360. //
  361. // Returns a pointer to the data and also indicates that the particular type
  362. // was just used.
  363. //
  364. // PARAMETERS:
  365. //
  366. // iObj Number. The acutally translates to the object number
  367. // that perf monitor uses to identify objects.
  368. //
  369. // RETURN VALUE:
  370. //
  371. // see description.
  372. //***************************************************************************
  373. LPSTR PerfBuff::Get(
  374. int iObj)
  375. {
  376. List.SetUse(iObj);
  377. return pData;
  378. }
  379. //***************************************************************************
  380. //
  381. // void PerfBuff::Free
  382. //
  383. // DESCRIPTION:
  384. //
  385. // Frees up the memory
  386. //
  387. //***************************************************************************
  388. void PerfBuff::Free()
  389. {
  390. if(pData)
  391. delete pData;
  392. pData = NULL;
  393. dwSize = 0;
  394. hKeyLastRead = NULL;
  395. dwBuffLastRead = 0;
  396. List.FreeAll();
  397. }
  398. //***************************************************************************
  399. //
  400. // PerfBuff::PerfBuff
  401. //
  402. // DESCRIPTION:
  403. //
  404. // Constructor.
  405. //
  406. //***************************************************************************
  407. PerfBuff::PerfBuff()
  408. {
  409. dwSize = 0;
  410. pData = NULL;
  411. hKeyLastRead = NULL;
  412. dwBuffLastRead = 0;
  413. }
  414. //***************************************************************************
  415. //
  416. // BOOL PerfBuff::bOK
  417. //
  418. // DESCRIPTION:
  419. //
  420. // Returns TRUE, if and only if the same registry key was used to read
  421. // the data, the data isnt too old, and the particular object type is
  422. // in the data block.
  423. //
  424. // PARAMETERS:
  425. //
  426. // hKey Registry key for reading data
  427. // dwMaxAge Maximum acceptable age
  428. // iObj Number. The acutally translates to the object number
  429. // that perf monitor uses to identify objects.
  430. //
  431. // RETURN VALUE:
  432. //
  433. // see desription
  434. //***************************************************************************
  435. BOOL PerfBuff::bOK(
  436. IN HKEY hKey,
  437. IN DWORD dwMaxAge,
  438. IN int iObj)
  439. {
  440. if(dwSize ==0)
  441. return FALSE;
  442. if(hKey != hKeyLastRead)
  443. return FALSE;
  444. if((GetCurrentTime() - dwBuffLastRead) > dwMaxAge)
  445. return FALSE;
  446. return List.bItemInList(iObj);
  447. }
  448. //***************************************************************************
  449. //
  450. // PerfBuff & PerfBuff::operator =
  451. //
  452. // DESCRIPTION:
  453. //
  454. // Allows assignment.
  455. //
  456. // PARAMETERS:
  457. //
  458. // from Assignment source
  459. //
  460. // RETURN VALUE:
  461. //
  462. // reference to "this" object.
  463. //***************************************************************************
  464. PerfBuff & PerfBuff::operator = (
  465. IN PerfBuff & from)
  466. {
  467. // if the objects have different buffer sizes, free up the destinations
  468. // buffer and reallocate on of the same size as the source.
  469. if(from.dwSize != dwSize)
  470. {
  471. Free();
  472. pData = new char[from.dwSize];
  473. if(pData == NULL)
  474. {
  475. // failure in assignment isnt too serious since the buffer
  476. // will just return null when asked for the data.
  477. dwSize = 0;
  478. dwBuffLastRead = 0;
  479. return *this;
  480. }
  481. dwSize = from.dwSize;
  482. }
  483. // Copy the list of objects and times etc.
  484. memcpy(pData,from.pData,dwSize);
  485. List = from.List;
  486. hKeyLastRead = from.hKeyLastRead;
  487. dwBuffLastRead = from.dwBuffLastRead;
  488. PerfTime = from.PerfTime;
  489. PerfTime100nSec = from.PerfTime100nSec;
  490. PerfFreq = from.PerfFreq;
  491. return *this;
  492. }
  493. //***************************************************************************
  494. //
  495. // void PerfCache::FreeOldBuffers
  496. //
  497. // DESCRIPTION:
  498. //
  499. // Called by the house keeping thread to free up any buffers tool old to
  500. // be of any use.
  501. //
  502. //***************************************************************************
  503. void PerfCache::FreeOldBuffers(void)
  504. {
  505. if(Old.dwSize != 0 &&
  506. (GetCurrentTime() - Old.dwBuffLastRead) > MAX_OLD_AGE)
  507. Old.Free();
  508. if(New.dwSize != 0 &&
  509. (GetCurrentTime() - New.dwBuffLastRead) > MAX_OLD_AGE)
  510. New.Free();
  511. }
  512. //***************************************************************************
  513. //
  514. // DWORD PerfCache::dwGetNew
  515. //
  516. // DESCRIPTION:
  517. //
  518. // Sets a pointer to the most recently read data and will actually do a read
  519. // if the data in the new buffer isnt fresh enough. The PLINESTRUCT data is
  520. // also set.
  521. //
  522. // PARAMETERS:
  523. //
  524. // pName Machine name
  525. // iObj Number. The acutally translates to the object number
  526. // that perf monitor uses to identify objects.
  527. // pData Set to the object name
  528. // pls Set to info used to do calculations.
  529. //
  530. // RETURN VALUE:
  531. //
  532. // 0 all is well
  533. // WBEM_E_OUT_OF_MEMORY
  534. // otherwise error from dwGetHandle, or Read.
  535. //***************************************************************************
  536. DWORD PerfCache::dwGetNew(
  537. IN LPCTSTR pName,
  538. IN int iObj,
  539. OUT IN LPSTR * pData,
  540. OUT IN PLINESTRUCT pls)
  541. {
  542. DWORD dwRet;
  543. // Get the handle
  544. dwRet = dwGetHandle(pName);
  545. if(hHandle == NULL || dwRet != 0)
  546. return dwRet;
  547. // If the new data is acceptable, then use it
  548. if(New.bOK(hHandle,MAX_NEW_AGE, iObj))
  549. {
  550. // OutputDebugString(TEXT("\r\nCurrent New is OK"));
  551. }
  552. else
  553. {
  554. // If the new data has the correct type, AND either the old data
  555. // is junk, or the new data has aged enough to be old, copy the
  556. // new into the old.
  557. if(New.bOK(hHandle,MAX_OLD_AGE, iObj) &&
  558. (!Old.bOK(hHandle,MAX_OLD_AGE, iObj) ||
  559. (GetCurrentTime() - New.dwBuffLastRead >= MIN_TIME_DIFF)))
  560. {
  561. // OutputDebugString("\r\nMoving New into Old in dwGetNew");
  562. Old = New;
  563. if(Old.dwSize == 0) // could happen in low memory
  564. return WBEM_E_OUT_OF_MEMORY;
  565. }
  566. // Read the latest data.
  567. dwRet = New.Read(hHandle, iObj, FALSE);
  568. // OutputDebugString(TEXT("\r\nRead in New"));
  569. if(dwRet != ERROR_SUCCESS)
  570. return dwRet;
  571. }
  572. *pData = New.Get(iObj);
  573. pls->lnNewTime = New.PerfTime;
  574. pls->lnNewTime100Ns = New.PerfTime100nSec;
  575. pls->lnPerfFreq = New.PerfFreq;
  576. return ERROR_SUCCESS;
  577. }
  578. //***************************************************************************
  579. //
  580. // DWORD PerfCache::dwGetPair
  581. //
  582. // DESCRIPTION:
  583. //
  584. // Sets a pointer to the most recently read data and to the old data so that
  585. // time averaging can be done. This routine will ensure that the time
  586. // difference between the old and new is sufficient. The dwGetNew
  587. // routine should always be called first. The PLINESTRUCT data is
  588. // also set.
  589. //
  590. // PARAMETERS:
  591. //
  592. // pName Object Name
  593. // iObj Number. The acutally translates to the object number
  594. // that perf monitor uses to identify objects.
  595. //
  596. // pOldData Older data sample
  597. // pNewData Newer data sample
  598. // pls line struct data with things like frequency, age etc.
  599. //
  600. // RETURN VALUE:
  601. //
  602. // 0 if OK, otherwise retuns an error code.
  603. //
  604. //***************************************************************************
  605. DWORD PerfCache::dwGetPair(
  606. IN LPCTSTR pName,
  607. IN int iObj,
  608. OUT IN LPSTR * pOldData,
  609. OUT IN LPSTR * pNewData,
  610. OUT IN PLINESTRUCT pls)
  611. {
  612. DWORD dwRet;
  613. BOOL bOldOK;
  614. // Check to see if the old buffer is OK.
  615. bOldOK = Old.bOK(hHandle,MAX_OLD_AGE, iObj);
  616. // If both buffers are ok, then we are done
  617. if(bOldOK)
  618. {
  619. *pOldData = Old.Get(iObj);
  620. pls->lnOldTime = Old.PerfTime;
  621. pls->lnOldTime100Ns = Old.PerfTime100nSec;
  622. // OutputDebugString(TEXT("\r\nOld is OK"));
  623. return ERROR_SUCCESS;
  624. }
  625. // Since the new buffer has already been read, use it as the old buffer
  626. Old = New;
  627. if(Old.dwSize == 0) // could happen in low memory
  628. return WBEM_E_OUT_OF_MEMORY;
  629. // OutputDebugString(TEXT("\r\nCopying New into Old in dwGetPair"));
  630. // Possibly delay long enough so that there is a decent interval
  631. DWORD dwAge = GetCurrentTime() - Old.dwBuffLastRead;
  632. if(dwAge < MIN_TIME_DIFF)
  633. {
  634. DWORD dwSleep = MIN_TIME_DIFF - dwAge;
  635. TCHAR temp[100];
  636. wsprintf(temp,TEXT("\r\nsleeping %u ms"),dwSleep);
  637. // OutputDebugString(temp);
  638. Sleep(dwSleep);
  639. }
  640. // Read in the new buffer
  641. dwRet = New.Read(hHandle, iObj, FALSE);
  642. // OutputDebugString(TEXT("\r\ndoing raw read of new after delay"));
  643. if(dwRet != ERROR_SUCCESS)
  644. return dwRet;
  645. *pNewData = New.Get(iObj);
  646. *pOldData = Old.Get(iObj);
  647. pls->lnOldTime = Old.PerfTime;
  648. pls->lnOldTime100Ns = Old.PerfTime100nSec;
  649. pls->lnNewTime = New.PerfTime;
  650. pls->lnNewTime100Ns = New.PerfTime100nSec;
  651. pls->lnPerfFreq = New.PerfFreq;
  652. return ERROR_SUCCESS;
  653. }
  654. //***************************************************************************
  655. //
  656. // PerfCache::PerfCache
  657. //
  658. // DESCRIPTION:
  659. //
  660. // Constructor.
  661. //
  662. //***************************************************************************
  663. PerfCache::PerfCache()
  664. {
  665. // Read in the standard counters. This builds a list containing
  666. // those standards as well as providing immediate data for any
  667. // request to come in the near future.
  668. hHandle = HKEY_PERFORMANCE_DATA;
  669. /// New.Read(hHandle, 0, TRUE);
  670. }
  671. //***************************************************************************
  672. //
  673. // PerfCache::~PerfCache
  674. //
  675. // DESCRIPTION:
  676. //
  677. // Destructor.
  678. //
  679. //***************************************************************************
  680. PerfCache::~PerfCache()
  681. {
  682. // If the handle is to a remote machine, close it.
  683. if(hHandle != NULL && hHandle != HKEY_PERFORMANCE_DATA)
  684. RegCloseKey(hHandle);
  685. }
  686. //***************************************************************************
  687. //
  688. // DWORD PerfCache::dwGetHandle
  689. //
  690. // DESCRIPTION:
  691. //
  692. // Makes sure that hHandle is set correctly.
  693. //
  694. // PARAMETERS:
  695. //
  696. // pMachine Machine name.
  697. //
  698. // RETURN VALUE:
  699. //
  700. // 0 all is well
  701. // WBEM_E_OUT_OF_MEMORY
  702. // WBEM_E_INVALID_PARAMETER bad argument
  703. // otherwise error from RegConnectRegistry
  704. //
  705. //***************************************************************************
  706. DWORD PerfCache::dwGetHandle(
  707. LPCTSTR pMachine)
  708. {
  709. DWORD dwRet;
  710. // if the machines are the same, the just use the existing handle
  711. if(pMachine == NULL)
  712. return WBEM_E_INVALID_PARAMETER; // bad mapping string
  713. if(!lstrcmpi(sMachine,pMachine) && hHandle != NULL)
  714. return 0; // already got it!
  715. // handle is needed for machine other that the local. Start
  716. // by freeing the existing handle if it too is non local
  717. if(hHandle != NULL && hHandle != HKEY_PERFORMANCE_DATA)
  718. RegCloseKey(hHandle);
  719. // save the machine name so that we dont reopen this
  720. sMachine = pMachine;
  721. if(lstrcmpi(pMachine,TEXT("local")))
  722. {
  723. LPTSTR pTemp = NULL;
  724. int iLen = sMachine.Length() +1;
  725. dwRet = RegConnectRegistry(sMachine,HKEY_PERFORMANCE_DATA,
  726. &hHandle);
  727. if(dwRet != ERROR_SUCCESS)
  728. { // could not remote connect
  729. hHandle = NULL;
  730. sMachine.Empty();
  731. }
  732. }
  733. else
  734. { // local machine, use standard handle.
  735. sMachine = TEXT("Local");
  736. hHandle = HKEY_PERFORMANCE_DATA;
  737. dwRet = 0;
  738. }
  739. return dwRet;
  740. }