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.

2422 lines
100 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 1998-1999 by Microsoft Corp.
  4. //
  5. // PerfAcc.CPP
  6. //
  7. // Windows NT Performance Data Access helper functions
  8. //
  9. // bobw 8-Jub-98 Created for use with NT Perf counters
  10. //
  11. //***************************************************************************
  12. //
  13. #include "wpheader.h"
  14. #include <stdlib.h>
  15. #include "oahelp.inl"
  16. #include <malloc.h>
  17. // NOTE: Consider reading this from the registry
  18. LONG lExtCounterTestLevel = EXT_TEST_ALL;
  19. //
  20. //
  21. // precompiled security descriptor
  22. // System and NetworkService has full access
  23. //
  24. // since this is RELATIVE, it will work on both IA32 and IA64
  25. //
  26. DWORD g_PrecSD[] = {
  27. 0x80040001 , 0x00000044 , 0x00000050 , 0x00000000 ,
  28. 0x00000014 , 0x00300002 , 0x00000002 , 0x00140000 ,
  29. 0x001f0001 , 0x00000101 , 0x05000000 , 0x00000012 ,
  30. 0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 ,
  31. 0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 ,
  32. 0x00000101 , 0x05000000 , 0x00000014
  33. };
  34. DWORD g_SizeSD = 0;
  35. DWORD g_RuntimeSD[(sizeof(ACL)+sizeof(ACCESS_ALLOWED_ACE)+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+4*(sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)))/sizeof(DWORD)];
  36. typedef
  37. BOOLEAN ( * fnRtlValidRelativeSecurityDescriptor)(
  38. IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
  39. IN ULONG SecurityDescriptorLength,
  40. IN SECURITY_INFORMATION RequiredInformation
  41. );
  42. fnRtlValidRelativeSecurityDescriptor RtlValidRelativeSecurityDescriptor;
  43. //
  44. // Build a SD with owner == This
  45. // group == This
  46. // DACL
  47. // ACE[0] MUTEX_ALL_ACCESS Owner
  48. // ACE[1] MUTEX_ALL_ACCESS System
  49. ///////////////////////////////////////////////////////////////////
  50. BOOL
  51. CreateSD( )
  52. {
  53. if (!RtlValidRelativeSecurityDescriptor)
  54. {
  55. HMODULE hModule = GetModuleHandleW(L"ntdll.dll");
  56. if (hModule)
  57. {
  58. RtlValidRelativeSecurityDescriptor = (fnRtlValidRelativeSecurityDescriptor)GetProcAddress(hModule,"RtlValidRelativeSecurityDescriptor");
  59. if (!RtlValidRelativeSecurityDescriptor)
  60. {
  61. return FALSE;
  62. }
  63. }
  64. }
  65. HANDLE hToken;
  66. BOOL bRet;
  67. bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken);
  68. if (bRet)
  69. {
  70. TOKEN_USER * pToken_User;
  71. DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
  72. pToken_User = (TOKEN_USER *)_alloca(dwSize);
  73. bRet = GetTokenInformation(hToken,TokenUser,pToken_User,dwSize,&dwSize);
  74. if (bRet)
  75. {
  76. SID SystemSid = { SID_REVISION,
  77. 1,
  78. SECURITY_NT_AUTHORITY,
  79. SECURITY_LOCAL_SYSTEM_RID
  80. };
  81. PSID pSIDUser = pToken_User->User.Sid;
  82. dwSize = GetLengthSid(pSIDUser);
  83. DWORD dwSids = 2; // Owner and System
  84. DWORD ACLLength = (ULONG) sizeof(ACL) +
  85. (dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwSize + sizeof(SystemSid);
  86. DWORD dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE) + dwSize + dwSize + ACLLength;
  87. SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)_alloca(dwSizeSD);
  88. memset(pLocalSD,0,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  89. pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION;
  90. pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE;
  91. //SetSecurityDescriptorOwner(pLocalSD,pSIDUser,FALSE);
  92. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE),pSIDUser,dwSize);
  93. pLocalSD->Owner = (DWORD)sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  94. //SetSecurityDescriptorGroup(pLocalSD,pSIDUser,FALSE);
  95. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize,pSIDUser,dwSize);
  96. pLocalSD->Group = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize);
  97. PACL pDacl = (PACL)_alloca(ACLLength);
  98. bRet = InitializeAcl( pDacl,
  99. ACLLength,
  100. ACL_REVISION);
  101. if (bRet)
  102. {
  103. bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&SystemSid);
  104. if (bRet)
  105. {
  106. bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,pSIDUser);
  107. if (bRet)
  108. {
  109. //bRet = SetSecurityDescriptorDacl(pLocalSD,TRUE,pDacl,FALSE);
  110. memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize,pDacl,ACLLength);
  111. pLocalSD->Dacl = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize);
  112. if (RtlValidRelativeSecurityDescriptor(pLocalSD,
  113. dwSizeSD,
  114. OWNER_SECURITY_INFORMATION|
  115. GROUP_SECURITY_INFORMATION|
  116. DACL_SECURITY_INFORMATION))
  117. {
  118. g_SizeSD = dwSizeSD;
  119. memcpy(g_RuntimeSD,pLocalSD,dwSizeSD);
  120. }
  121. else
  122. {
  123. bRet = FALSE;
  124. }
  125. }
  126. }
  127. }
  128. }
  129. CloseHandle(hToken);
  130. }
  131. return bRet;
  132. };
  133. //***************************************************************************
  134. //
  135. // HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
  136. //
  137. // This function will create a mutex using the process' security context
  138. //
  139. //***************************************************************************
  140. //
  141. HANDLE CreateMutexAsProcess(LPCWSTR pwszName)
  142. {
  143. BOOL bImpersonating = FALSE;
  144. HANDLE hThreadToken = NULL;
  145. // Determine if we are impersonating
  146. bImpersonating = OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE, TRUE,
  147. &hThreadToken);
  148. if(bImpersonating)
  149. {
  150. // Determine if we are impersonating
  151. bImpersonating = RevertToSelf();
  152. }
  153. // Create the mutex as using the process token.
  154. HANDLE hRet = OpenMutexW(MUTEX_ALL_ACCESS,FALSE,pwszName);
  155. if (NULL == hRet)
  156. {
  157. SECURITY_ATTRIBUTES sa;
  158. if (0 == g_SizeSD)
  159. {
  160. if (CreateSD())
  161. {
  162. sa.nLength = g_SizeSD;
  163. sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
  164. sa.bInheritHandle = FALSE;
  165. }
  166. else
  167. {
  168. sa.nLength = sizeof(g_PrecSD);
  169. sa.lpSecurityDescriptor = (LPVOID)g_PrecSD;
  170. sa.bInheritHandle = FALSE;
  171. }
  172. }
  173. else
  174. {
  175. sa.nLength = g_SizeSD;
  176. sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
  177. sa.bInheritHandle = FALSE;
  178. }
  179. hRet = CreateMutexW(&sa, FALSE, pwszName);
  180. }
  181. // If code was oringinally impersonating, resume impersonation
  182. if(bImpersonating)
  183. SetThreadToken(NULL, hThreadToken);
  184. if(hThreadToken)
  185. CloseHandle(hThreadToken);
  186. return hRet;
  187. }
  188. //***************************************************************************
  189. //
  190. // CPerfDataLibrary ::CPerfDataLibrary
  191. //
  192. // This object is used to abstract the perf data library
  193. //
  194. //***************************************************************************
  195. //
  196. CPerfDataLibrary::CPerfDataLibrary (void)
  197. {
  198. pLibInfo = NULL;
  199. memset ((LPVOID)szQueryString, 0, sizeof(szQueryString));
  200. dwRefCount = 0; // number of classes referencing this object
  201. }
  202. CPerfDataLibrary::~CPerfDataLibrary (void)
  203. {
  204. // all libraries should be closed before this is
  205. // destructed
  206. assert (dwRefCount == 0);
  207. assert (pLibInfo == NULL);
  208. }
  209. //***************************************************************************
  210. //
  211. // CPerfObjectAccess::CPerfObjectAccess
  212. //
  213. // This object is used to abstract a data object within a perf library
  214. //
  215. //***************************************************************************
  216. //
  217. CPerfObjectAccess::CPerfObjectAccess ()
  218. {
  219. m_hObjectHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0);
  220. if (m_hObjectHeap == NULL) {
  221. // then just use the process heap
  222. m_hObjectHeap = GetProcessHeap();
  223. }
  224. for (DWORD n=0; n < PL_TIMER_NUM_OBJECTS; n++) {
  225. hTimerHandles[n] = NULL;
  226. }
  227. hTimerDataMutex = NULL;
  228. hPerflibTimingThread = NULL;
  229. pTimerItemListHead = NULL;
  230. m_aLibraries.Empty();
  231. lEventLogLevel = LOG_UNDEFINED;
  232. hEventLog = NULL;
  233. }
  234. CPerfObjectAccess::~CPerfObjectAccess ()
  235. {
  236. int nNumLibraries;
  237. int nIdx;
  238. CPerfDataLibrary *pThisLibrary;
  239. if (pTimerItemListHead != NULL) {
  240. DestroyPerflibFunctionTimer();
  241. pTimerItemListHead = NULL;
  242. }
  243. // the DestroyPerflibFunctionTimer should take care of these
  244. // but just in case....
  245. if (hTimerDataMutex != NULL) {
  246. CloseHandle (hTimerDataMutex);
  247. hTimerDataMutex = NULL;
  248. }
  249. if (hPerflibTimingThread != NULL) {
  250. CloseHandle (hPerflibTimingThread);
  251. hPerflibTimingThread = NULL;
  252. }
  253. for (DWORD n=0; n < PL_TIMER_NUM_OBJECTS; n++) {
  254. if (hTimerHandles[n] != NULL) {
  255. CloseHandle (hTimerHandles[n]);
  256. hTimerHandles[n] = NULL;
  257. }
  258. }
  259. // close any lingering libraries
  260. nNumLibraries = m_aLibraries.Size();
  261. for (nIdx = 0; nIdx < nNumLibraries; nIdx++) {
  262. pThisLibrary = (CPerfDataLibrary *)m_aLibraries[nIdx];
  263. CloseLibrary (pThisLibrary);
  264. FREEMEM(m_hObjectHeap, 0, pThisLibrary->pLibInfo);
  265. pThisLibrary->pLibInfo = NULL;
  266. delete pThisLibrary;
  267. }
  268. m_aLibraries.Empty();
  269. if ((m_hObjectHeap != NULL) && (m_hObjectHeap != GetProcessHeap())) {
  270. HeapDestroy (m_hObjectHeap);
  271. }
  272. }
  273. //
  274. // Timer functions
  275. //
  276. DWORD
  277. __stdcall
  278. PerflibTimerFunction (
  279. LPVOID pArg
  280. )
  281. /*++
  282. PerflibTimerFunction
  283. Timing thread used to write an event log message if the timer expires.
  284. This thread runs until the Exit event is set or the wait for the
  285. Exit event times out.
  286. While the start event is set, then the timer checks the current events
  287. to be timed and reports on any that have expired. It then sleeps for
  288. the duration of the timing interval after which it checks the status
  289. of the start & exit events to begin the next cycle.
  290. The timing events are added and deleted from the list only by the
  291. StartPerflibFunctionTimer and KillPerflibFunctionTimer functions.
  292. Arguments
  293. pArg -- parent class object
  294. --*/
  295. {
  296. CPerfObjectAccess *pObj = (CPerfObjectAccess *)pArg;
  297. LONG lStatus = ERROR_SUCCESS;
  298. BOOL bKeepTiming = TRUE;
  299. LPOPEN_PROC_WAIT_INFO pLocalInfo;
  300. LPWSTR szMessageArray[2];
  301. DWORD dwData;
  302. if (lStatus == ERROR_SUCCESS) {
  303. while (bKeepTiming) {
  304. // wait for either the start or exit event flags to be set
  305. lStatus = WaitForMultipleObjects (
  306. PL_TIMER_NUM_OBJECTS,
  307. &pObj->hTimerHandles[0],
  308. FALSE, //wait for either one to be set
  309. PERFLIB_TIMING_THREAD_TIMEOUT);
  310. if (lStatus != WAIT_TIMEOUT) {
  311. if ((lStatus - WAIT_OBJECT_0) == PL_TIMER_EXIT_EVENT ) {
  312. // then that's all
  313. bKeepTiming = FALSE;
  314. break;
  315. } else if ((lStatus - WAIT_OBJECT_0) == PL_TIMER_START_EVENT) {
  316. // then the timer is running so wait the interval period
  317. // wait on exit event here to prevent hanging
  318. lStatus = WaitForSingleObject (
  319. pObj->hTimerHandles[PL_TIMER_EXIT_EVENT],
  320. PERFLIB_TIMING_THREAD_TIMEOUT);
  321. if (lStatus == WAIT_TIMEOUT) {
  322. // then the wait time expired without being told
  323. // to terminate the thread so
  324. // now evaluate the list of timed events
  325. // lock the data mutex
  326. lStatus = WaitForSingleObject (
  327. pObj->hTimerDataMutex,
  328. (PERFLIB_TIMER_INTERVAL * 2));
  329. for (pLocalInfo = pObj->pTimerItemListHead;
  330. pLocalInfo != NULL;
  331. pLocalInfo = pLocalInfo->pNext) {
  332. if (pLocalInfo->dwWaitTime != 0) {
  333. if (pLocalInfo->dwWaitTime == 1) {
  334. // then this is the last interval so log error
  335. szMessageArray[0] = pLocalInfo->szServiceName;
  336. szMessageArray[1] = pLocalInfo->szLibraryName;
  337. dwData = pLocalInfo->dwWaitTime * 1000;
  338. ReportEventW (hEventLog,
  339. EVENTLOG_WARNING_TYPE, // error type
  340. 0, // category (not used)
  341. (DWORD)WBEMPERF_OPEN_PROC_TIMEOUT, // event,
  342. NULL, // SID (not used),
  343. 2, // number of strings
  344. sizeof(DWORD), // sizeof raw data
  345. (LPCWSTR *)szMessageArray, // message text array
  346. (LPBYTE)&dwData); // raw data
  347. }
  348. pLocalInfo->dwWaitTime--;
  349. }
  350. }
  351. ReleaseMutex (pObj->hTimerDataMutex);
  352. } else {
  353. // we've been told to exit so
  354. lStatus = ERROR_SUCCESS;
  355. bKeepTiming = FALSE;
  356. break;
  357. }
  358. } else {
  359. // some unexpected error was returned
  360. assert (FALSE);
  361. }
  362. } else {
  363. // the wait timed out so it's time to go
  364. lStatus = ERROR_SUCCESS;
  365. bKeepTiming = FALSE;
  366. break;
  367. }
  368. }
  369. }
  370. return lStatus;
  371. }
  372. HANDLE
  373. CPerfObjectAccess::StartPerflibFunctionTimer (
  374. IN LPOPEN_PROC_WAIT_INFO pInfo
  375. )
  376. /*++
  377. Starts a timing event by adding it to the list of timing events.
  378. If the timer thread is not running, then the is started as well.
  379. If this is the first event in the list then the Start Event is
  380. set indicating that the timing thread can begin processing timing
  381. event(s).
  382. --*/
  383. {
  384. LONG Status = ERROR_SUCCESS;
  385. LPOPEN_PROC_WAIT_INFO pLocalInfo;
  386. DWORD dwLibNameLen;
  387. DWORD dwBufferLength = sizeof (OPEN_PROC_WAIT_INFO);
  388. HANDLE hReturn = NULL;
  389. if (pInfo == NULL) {
  390. // no required argument
  391. Status = ERROR_INVALID_PARAMETER;
  392. } else {
  393. // check on or create sync objects
  394. // allocate timing events for the timing thread
  395. if (hTimerHandles[PL_TIMER_START_EVENT] == NULL) {
  396. // create the event as NOT signaled since we're not ready to start
  397. hTimerHandles[PL_TIMER_START_EVENT] = CreateEvent (NULL, TRUE, FALSE, NULL);
  398. if (hTimerHandles[PL_TIMER_START_EVENT] == NULL) {
  399. Status = GetLastError();
  400. }
  401. }
  402. if (hTimerHandles[PL_TIMER_EXIT_EVENT] == NULL) {
  403. hTimerHandles[PL_TIMER_EXIT_EVENT] = CreateEvent (NULL, TRUE, FALSE, NULL);
  404. if (hTimerHandles[PL_TIMER_EXIT_EVENT] == NULL) {
  405. Status = GetLastError();
  406. }
  407. }
  408. // create data sync mutex if it hasn't already been created
  409. if (hTimerDataMutex == NULL) {
  410. hTimerDataMutex = CreateMutex (NULL, FALSE, NULL);
  411. if (hTimerDataMutex == NULL) {
  412. Status = GetLastError();
  413. }
  414. }
  415. }
  416. if (Status == ERROR_SUCCESS) {
  417. // continue creating timer entry
  418. if (hPerflibTimingThread != NULL) {
  419. // see if the handle is valid (i.e the thread is alive)
  420. Status = WaitForSingleObject (hPerflibTimingThread, 0);
  421. if (Status == WAIT_OBJECT_0) {
  422. // the thread has terminated so close the handle
  423. CloseHandle (hPerflibTimingThread);
  424. hPerflibTimingThread = NULL;
  425. Status = ERROR_SUCCESS;
  426. } else if (Status == WAIT_TIMEOUT) {
  427. // the thread is still running so continue
  428. Status = ERROR_SUCCESS;
  429. } else {
  430. // some other, probably serious, error
  431. // so pass it on through
  432. }
  433. } else {
  434. // the thread has never been created yet so continue
  435. }
  436. if (hPerflibTimingThread == NULL) {
  437. DWORD hThreadID;
  438. // create the timing thread
  439. assert (pTimerItemListHead == NULL); // there should be no entries, yet
  440. // everything is ready for the timer thread
  441. hPerflibTimingThread = CreateThread (
  442. NULL, 0,
  443. (LPTHREAD_START_ROUTINE)PerflibTimerFunction,
  444. (LPVOID)this, 0, &hThreadID);
  445. assert (hPerflibTimingThread != NULL);
  446. if (hPerflibTimingThread == NULL) {
  447. Status = GetLastError();
  448. }
  449. }
  450. if (Status == ERROR_SUCCESS) {
  451. // compute the length of the required buffer;
  452. dwLibNameLen = (lstrlenW (pInfo->szLibraryName) + 1) * sizeof(WCHAR);
  453. dwBufferLength += dwLibNameLen;
  454. dwBufferLength += (lstrlenW (pInfo->szServiceName) + 1) * sizeof(WCHAR);
  455. dwBufferLength = DWORD_MULTIPLE (dwBufferLength);
  456. pLocalInfo = (LPOPEN_PROC_WAIT_INFO)ALLOCMEM (
  457. m_hObjectHeap, HEAP_ZERO_MEMORY, dwBufferLength);
  458. if (pLocalInfo) {
  459. // copy the arg buffer to the local list
  460. pLocalInfo->szLibraryName = (LPWSTR)&pLocalInfo[1];
  461. lstrcpyW (pLocalInfo->szLibraryName, pInfo->szLibraryName);
  462. pLocalInfo->szServiceName = (LPWSTR)
  463. ((LPBYTE)pLocalInfo->szLibraryName + dwLibNameLen);
  464. lstrcpyW (pLocalInfo->szServiceName, pInfo->szServiceName);
  465. // convert wait time in milliseconds to the number of "loops"
  466. pLocalInfo->dwWaitTime = pInfo->dwWaitTime / PERFLIB_TIMER_INTERVAL;
  467. // wait for access to the data
  468. if (hTimerDataMutex != NULL) {
  469. Status = WaitForSingleObject (
  470. hTimerDataMutex,
  471. (PERFLIB_TIMER_INTERVAL * 2));
  472. } else {
  473. Status = ERROR_NOT_READY;
  474. }
  475. if (Status == WAIT_OBJECT_0) {
  476. // we have access to the data so add this item to the front of the list
  477. pLocalInfo->pNext = pTimerItemListHead;
  478. pTimerItemListHead = pLocalInfo;
  479. ReleaseMutex (hTimerDataMutex);
  480. if (pLocalInfo->pNext == NULL) {
  481. // then the list was empty before this call so start the timer
  482. // going
  483. SetEvent (hTimerHandles[PL_TIMER_START_EVENT]);
  484. }
  485. hReturn = (HANDLE)pLocalInfo;
  486. } else {
  487. SetLastError (Status);
  488. }
  489. }
  490. else {
  491. Status = ERROR_NOT_ENOUGH_MEMORY;
  492. SetLastError (Status);
  493. }
  494. } else {
  495. // unable to create thread
  496. SetLastError (Status);
  497. }
  498. } else {
  499. // unable to start timer
  500. SetLastError (Status);
  501. }
  502. return hReturn;
  503. }
  504. DWORD
  505. CPerfObjectAccess::KillPerflibFunctionTimer (
  506. IN HANDLE hPerflibTimer
  507. )
  508. /*++
  509. Terminates a timing event by removing it from the list. When the last
  510. item is removed from the list the Start event is reset so the timing
  511. thread will wait for either the next start event, exit event or it's
  512. timeout to expire.
  513. --*/
  514. {
  515. DWORD Status;
  516. LPOPEN_PROC_WAIT_INFO pArg = (LPOPEN_PROC_WAIT_INFO)hPerflibTimer;
  517. LPOPEN_PROC_WAIT_INFO pLocalInfo;
  518. BOOL bFound = FALSE;
  519. DWORD dwReturn = ERROR_SUCCESS;
  520. if (hTimerDataMutex == NULL) {
  521. dwReturn = ERROR_NOT_READY;
  522. } else if (pArg == NULL) {
  523. dwReturn = ERROR_INVALID_HANDLE;
  524. } else {
  525. // so far so good
  526. // wait for access to the data
  527. Status = WaitForSingleObject (
  528. hTimerDataMutex,
  529. (PERFLIB_TIMER_INTERVAL * 2));
  530. if (Status == WAIT_OBJECT_0) {
  531. // we have access to the list so walk down the list and remove the
  532. // specified item
  533. // see if it's the first one in the list
  534. if (pArg == pTimerItemListHead) {
  535. // then remove it
  536. pTimerItemListHead = pArg->pNext;
  537. bFound = TRUE;
  538. } else {
  539. for (pLocalInfo = pTimerItemListHead;
  540. pLocalInfo != NULL;
  541. pLocalInfo = pLocalInfo->pNext) {
  542. if (pLocalInfo->pNext == pArg) {
  543. pLocalInfo->pNext = pArg->pNext;
  544. bFound = TRUE;
  545. break;
  546. }
  547. }
  548. }
  549. assert (bFound);
  550. if (bFound) {
  551. // it's out of the list so release the lock
  552. ReleaseMutex (hTimerDataMutex);
  553. if (pTimerItemListHead == NULL) {
  554. // then the list is empty now so stop timing
  555. // going
  556. ResetEvent (hTimerHandles[PL_TIMER_START_EVENT]);
  557. }
  558. // free memory
  559. FREEMEM (m_hObjectHeap, 0, pArg);
  560. dwReturn = ERROR_SUCCESS;
  561. } else {
  562. dwReturn = ERROR_NOT_FOUND;
  563. }
  564. } else {
  565. dwReturn = ERROR_TIMEOUT;
  566. }
  567. }
  568. return dwReturn;
  569. }
  570. DWORD
  571. CPerfObjectAccess::DestroyPerflibFunctionTimer (
  572. )
  573. /*++
  574. Terminates the timing thread and cancels any current timer events.
  575. --*/
  576. {
  577. LONG Status;
  578. LPOPEN_PROC_WAIT_INFO pThisItem;
  579. LPOPEN_PROC_WAIT_INFO pNextItem;
  580. // wait for data mutex
  581. Status = WaitForSingleObject (
  582. hTimerDataMutex,
  583. (PERFLIB_TIMER_INTERVAL * 2));
  584. assert (Status != WAIT_TIMEOUT);
  585. // free all entries in the list
  586. for (pNextItem = pTimerItemListHead;
  587. pNextItem != NULL;) {
  588. pThisItem = pNextItem;
  589. pNextItem = pThisItem->pNext;
  590. FREEMEM (m_hObjectHeap, 0, pThisItem);
  591. }
  592. // set exit event
  593. SetEvent (hTimerHandles[PL_TIMER_EXIT_EVENT]);
  594. // wait for thread to terminate
  595. Status = WaitForSingleObject (
  596. hPerflibTimingThread,
  597. (PERFLIB_TIMER_INTERVAL * 5));
  598. assert (Status != WAIT_TIMEOUT);
  599. if (hPerflibTimingThread != NULL) {
  600. CloseHandle (hPerflibTimingThread);
  601. hPerflibTimingThread = NULL;
  602. }
  603. if (hTimerDataMutex != NULL) {
  604. // cloes handles and leave
  605. ReleaseMutex (hTimerDataMutex);
  606. CloseHandle (hTimerDataMutex);
  607. hTimerDataMutex = NULL;
  608. }
  609. if (hTimerHandles[PL_TIMER_START_EVENT] != NULL) {
  610. CloseHandle (hTimerHandles[PL_TIMER_START_EVENT]);
  611. hTimerHandles[PL_TIMER_START_EVENT] = NULL;
  612. }
  613. if (hTimerHandles[PL_TIMER_EXIT_EVENT] != NULL) {
  614. CloseHandle (hTimerHandles[PL_TIMER_EXIT_EVENT]);
  615. hTimerHandles[PL_TIMER_EXIT_EVENT] = NULL;
  616. }
  617. return ERROR_SUCCESS;
  618. }
  619. //***************************************************************************
  620. //
  621. // CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
  622. //
  623. // removes a reference to the library that contains this object and closes
  624. // the library when the last reference is removed
  625. //
  626. //***************************************************************************
  627. //
  628. DWORD
  629. CPerfObjectAccess::CloseLibrary (CPerfDataLibrary *pLib)
  630. {
  631. pExtObject pInfo;
  632. LONG lStatus;
  633. assert (pLib != NULL);
  634. assert (pLib->pLibInfo != NULL);
  635. pInfo = pLib->pLibInfo;
  636. assert (pLib->dwRefCount > 0);
  637. if (pLib->dwRefCount > 0) {
  638. pLib->dwRefCount--;
  639. if (pLib->dwRefCount == 0) {
  640. // if there's a close proc to call, then
  641. // call close procedure to close anything that may have
  642. // been allocated by the library
  643. if (pInfo->hMutex != NULL){
  644. lStatus = WaitForSingleObject (
  645. pInfo->hMutex,
  646. pInfo->dwOpenTimeout);
  647. // BUG!!A-DCREWS: If CloseProc is uninitialized, then the condition will
  648. // result in the lockoutcount being incremented
  649. if ((lStatus != WAIT_TIMEOUT) &&
  650. (pInfo->CloseProc != NULL)) {
  651. lStatus = (*pInfo->CloseProc) ();
  652. ReleaseMutex(pInfo->hMutex);
  653. } else {
  654. pInfo->dwLockoutCount++;
  655. }
  656. } else {
  657. lStatus = ERROR_LOCK_FAILED;
  658. }
  659. // then close everything
  660. if (pInfo->hMutex != NULL) {
  661. CloseHandle (pInfo->hMutex);
  662. pInfo->hMutex = NULL;
  663. }
  664. if (pInfo->hLibrary != NULL) {
  665. FreeLibrary (pInfo->hLibrary);
  666. pInfo->hLibrary = NULL;
  667. }
  668. if (pInfo->hPerfKey != NULL) {
  669. RegCloseKey (pInfo->hPerfKey);
  670. pInfo->hPerfKey = NULL;
  671. }
  672. }
  673. }
  674. return pLib->dwRefCount; // returns remaining references
  675. }
  676. //***************************************************************************
  677. //
  678. // CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
  679. //
  680. // OpenExtObjectLibrary
  681. //
  682. // Opens the specified library and looks up the functions used by
  683. // the performance library. If the library is successfully
  684. // loaded and opened then the open procedure is called to initialize
  685. // the object.
  686. //
  687. // This function expects locked and exclusive access to the object while
  688. // it is opening. This must be provided by the calling function.
  689. //
  690. // Arguments:
  691. //
  692. // pObj -- pointer to the object information structure of the
  693. // perf object to close
  694. //
  695. //***************************************************************************
  696. //
  697. DWORD
  698. CPerfObjectAccess::OpenExtObjectLibrary (pExtObject pObj)
  699. {
  700. DWORD Status = ERROR_SUCCESS;
  701. DWORD dwOpenEvent = 0;
  702. DWORD dwType;
  703. DWORD dwSize;
  704. DWORD dwValue;
  705. // variables used for event logging
  706. DWORD dwDataIndex;
  707. WORD wStringIndex;
  708. DWORD dwRawDataDwords[8];
  709. LPWSTR szMessageArray[8];
  710. HANDLE hPerflibFuncTimer = NULL;
  711. OPEN_PROC_WAIT_INFO opwInfo;
  712. UINT nErrorMode;
  713. // check to see if the library has already been opened
  714. if (pObj->hLibrary == NULL) {
  715. // library isn't loaded yet, so
  716. // check to see if this function is enabled
  717. dwType = 0;
  718. dwSize = sizeof (dwValue);
  719. dwValue = 0;
  720. Status = RegQueryValueExW (
  721. pObj->hPerfKey,
  722. cszDisablePerformanceCounters,
  723. NULL,
  724. &dwType,
  725. (LPBYTE)&dwValue,
  726. &dwSize);
  727. if ((Status == ERROR_SUCCESS) &&
  728. (dwType == REG_DWORD) &&
  729. (dwValue == 1)) {
  730. // then DON'T Load this library
  731. Status = ERROR_SERVICE_DISABLED;
  732. } else {
  733. Status = ERROR_SUCCESS;
  734. // go ahead and load it
  735. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  736. // then load library & look up functions
  737. pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
  738. NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  739. if (pObj->hLibrary != NULL) {
  740. // lookup function names
  741. pObj->OpenProc = (OPENPROC)GetProcAddress(
  742. pObj->hLibrary, pObj->szOpenProcName);
  743. if (pObj->OpenProc == NULL) {
  744. if (lEventLogLevel >= LOG_USER) {
  745. Status = GetLastError();
  746. // load data for eventlog message
  747. dwDataIndex = wStringIndex = 0;
  748. dwRawDataDwords[dwDataIndex++] =
  749. (DWORD)Status;
  750. szMessageArray[wStringIndex++] =
  751. ConvertProcName(pObj->szOpenProcName);
  752. szMessageArray[wStringIndex++] =
  753. pObj->szLibraryName;
  754. szMessageArray[wStringIndex++] =
  755. pObj->szServiceName;
  756. ReportEventW (hEventLog,
  757. EVENTLOG_ERROR_TYPE, // error type
  758. 0, // category (not used)
  759. (DWORD)WBEMPERF_OPEN_PROC_NOT_FOUND, // event,
  760. NULL, // SID (not used),
  761. wStringIndex, // number of strings
  762. dwDataIndex*sizeof(DWORD), // sizeof raw data
  763. (LPCWSTR *)szMessageArray, // message text array
  764. (LPVOID)&dwRawDataDwords[0]); // raw data
  765. }
  766. }
  767. if (Status == ERROR_SUCCESS) {
  768. if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
  769. pObj->QueryProc = (QUERYPROC)GetProcAddress (
  770. pObj->hLibrary, pObj->szCollectProcName);
  771. pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
  772. } else {
  773. pObj->CollectProc = (COLLECTPROC)GetProcAddress (
  774. pObj->hLibrary, pObj->szCollectProcName);
  775. pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
  776. }
  777. if (pObj->CollectProc == NULL) {
  778. if (lEventLogLevel >= LOG_USER) {
  779. Status = GetLastError();
  780. // load data for eventlog message
  781. dwDataIndex = wStringIndex = 0;
  782. dwRawDataDwords[dwDataIndex++] =
  783. (DWORD)Status;
  784. szMessageArray[wStringIndex++] =
  785. ConvertProcName(pObj->szCollectProcName);
  786. szMessageArray[wStringIndex++] =
  787. pObj->szLibraryName;
  788. szMessageArray[wStringIndex++] =
  789. pObj->szServiceName;
  790. ReportEventW (hEventLog,
  791. EVENTLOG_ERROR_TYPE, // error type
  792. 0, // category (not used)
  793. (DWORD)WBEMPERF_COLLECT_PROC_NOT_FOUND, // event,
  794. NULL, // SID (not used),
  795. wStringIndex, // number of strings
  796. dwDataIndex*sizeof(DWORD), // sizeof raw data
  797. (LPCWSTR *)szMessageArray, // message text array
  798. (LPVOID)&dwRawDataDwords[0]); // raw data
  799. }
  800. }
  801. }
  802. if (Status == ERROR_SUCCESS) {
  803. pObj->CloseProc = (CLOSEPROC)GetProcAddress (
  804. pObj->hLibrary, pObj->szCloseProcName);
  805. if (pObj->CloseProc == NULL) {
  806. if (lEventLogLevel >= LOG_USER) {
  807. Status = GetLastError();
  808. // load data for eventlog message
  809. dwDataIndex = wStringIndex = 0;
  810. dwRawDataDwords[dwDataIndex++] =
  811. (DWORD)Status;
  812. szMessageArray[wStringIndex++] =
  813. ConvertProcName(pObj->szCloseProcName);
  814. szMessageArray[wStringIndex++] =
  815. pObj->szLibraryName;
  816. szMessageArray[wStringIndex++] =
  817. pObj->szServiceName;
  818. ReportEventW (hEventLog,
  819. EVENTLOG_ERROR_TYPE, // error type
  820. 0, // category (not used)
  821. (DWORD)WBEMPERF_CLOSE_PROC_NOT_FOUND, // event,
  822. NULL, // SID (not used),
  823. wStringIndex, // number of strings
  824. dwDataIndex*sizeof(DWORD), // sizeof raw data
  825. (LPCWSTR *)szMessageArray, // message text array
  826. (LPVOID)&dwRawDataDwords[0]); // raw data
  827. }
  828. }
  829. }
  830. if (Status == ERROR_SUCCESS) {
  831. __try {
  832. // start timer
  833. opwInfo.pNext = NULL;
  834. opwInfo.szLibraryName = pObj->szLibraryName;
  835. opwInfo.szServiceName = pObj->szServiceName;
  836. opwInfo.dwWaitTime = pObj->dwOpenTimeout;
  837. #if 0 // disabled for testing
  838. hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
  839. // if no timer, continue anyway, even though things may
  840. // hang, it's better than not loading the DLL since they
  841. // usually load OK
  842. //
  843. if (hPerflibFuncTimer == NULL) {
  844. // unable to get a timer entry
  845. DebugPrint (("\nPERFLIB: Unable to acquire timer for Open Proc"));
  846. }
  847. #endif //test section
  848. // call open procedure to initialize DLL
  849. if (pObj->hMutex != NULL) {
  850. Status = WaitForSingleObject (
  851. pObj->hMutex,
  852. pObj->dwOpenTimeout);
  853. // BUG!!A-DCREWS: If OpenProc is uninitialized, then the condition will
  854. // result in the lockoutcount being incremented
  855. if ((Status != WAIT_TIMEOUT) &&
  856. (pObj->OpenProc != NULL)) {
  857. Status = (*pObj->OpenProc)(pObj->szLinkageString);
  858. ReleaseMutex(pObj->hMutex);
  859. }
  860. else {
  861. pObj->dwLockoutCount++;
  862. }
  863. } else {
  864. Status = ERROR_LOCK_FAILED;
  865. }
  866. // check the result.
  867. if (Status != ERROR_SUCCESS) {
  868. dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
  869. } else {
  870. InterlockedIncrement((LONG *)&pObj->dwOpenCount);
  871. }
  872. if (hPerflibFuncTimer != NULL) {
  873. // kill timer
  874. Status = KillPerflibFunctionTimer (hPerflibFuncTimer);
  875. }
  876. else
  877. dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
  878. } __except (EXCEPTION_EXECUTE_HANDLER) {
  879. Status = GetExceptionCode();
  880. dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION;
  881. }
  882. if (Status != ERROR_SUCCESS) {
  883. // load data for eventlog message
  884. dwDataIndex = wStringIndex = 0;
  885. dwRawDataDwords[dwDataIndex++] =
  886. (DWORD)Status;
  887. szMessageArray[wStringIndex++] =
  888. pObj->szServiceName;
  889. szMessageArray[wStringIndex++] =
  890. pObj->szLibraryName;
  891. ReportEventW (hEventLog,
  892. (WORD)EVENTLOG_ERROR_TYPE, // error type
  893. 0, // category (not used)
  894. dwOpenEvent, // event,
  895. NULL, // SID (not used),
  896. wStringIndex, // number of strings
  897. dwDataIndex*sizeof(DWORD), // sizeof raw data
  898. (LPCWSTR *)szMessageArray, // message text array
  899. (LPVOID)&dwRawDataDwords[0]); // raw data
  900. }
  901. }
  902. if (Status != ERROR_SUCCESS) {
  903. // clear fields
  904. pObj->OpenProc = NULL;
  905. pObj->CollectProc = NULL;
  906. pObj->QueryProc = NULL;
  907. pObj->CloseProc = NULL;
  908. if (pObj->hLibrary != NULL) {
  909. FreeLibrary (pObj->hLibrary);
  910. pObj->hLibrary = NULL;
  911. }
  912. } else {
  913. pObj->llLastUsedTime = GetTimeAsLongLong();
  914. }
  915. } else {
  916. Status = GetLastError();
  917. }
  918. SetErrorMode (nErrorMode);
  919. }
  920. } else {
  921. // else already open so bump the ref count
  922. pObj->llLastUsedTime = GetTimeAsLongLong();
  923. }
  924. return Status;
  925. }
  926. //***************************************************************************
  927. //
  928. // CPerfObjectAccess::AddLibrary (
  929. // IWbemClassObject *pClass,
  930. // IWbemQualifierSet *pClassQualifiers,
  931. // LPCWSTR szRegistryKey,
  932. // DWORD dwPerfIndex)
  933. //
  934. // Adds the library referenced by the class object to the list of
  935. // libraries to call
  936. //
  937. //***************************************************************************
  938. //
  939. DWORD
  940. CPerfObjectAccess::AddLibrary (
  941. IWbemClassObject *pClass,
  942. IWbemQualifierSet *pClassQualifiers,
  943. LPCWSTR szRegistryKey,
  944. DWORD dwPerfIndex)
  945. {
  946. CPerfDataLibrary *pLibEntry = NULL;
  947. LONG Status = ERROR_SUCCESS;
  948. HKEY hServicesKey = NULL;
  949. HKEY hPerfKey = NULL;
  950. LPWSTR szServiceName = NULL;
  951. HKEY hKeyLinkage;
  952. BOOL bUseQueryFn = FALSE;
  953. pExtObject pReturnObject = NULL;
  954. DWORD dwType = 0;
  955. DWORD dwSize = 0;
  956. DWORD dwFlags = 0;
  957. DWORD dwKeep;
  958. DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
  959. DWORD dwObjIndex = 0;
  960. DWORD dwMemBlockSize = sizeof(ExtObject);
  961. DWORD dwLinkageStringLen = 0;
  962. CHAR szOpenProcName[MAX_PATH];
  963. CHAR szCollectProcName[MAX_PATH];
  964. CHAR szCloseProcName[MAX_PATH];
  965. WCHAR szLibraryString[MAX_PATH];
  966. WCHAR szLibraryExpPath[MAX_PATH];
  967. WCHAR mszObjectList[MAX_PATH];
  968. WCHAR szLinkageKeyPath[MAX_PATH];
  969. WCHAR szLinkageString[MAX_PATH];
  970. DWORD dwOpenTimeout = 0;
  971. DWORD dwCollectTimeout = 0;
  972. LPWSTR szThisObject;
  973. LPWSTR szThisChar;
  974. LPSTR pNextStringA;
  975. LPWSTR pNextStringW;
  976. WCHAR szServicePath[MAX_PATH];
  977. WCHAR szMutexName[MAX_PATH];
  978. WCHAR szPID[32];
  979. assert(pClass != NULL);
  980. assert(pClassQualifiers != NULL);
  981. UNREFERENCED_PARAMETER(pClassQualifiers);
  982. UNREFERENCED_PARAMETER(pClass);
  983. pLibEntry = new CPerfDataLibrary;
  984. if ((pLibEntry != NULL) && (szRegistryKey != NULL)) {
  985. lstrcpyW (szServicePath, cszHklmServicesKey);
  986. Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
  987. 0, KEY_READ, &hServicesKey);
  988. if (Status == ERROR_SUCCESS) {
  989. lstrcpyW (szServicePath, szRegistryKey);
  990. lstrcatW (szServicePath, cszPerformance);
  991. Status = RegOpenKeyExW (hServicesKey, szServicePath,
  992. 0, KEY_READ, &hPerfKey);
  993. if (Status == ERROR_SUCCESS) {
  994. szServiceName = (LPWSTR)szRegistryKey;
  995. // read the performance DLL name
  996. dwType = 0;
  997. dwSize = sizeof(szLibraryString);
  998. memset (szLibraryString, 0, sizeof(szLibraryString));
  999. memset (szLibraryString, 0, sizeof(szLibraryExpPath));
  1000. Status = RegQueryValueExW (hPerfKey,
  1001. cszDLLValue,
  1002. NULL,
  1003. &dwType,
  1004. (LPBYTE)szLibraryString,
  1005. &dwSize);
  1006. }
  1007. }
  1008. if (Status == ERROR_SUCCESS) {
  1009. if (dwType == REG_EXPAND_SZ) {
  1010. // expand any environment vars
  1011. dwSize = ExpandEnvironmentStringsW(
  1012. szLibraryString,
  1013. szLibraryExpPath,
  1014. MAX_PATH);
  1015. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  1016. Status = ERROR_INVALID_DLL;
  1017. } else {
  1018. dwSize += 1;
  1019. dwSize *= sizeof(WCHAR);
  1020. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1021. }
  1022. } else if (dwType == REG_SZ) {
  1023. // look for dll and save full file Path
  1024. dwSize = SearchPathW (
  1025. NULL, // use standard system search path
  1026. szLibraryString,
  1027. NULL,
  1028. MAX_PATH,
  1029. szLibraryExpPath,
  1030. NULL);
  1031. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  1032. Status = ERROR_INVALID_DLL;
  1033. } else {
  1034. dwSize += 1;
  1035. dwSize *= sizeof(WCHAR);
  1036. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1037. }
  1038. } else {
  1039. Status = ERROR_INVALID_DLL;
  1040. }
  1041. if (Status == ERROR_SUCCESS) {
  1042. // we have the DLL name so get the procedure names
  1043. dwType = 0;
  1044. dwSize = sizeof(szOpenProcName);
  1045. memset (szOpenProcName, 0, sizeof(szOpenProcName));
  1046. Status = RegQueryValueExA (hPerfKey,
  1047. caszOpenValue,
  1048. NULL,
  1049. &dwType,
  1050. (LPBYTE)szOpenProcName,
  1051. &dwSize);
  1052. }
  1053. if (Status == ERROR_SUCCESS) {
  1054. // add in size of previous string
  1055. // the size value includes the Term. NULL
  1056. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1057. // we have the procedure name so get the timeout value
  1058. dwType = 0;
  1059. dwSize = sizeof(dwOpenTimeout);
  1060. Status = RegQueryValueExW (hPerfKey,
  1061. cszOpenTimeout,
  1062. NULL,
  1063. &dwType,
  1064. (LPBYTE)&dwOpenTimeout,
  1065. &dwSize);
  1066. // if error, then apply default
  1067. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  1068. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  1069. Status = ERROR_SUCCESS;
  1070. }
  1071. }
  1072. if (Status == ERROR_SUCCESS) {
  1073. // get next string
  1074. dwType = 0;
  1075. dwSize = sizeof(szCloseProcName);
  1076. memset (szCloseProcName, 0, sizeof(szCloseProcName));
  1077. Status = RegQueryValueExA (hPerfKey,
  1078. caszCloseValue,
  1079. NULL,
  1080. &dwType,
  1081. (LPBYTE)szCloseProcName,
  1082. &dwSize);
  1083. }
  1084. if (Status == ERROR_SUCCESS) {
  1085. // add in size of previous string
  1086. // the size value includes the Term. NULL
  1087. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1088. // try to look up the query function which is the
  1089. // preferred interface if it's not found, then
  1090. // try the collect function name. If that's not found,
  1091. // then bail
  1092. dwType = 0;
  1093. dwSize = sizeof(szCollectProcName);
  1094. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  1095. Status = RegQueryValueExA (hPerfKey,
  1096. caszQueryValue,
  1097. NULL,
  1098. &dwType,
  1099. (LPBYTE)szCollectProcName,
  1100. &dwSize);
  1101. if (Status == ERROR_SUCCESS) {
  1102. // add in size of the Query Function Name
  1103. // the size value includes the Term. NULL
  1104. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1105. // get next string
  1106. bUseQueryFn = TRUE;
  1107. // the query function can support a static object list
  1108. // so look it up
  1109. } else {
  1110. // the QueryFunction wasn't found so look up the
  1111. // Collect Function name instead
  1112. dwType = 0;
  1113. dwSize = sizeof(szCollectProcName);
  1114. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  1115. Status = RegQueryValueExA (hPerfKey,
  1116. caszCollectValue,
  1117. NULL,
  1118. &dwType,
  1119. (LPBYTE)szCollectProcName,
  1120. &dwSize);
  1121. if (Status == ERROR_SUCCESS) {
  1122. // add in size of Collect Function Name
  1123. // the size value includes the Term. NULL
  1124. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1125. }
  1126. }
  1127. if (Status == ERROR_SUCCESS) {
  1128. // we have the procedure name so get the timeout value
  1129. dwType = 0;
  1130. dwSize = sizeof(dwCollectTimeout);
  1131. Status = RegQueryValueExW (hPerfKey,
  1132. cszCollectTimeout,
  1133. NULL,
  1134. &dwType,
  1135. (LPBYTE)&dwCollectTimeout,
  1136. &dwSize);
  1137. // if error, then apply default
  1138. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  1139. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  1140. Status = ERROR_SUCCESS;
  1141. }
  1142. }
  1143. // get the list of supported objects if provided by the registry
  1144. dwType = 0;
  1145. dwSize = sizeof(mszObjectList);
  1146. memset (mszObjectList, 0, sizeof(mszObjectList));
  1147. Status = RegQueryValueExW (hPerfKey,
  1148. cszObjListValue,
  1149. NULL,
  1150. &dwType,
  1151. (LPBYTE)mszObjectList,
  1152. &dwSize);
  1153. if (Status == ERROR_SUCCESS) {
  1154. if (dwType != REG_MULTI_SZ) {
  1155. // convert space delimited list to msz
  1156. for (szThisChar = mszObjectList; *szThisChar != 0; szThisChar++) {
  1157. if (*szThisChar == L' ') *szThisChar = L'\0';
  1158. }
  1159. ++szThisChar;
  1160. *szThisChar = 0; // add MSZ term Null
  1161. }
  1162. for (szThisObject = mszObjectList, dwObjIndex = 0;
  1163. (*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
  1164. szThisObject += lstrlenW(szThisObject) + 1) {
  1165. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  1166. dwObjIndex++;
  1167. }
  1168. if (*szThisObject != 0) {
  1169. DWORD dwDataIndex = 0;
  1170. WORD wStringIndex = 0;
  1171. DWORD dwRawDataDwords[8];
  1172. LPWSTR szMessageArray[8];
  1173. dwRawDataDwords[dwDataIndex++] = (DWORD) ERROR_SUCCESS;
  1174. szMessageArray[wStringIndex++] = (LPWSTR) cszObjListValue;
  1175. szMessageArray[wStringIndex++] = szLibraryString;
  1176. szMessageArray[wStringIndex++] = szServicePath;
  1177. ReportEventW(hEventLog,
  1178. EVENTLOG_WARNING_TYPE,
  1179. 0,
  1180. (DWORD) WBEMPERF_TOO_MANY_OBJECT_IDS,
  1181. NULL,
  1182. wStringIndex,
  1183. dwDataIndex * sizeof(DWORD),
  1184. (LPCWSTR *) szMessageArray,
  1185. (LPVOID) & dwRawDataDwords[0]);
  1186. }
  1187. } else {
  1188. // reset status since not having this is
  1189. // not a showstopper
  1190. Status = ERROR_SUCCESS;
  1191. }
  1192. if (Status == ERROR_SUCCESS) {
  1193. dwType = 0;
  1194. dwKeep = 0;
  1195. dwSize = sizeof(dwKeep);
  1196. Status = RegQueryValueExW (hPerfKey,
  1197. cszKeepResident,
  1198. NULL,
  1199. &dwType,
  1200. (LPBYTE)&dwKeep,
  1201. &dwSize);
  1202. if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  1203. if (dwKeep == 1) {
  1204. dwFlags |= PERF_EO_KEEP_RESIDENT;
  1205. } else {
  1206. // no change.
  1207. }
  1208. } else {
  1209. // not fatal, just use the defaults.
  1210. Status = ERROR_SUCCESS;
  1211. }
  1212. }
  1213. }
  1214. }
  1215. if (Status == ERROR_SUCCESS) {
  1216. memset (szLinkageString, 0, sizeof(szLinkageString));
  1217. lstrcpyW (szLinkageKeyPath, szServiceName);
  1218. lstrcatW (szLinkageKeyPath, cszLinkageKey);
  1219. Status = RegOpenKeyExW (
  1220. hServicesKey,
  1221. szLinkageKeyPath,
  1222. 0L,
  1223. KEY_READ,
  1224. &hKeyLinkage);
  1225. if (Status == ERROR_SUCCESS) {
  1226. // look up export value string
  1227. dwSize = sizeof(szLinkageString);
  1228. dwType = 0;
  1229. Status = RegQueryValueExW (
  1230. hKeyLinkage,
  1231. cszExportValue,
  1232. NULL,
  1233. &dwType,
  1234. (LPBYTE)&szLinkageString,
  1235. &dwSize);
  1236. if ((Status != ERROR_SUCCESS) ||
  1237. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  1238. // clear buffer
  1239. memset (szLinkageString, 0, sizeof(szLinkageString));
  1240. dwLinkageStringLen = 0;
  1241. // not finding a linkage key is not fatal so correct
  1242. // status
  1243. Status = ERROR_SUCCESS;
  1244. } else {
  1245. // add size of linkage string to buffer
  1246. // the size value includes the Term. NULL
  1247. dwLinkageStringLen = dwSize;
  1248. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1249. }
  1250. RegCloseKey (hKeyLinkage);
  1251. } else {
  1252. // not finding a linkage key is not fatal so correct
  1253. // status
  1254. Status = ERROR_SUCCESS;
  1255. }
  1256. }
  1257. if (Status == ERROR_SUCCESS) {
  1258. // add in size of service name
  1259. dwSize = lstrlenW (szServiceName);
  1260. dwSize += 1;
  1261. dwSize *= sizeof(WCHAR);
  1262. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  1263. // allocate and initialize a new ext. object block
  1264. pReturnObject = (pExtObject)ALLOCMEM(m_hObjectHeap,
  1265. HEAP_ZERO_MEMORY, dwMemBlockSize);
  1266. if (pReturnObject != NULL) {
  1267. // copy values to new buffer (all others are NULL)
  1268. pNextStringA = (LPSTR)&pReturnObject[1];
  1269. // copy Open Procedure Name
  1270. pReturnObject->szOpenProcName = pNextStringA;
  1271. lstrcpyA (pNextStringA, szOpenProcName);
  1272. pNextStringA += lstrlenA (pNextStringA) + 1;
  1273. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  1274. pReturnObject->dwOpenTimeout = dwOpenTimeout;
  1275. // copy collect function or query function, depending
  1276. pReturnObject->szCollectProcName = pNextStringA;
  1277. lstrcpyA (pNextStringA, szCollectProcName);
  1278. pNextStringA += lstrlenA (pNextStringA) + 1;
  1279. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  1280. pReturnObject->dwCollectTimeout = dwCollectTimeout;
  1281. // copy Close Procedure Name
  1282. pReturnObject->szCloseProcName = pNextStringA;
  1283. lstrcpyA (pNextStringA, szCloseProcName);
  1284. pNextStringA += lstrlenA (pNextStringA) + 1;
  1285. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  1286. // copy Library path
  1287. pNextStringW = (LPWSTR)pNextStringA;
  1288. pReturnObject->szLibraryName = pNextStringW;
  1289. lstrcpyW (pNextStringW, szLibraryExpPath);
  1290. pNextStringW += lstrlenW (pNextStringW) + 1;
  1291. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1292. // copy Linkage String if there is one
  1293. if (*szLinkageString != 0) {
  1294. pReturnObject->szLinkageString = pNextStringW;
  1295. memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
  1296. // length includes extra NULL char and is in BYTES
  1297. pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
  1298. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1299. }
  1300. // copy Service name
  1301. pReturnObject->szServiceName = pNextStringW;
  1302. lstrcpyW (pNextStringW, szServiceName);
  1303. pNextStringW += lstrlenW (pNextStringW) + 1;
  1304. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  1305. // load flags
  1306. if (bUseQueryFn) {
  1307. dwFlags |= PERF_EO_QUERY_FUNC;
  1308. }
  1309. pReturnObject->dwFlags = dwFlags;
  1310. pReturnObject->hPerfKey = hPerfKey;
  1311. // load Object array
  1312. if (dwObjIndex > 0) {
  1313. pReturnObject->dwNumObjects = dwObjIndex;
  1314. memcpy (pReturnObject->dwObjList,
  1315. dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
  1316. }
  1317. pReturnObject->llLastUsedTime = 0;
  1318. // create Mutex name
  1319. lstrcpyW (szMutexName, szRegistryKey);
  1320. lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
  1321. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  1322. lstrcatW (szMutexName, szPID);
  1323. // pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
  1324. pReturnObject->hMutex = CreateMutexAsProcess(szMutexName);
  1325. } else {
  1326. Status = ERROR_OUTOFMEMORY;
  1327. }
  1328. }
  1329. if (Status != ERROR_SUCCESS) {
  1330. SetLastError (Status);
  1331. if (pReturnObject != NULL) {
  1332. // release the new block
  1333. FREEMEM (m_hObjectHeap, 0, pReturnObject);
  1334. }
  1335. } else {
  1336. if (pReturnObject != NULL) {
  1337. Status = OpenExtObjectLibrary (pReturnObject);
  1338. if (Status == ERROR_SUCCESS) {
  1339. if (dwPerfIndex != 0) {
  1340. // initialize the perf index string
  1341. _ultow (dwPerfIndex, pLibEntry->szQueryString, 10);
  1342. } else {
  1343. lstrcpyW (pLibEntry->szQueryString, cszGlobal);
  1344. }
  1345. // save the pointer to the initialize structure
  1346. pLibEntry->pLibInfo = pReturnObject;
  1347. m_aLibraries.Add(pLibEntry);
  1348. pLibEntry->dwRefCount++;
  1349. assert(pLibEntry->dwRefCount == 1);
  1350. } else {
  1351. // release the new block
  1352. FREEMEM (m_hObjectHeap, 0, pReturnObject);
  1353. }
  1354. }
  1355. }
  1356. if (hServicesKey != NULL) RegCloseKey (hServicesKey);
  1357. } else { // gets here if pLibEntry == NULL and/or szRegistryKey == NULL
  1358. if (pLibEntry == NULL) {
  1359. Status = ERROR_OUTOFMEMORY;
  1360. }
  1361. if (szRegistryKey == NULL) {
  1362. Status = ERROR_INVALID_PARAMETER;
  1363. }
  1364. }
  1365. if ((Status != ERROR_SUCCESS) && (pLibEntry != NULL))
  1366. delete pLibEntry;
  1367. return Status;
  1368. }
  1369. //***************************************************************************
  1370. //
  1371. // CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
  1372. //
  1373. // Adds the specified WBEM performance object class and any required library
  1374. // entries to the access object.
  1375. //
  1376. //***************************************************************************
  1377. //
  1378. DWORD
  1379. CPerfObjectAccess::AddClass (IWbemClassObject *pClass, BOOL bCatalogQuery)
  1380. {
  1381. CPerfDataLibrary *pLibEntry = NULL;
  1382. CPerfDataLibrary *pThisLibEntry = NULL;
  1383. DWORD dwIndex, dwEnd;
  1384. LPWSTR szRegistryKey = NULL;
  1385. IWbemQualifierSet *pClassQualifiers = NULL;
  1386. VARIANT vRegistryKey;
  1387. HRESULT hRes;
  1388. DWORD dwReturn = ERROR_SUCCESS;
  1389. DWORD dwPerfIndex = 0;
  1390. VariantInit (&vRegistryKey);
  1391. // get the Qualifier Set for this class
  1392. hRes = pClass->GetQualifierSet(&pClassQualifiers);
  1393. assert (hRes == 0);
  1394. // now get the library and procedure names
  1395. hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 0, &vRegistryKey, 0);
  1396. if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
  1397. szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
  1398. if (szRegistryKey == NULL) {
  1399. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1400. }
  1401. else {
  1402. // now also get the perf index
  1403. if (bCatalogQuery) {
  1404. // then insert 0 for the perf index to indicate a "GLOBAL"
  1405. // query
  1406. dwPerfIndex = 0;
  1407. } else {
  1408. VariantClear (&vRegistryKey);
  1409. hRes = pClassQualifiers->Get(CBSTR(cszPerfIndex), 0, &vRegistryKey, 0);
  1410. if (hRes == 0) {
  1411. dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
  1412. } else {
  1413. // unable to find NtPerfLibrary entry
  1414. dwReturn = ERROR_FILE_NOT_FOUND;
  1415. }
  1416. }
  1417. }
  1418. } else {
  1419. // unable to find NtPerfLibrary entry
  1420. dwReturn = ERROR_FILE_NOT_FOUND;
  1421. }
  1422. if (pClassQualifiers != NULL) pClassQualifiers->Release();
  1423. if (dwReturn == ERROR_SUCCESS) {
  1424. // find matching library in the array
  1425. dwEnd = m_aLibraries.Size();
  1426. if (dwEnd > 0) {
  1427. // walk down the list of libraries
  1428. for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
  1429. // see if this library entry is good enough to keep
  1430. // The library is assumed to be a match if the
  1431. // lib. name and all proc's are the same.
  1432. pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
  1433. assert (pThisLibEntry != NULL); // it should have been removed!
  1434. // make sure it's complete
  1435. assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
  1436. if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
  1437. pLibEntry = pThisLibEntry;
  1438. break;
  1439. } else {
  1440. // wrong library
  1441. // so continue
  1442. }
  1443. }
  1444. }
  1445. if (pLibEntry == NULL) {
  1446. // add this class & it's library to the list
  1447. dwReturn = AddLibrary (pClass, pClassQualifiers, szRegistryKey, dwPerfIndex);
  1448. } else {
  1449. WCHAR wszNewIndex[MAX_PATH];
  1450. pLibEntry->dwRefCount++;
  1451. _ultow (dwPerfIndex, wszNewIndex, 10);
  1452. if (!IsNumberInUnicodeList (dwPerfIndex, pLibEntry->szQueryString)) {
  1453. // then add it to the list
  1454. lstrcatW (pLibEntry->szQueryString, cszSpace);
  1455. lstrcatW (pLibEntry->szQueryString, wszNewIndex);
  1456. }
  1457. }
  1458. }
  1459. if (szRegistryKey != NULL) delete szRegistryKey;
  1460. VariantClear(&vRegistryKey);
  1461. return dwReturn;
  1462. }
  1463. //***************************************************************************
  1464. //
  1465. // CPerfObjectAccess::CollectData (LPBYTE pBuffer,
  1466. // LPDWORD pdwBufferSize, LPWSTR pszItemList)
  1467. //
  1468. // Collects data from the perf objects and libraries added to the access
  1469. // object
  1470. //
  1471. // Inputs:
  1472. //
  1473. // pBuffer - pointer to start of data block
  1474. // where data is being collected
  1475. //
  1476. // pdwBufferSize - pointer to size of data buffer
  1477. //
  1478. // pszItemList - string to pass to ext DLL
  1479. //
  1480. // Outputs:
  1481. //
  1482. // *lppDataDefinition - set to location for next Type
  1483. // Definition if successful
  1484. //
  1485. // Returns:
  1486. //
  1487. // 0 if successful, else Win 32 error code of failure
  1488. //
  1489. //
  1490. //***************************************************************************
  1491. //
  1492. DWORD
  1493. CPerfObjectAccess::CollectData (LPBYTE pBuffer, LPDWORD pdwBufferSize, LPWSTR pszItemList)
  1494. {
  1495. LPWSTR lpValueName = NULL;
  1496. LPBYTE lpData = pBuffer;
  1497. LPDWORD lpcbData = pdwBufferSize;
  1498. LPVOID lpDataDefinition = NULL;
  1499. DWORD Win32Error=ERROR_SUCCESS; // Failure code
  1500. DWORD BytesLeft;
  1501. DWORD NumObjectTypes;
  1502. LPVOID lpExtDataBuffer = NULL;
  1503. LPVOID lpCallBuffer = NULL;
  1504. LPVOID lpLowGuardPage = NULL;
  1505. LPVOID lpHiGuardPage = NULL;
  1506. LPVOID lpEndPointer = NULL;
  1507. LPVOID lpBufferBefore = NULL;
  1508. LPVOID lpBufferAfter = NULL;
  1509. LPDWORD lpCheckPointer;
  1510. LARGE_INTEGER liStartTime, liEndTime, liWaitTime;
  1511. pExtObject pThisExtObj = NULL;
  1512. BOOL bGuardPageOK;
  1513. BOOL bBufferOK;
  1514. BOOL bException;
  1515. BOOL bUseSafeBuffer;
  1516. BOOL bUnlockObjData = FALSE;
  1517. LPWSTR szMessageArray[8];
  1518. DWORD dwRawDataDwords[8]; // raw data buffer
  1519. DWORD dwDataIndex;
  1520. WORD wStringIndex;
  1521. LONG lReturnValue = ERROR_SUCCESS;
  1522. LONG lInstIndex;
  1523. PERF_OBJECT_TYPE *pObject, *pNextObject;
  1524. PERF_INSTANCE_DEFINITION *pInstance;
  1525. PERF_DATA_BLOCK *pPerfData;
  1526. BOOL bForeignDataBuffer;
  1527. DWORD dwItemsInList = 0;
  1528. DWORD dwIndex, dwEntry;
  1529. CPerfDataLibrary *pThisLib;
  1530. liStartTime.QuadPart = 0;
  1531. liEndTime.QuadPart = 0;
  1532. if (lExtCounterTestLevel < EXT_TEST_NOMEMALLOC) {
  1533. bUseSafeBuffer = TRUE;
  1534. } else {
  1535. bUseSafeBuffer = FALSE;
  1536. }
  1537. lReturnValue = RegisterExtObjListAccess();
  1538. if (lReturnValue == ERROR_SUCCESS) {
  1539. if (*pdwBufferSize > (sizeof(PERF_DATA_BLOCK) *2)) {
  1540. MonBuildPerfDataBlock(
  1541. (PERF_DATA_BLOCK *)pBuffer,
  1542. &lpDataDefinition,
  1543. 0,0);
  1544. dwItemsInList = m_aLibraries.Size();
  1545. } else {
  1546. lReturnValue = ERROR_MORE_DATA;
  1547. dwItemsInList = 0;
  1548. }
  1549. if (dwItemsInList > 0) {
  1550. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  1551. pThisLib = (CPerfDataLibrary *)m_aLibraries[dwEntry];
  1552. assert (pThisLib != NULL);
  1553. pThisExtObj = pThisLib->pLibInfo;
  1554. if (pszItemList == NULL) {
  1555. // use the one for this library
  1556. lpValueName = pThisLib->szQueryString;
  1557. } else {
  1558. // use the one passed by the caller
  1559. lpValueName = pszItemList;
  1560. }
  1561. // convert timeout value
  1562. liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
  1563. // initialize values to pass to the extensible counter function
  1564. NumObjectTypes = 0;
  1565. BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData));
  1566. bException = FALSE;
  1567. if (pThisExtObj->hLibrary == NULL) {
  1568. // lock library object
  1569. if (pThisExtObj->hMutex != NULL) {
  1570. Win32Error = WaitForSingleObject (
  1571. pThisExtObj->hMutex,
  1572. pThisExtObj->dwCollectTimeout);
  1573. if (Win32Error != WAIT_TIMEOUT) {
  1574. // if necessary, open the library
  1575. if (pThisExtObj->hLibrary == NULL) {
  1576. // make sure the library is open
  1577. Win32Error = OpenExtObjectLibrary(pThisExtObj);
  1578. if (Win32Error != ERROR_SUCCESS) {
  1579. // assume error has been posted
  1580. ReleaseMutex (pThisExtObj->hMutex);
  1581. continue; // to next entry
  1582. }
  1583. }
  1584. ReleaseMutex (pThisExtObj->hMutex);
  1585. } else {
  1586. pThisExtObj->dwLockoutCount++;
  1587. }
  1588. } else {
  1589. Win32Error = ERROR_LOCK_FAILED;
  1590. }
  1591. } else {
  1592. // library should be ready to use
  1593. }
  1594. // allocate a local block of memory to pass to the
  1595. // extensible counter function.
  1596. if (bUseSafeBuffer) {
  1597. lpExtDataBuffer = ALLOCMEM (m_hObjectHeap,
  1598. HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE));
  1599. } else {
  1600. lpExtDataBuffer =
  1601. lpCallBuffer = lpDataDefinition;
  1602. }
  1603. if (lpExtDataBuffer != NULL) {
  1604. if (bUseSafeBuffer) {
  1605. // set buffer pointers
  1606. lpLowGuardPage = lpExtDataBuffer;
  1607. lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
  1608. lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
  1609. lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
  1610. lpBufferBefore = lpCallBuffer;
  1611. lpBufferAfter = NULL;
  1612. // initialize GuardPage Data
  1613. memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  1614. memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  1615. }
  1616. __try {
  1617. //
  1618. // Collect data from extesible objects
  1619. //
  1620. bUnlockObjData = FALSE;
  1621. if (pThisExtObj->hMutex != NULL) {
  1622. Win32Error = WaitForSingleObject (
  1623. pThisExtObj->hMutex,
  1624. pThisExtObj->dwCollectTimeout);
  1625. // BUG!!A-DCREWS: If CollectProc is uninitialized, then the condition will
  1626. // result in the lockoutcount being incremented
  1627. if ((Win32Error != WAIT_TIMEOUT) &&
  1628. (pThisExtObj->CollectProc != NULL)) {
  1629. bUnlockObjData = TRUE;
  1630. QueryPerformanceCounter (&liStartTime);
  1631. Win32Error = (*pThisExtObj->CollectProc) (
  1632. lpValueName,
  1633. &lpCallBuffer,
  1634. &BytesLeft,
  1635. &NumObjectTypes);
  1636. QueryPerformanceCounter (&liEndTime);
  1637. pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
  1638. ReleaseMutex (pThisExtObj->hMutex);
  1639. bUnlockObjData = FALSE;
  1640. } else {
  1641. pThisExtObj->dwLockoutCount++;
  1642. }
  1643. } else {
  1644. Win32Error = ERROR_LOCK_FAILED;
  1645. }
  1646. if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
  1647. // increment perf counters
  1648. InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
  1649. pThisExtObj->llElapsedTime +=
  1650. liEndTime.QuadPart - liStartTime.QuadPart;
  1651. if (bUseSafeBuffer) {
  1652. // a data buffer was returned and
  1653. // the function returned OK so see how things
  1654. // turned out...
  1655. //
  1656. lpBufferAfter = lpCallBuffer;
  1657. //
  1658. // check for buffer corruption here
  1659. //
  1660. bBufferOK = TRUE; // assume it's ok until a check fails
  1661. //
  1662. if (lExtCounterTestLevel <= EXT_TEST_BASIC) {
  1663. //
  1664. // check 1: bytes left should be the same as
  1665. // new data buffer ptr - orig data buffer ptr
  1666. //
  1667. if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
  1668. if (lEventLogLevel >= LOG_DEBUG) {
  1669. // issue WARNING, that bytes left param is incorrect
  1670. // load data for eventlog message
  1671. // since this error is correctable (though with
  1672. // some risk) this won't be reported at LOG_USER
  1673. // level
  1674. dwDataIndex = wStringIndex = 0;
  1675. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  1676. dwRawDataDwords[dwDataIndex++] =
  1677. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  1678. szMessageArray[wStringIndex++] =
  1679. pThisExtObj->szServiceName;
  1680. szMessageArray[wStringIndex++] =
  1681. pThisExtObj->szLibraryName;
  1682. ReportEventW (hEventLog,
  1683. EVENTLOG_WARNING_TYPE, // error type
  1684. 0, // category (not used)
  1685. (DWORD)WBEMPERF_BUFFER_POINTER_MISMATCH, // event,
  1686. NULL, // SID (not used),
  1687. wStringIndex, // number of strings
  1688. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1689. (LPCWSTR *)szMessageArray, // message text array
  1690. (LPVOID)&dwRawDataDwords[0]); // raw data
  1691. }
  1692. // we'll keep the buffer, since the returned bytes left
  1693. // value is ignored anyway, in order to make the
  1694. // rest of this function work, we'll fix it here
  1695. BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  1696. }
  1697. //
  1698. // check 2: buffer after ptr should be < hi Guard page ptr
  1699. //
  1700. if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) {
  1701. // see if they exceeded the allocated memory
  1702. if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
  1703. // this is very serious since they've probably trashed
  1704. // the heap by overwriting the heap sig. block
  1705. // issue ERROR, buffer overrun
  1706. if (lEventLogLevel >= LOG_USER) {
  1707. // load data for eventlog message
  1708. dwDataIndex = wStringIndex = 0;
  1709. dwRawDataDwords[dwDataIndex++] =
  1710. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  1711. szMessageArray[wStringIndex++] =
  1712. pThisExtObj->szLibraryName;
  1713. szMessageArray[wStringIndex++] =
  1714. pThisExtObj->szServiceName;
  1715. ReportEventW (hEventLog,
  1716. EVENTLOG_ERROR_TYPE, // error type
  1717. 0, // category (not used)
  1718. (DWORD)WBEMPERF_HEAP_ERROR, // event,
  1719. NULL, // SID (not used),
  1720. wStringIndex, // number of strings
  1721. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1722. (LPCWSTR *)szMessageArray, // message text array
  1723. (LPVOID)&dwRawDataDwords[0]); // raw data
  1724. }
  1725. } else {
  1726. // issue ERROR, buffer overrun
  1727. if (lEventLogLevel >= LOG_USER) {
  1728. // load data for eventlog message
  1729. dwDataIndex = wStringIndex = 0;
  1730. dwRawDataDwords[dwDataIndex++] =
  1731. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  1732. szMessageArray[wStringIndex++] =
  1733. pThisExtObj->szLibraryName;
  1734. szMessageArray[wStringIndex++] =
  1735. pThisExtObj->szServiceName;
  1736. ReportEventW (hEventLog,
  1737. EVENTLOG_ERROR_TYPE, // error type
  1738. 0, // category (not used)
  1739. (DWORD)WBEMPERF_BUFFER_OVERFLOW, // event,
  1740. NULL, // SID (not used),
  1741. wStringIndex, // number of strings
  1742. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1743. (LPCWSTR *)szMessageArray, // message text array
  1744. (LPVOID)&dwRawDataDwords[0]); // raw data
  1745. }
  1746. }
  1747. bBufferOK = FALSE;
  1748. // since the DLL overran the buffer, the buffer
  1749. // must be too small (no comments about the DLL
  1750. // will be made here) so the status will be
  1751. // changed to ERROR_MORE_DATA and the function
  1752. // will return.
  1753. Win32Error = ERROR_MORE_DATA;
  1754. }
  1755. //
  1756. // check 3: check lo guard page for corruption
  1757. //
  1758. if (bBufferOK) {
  1759. bGuardPageOK = TRUE;
  1760. for (lpCheckPointer = (LPDWORD)lpLowGuardPage;
  1761. lpCheckPointer < (LPDWORD)lpBufferBefore;
  1762. lpCheckPointer++) {
  1763. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  1764. bGuardPageOK = FALSE;
  1765. break;
  1766. }
  1767. }
  1768. if (!bGuardPageOK) {
  1769. // issue ERROR, Lo Guard Page corrupted
  1770. if (lEventLogLevel >= LOG_USER) {
  1771. // load data for eventlog message
  1772. dwDataIndex = wStringIndex = 0;
  1773. szMessageArray[wStringIndex++] =
  1774. pThisExtObj->szLibraryName;
  1775. szMessageArray[wStringIndex++] =
  1776. pThisExtObj->szServiceName;
  1777. ReportEventW (hEventLog,
  1778. EVENTLOG_ERROR_TYPE, // error type
  1779. 0, // category (not used)
  1780. (DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event
  1781. NULL, // SID (not used),
  1782. wStringIndex, // number of strings
  1783. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1784. (LPCWSTR *)szMessageArray, // message text array
  1785. (LPVOID)&dwRawDataDwords[0]); // raw data
  1786. }
  1787. bBufferOK = FALSE;
  1788. }
  1789. }
  1790. //
  1791. // check 4: check hi guard page for corruption
  1792. //
  1793. if (bBufferOK) {
  1794. bGuardPageOK = TRUE;
  1795. for (lpCheckPointer = (LPDWORD)lpHiGuardPage;
  1796. lpCheckPointer < (LPDWORD)lpEndPointer;
  1797. lpCheckPointer++) {
  1798. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  1799. bGuardPageOK = FALSE;
  1800. break;
  1801. }
  1802. }
  1803. if (!bGuardPageOK) {
  1804. // issue ERROR, Hi Guard Page corrupted
  1805. if (lEventLogLevel >= LOG_USER) {
  1806. // load data for eventlog message
  1807. dwDataIndex = wStringIndex = 0;
  1808. szMessageArray[wStringIndex++] =
  1809. pThisExtObj->szLibraryName;
  1810. szMessageArray[wStringIndex++] =
  1811. pThisExtObj->szServiceName;
  1812. ReportEventW (hEventLog,
  1813. EVENTLOG_ERROR_TYPE, // error type
  1814. 0, // category (not used)
  1815. (DWORD)WBEMPERF_GUARD_PAGE_VIOLATION, // event,
  1816. NULL, // SID (not used),
  1817. wStringIndex, // number of strings
  1818. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1819. (LPCWSTR *)szMessageArray, // message text array
  1820. (LPVOID)&dwRawDataDwords[0]); // raw data
  1821. }
  1822. bBufferOK = FALSE;
  1823. }
  1824. }
  1825. //
  1826. if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) {
  1827. //
  1828. // Internal consistency checks
  1829. //
  1830. //
  1831. // Check 5: Check object length field values
  1832. //
  1833. // first test to see if this is a foreign
  1834. // computer data block or not
  1835. //
  1836. pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
  1837. if ((pPerfData->Signature[0] == (WCHAR)'P') &&
  1838. (pPerfData->Signature[1] == (WCHAR)'E') &&
  1839. (pPerfData->Signature[2] == (WCHAR)'R') &&
  1840. (pPerfData->Signature[3] == (WCHAR)'F')) {
  1841. // if this is a foreign computer data block, then the
  1842. // first object is after the header
  1843. pObject = (PERF_OBJECT_TYPE *) (
  1844. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  1845. bForeignDataBuffer = TRUE;
  1846. } else {
  1847. // otherwise, if this is just a buffer from
  1848. // an extensible counter, the object starts
  1849. // at the beginning of the buffer
  1850. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  1851. bForeignDataBuffer = FALSE;
  1852. }
  1853. // go to where the pointers say the end of the
  1854. // buffer is and then see if it's where it
  1855. // should be
  1856. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  1857. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  1858. pObject->TotalByteLength);
  1859. }
  1860. if ((LPBYTE)pObject != (LPBYTE)lpCallBuffer) {
  1861. // then a length field is incorrect. This is FATAL
  1862. // since it can corrupt the rest of the buffer
  1863. // and render the buffer unusable.
  1864. if (lEventLogLevel >= LOG_USER) {
  1865. // load data for eventlog message
  1866. dwDataIndex = wStringIndex = 0;
  1867. dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
  1868. szMessageArray[wStringIndex++] =
  1869. pThisExtObj->szLibraryName;
  1870. szMessageArray[wStringIndex++] =
  1871. pThisExtObj->szServiceName;
  1872. ReportEventW (hEventLog,
  1873. EVENTLOG_ERROR_TYPE, // error type
  1874. 0, // category (not used)
  1875. (DWORD)WBEMPERF_INCORRECT_OBJECT_LENGTH, // event,
  1876. NULL, // SID (not used),
  1877. wStringIndex, // number of strings
  1878. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1879. (LPCWSTR *)szMessageArray, // message text array
  1880. (LPVOID)&dwRawDataDwords[0]); // raw data
  1881. }
  1882. bBufferOK = FALSE;
  1883. }
  1884. //
  1885. // Test 6: Test instance field size values
  1886. //
  1887. if (bBufferOK) {
  1888. // set object pointer
  1889. if (bForeignDataBuffer) {
  1890. pObject = (PERF_OBJECT_TYPE *) (
  1891. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  1892. } else {
  1893. // otherwise, if this is just a buffer from
  1894. // an extensible counter, the object starts
  1895. // at the beginning of the buffer
  1896. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  1897. }
  1898. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  1899. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  1900. pObject->TotalByteLength);
  1901. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  1902. pInstance = (PERF_INSTANCE_DEFINITION *)
  1903. ((LPBYTE)pObject + pObject->DefinitionLength);
  1904. lInstIndex = 0;
  1905. while (lInstIndex < pObject->NumInstances) {
  1906. PERF_COUNTER_BLOCK *pCounterBlock;
  1907. pCounterBlock = (PERF_COUNTER_BLOCK *)
  1908. ((PCHAR) pInstance + pInstance->ByteLength);
  1909. pInstance = (PERF_INSTANCE_DEFINITION *)
  1910. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  1911. lInstIndex++;
  1912. }
  1913. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  1914. bBufferOK = FALSE;
  1915. }
  1916. }
  1917. if (!bBufferOK) {
  1918. break;
  1919. } else {
  1920. pObject = pNextObject;
  1921. }
  1922. }
  1923. if (!bBufferOK) {
  1924. if (lEventLogLevel >= LOG_USER) {
  1925. // load data for eventlog message
  1926. dwDataIndex = wStringIndex = 0;
  1927. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  1928. szMessageArray[wStringIndex++] =
  1929. pThisExtObj->szLibraryName;
  1930. szMessageArray[wStringIndex++] =
  1931. pThisExtObj->szServiceName;
  1932. ReportEventW (hEventLog,
  1933. EVENTLOG_ERROR_TYPE, // error type
  1934. 0, // category (not used)
  1935. (DWORD)WBEMPERF_INCORRECT_INSTANCE_LENGTH, // event,
  1936. NULL, // SID (not used),
  1937. wStringIndex, // number of strings
  1938. dwDataIndex*sizeof(DWORD), // sizeof raw data
  1939. (LPCWSTR *)szMessageArray, // message text array
  1940. (LPVOID)&dwRawDataDwords[0]); // raw data
  1941. }
  1942. }
  1943. }
  1944. }
  1945. }
  1946. //
  1947. // if all the tests pass,then copy the data to the
  1948. // original buffer and update the pointers
  1949. if (bBufferOK) {
  1950. RtlMoveMemory (lpDataDefinition,
  1951. lpBufferBefore,
  1952. BytesLeft); // returned buffer size
  1953. } else {
  1954. NumObjectTypes = 0; // since this buffer was tossed
  1955. BytesLeft = 0; // reset the size value since the buffer wasn't used
  1956. }
  1957. } else {
  1958. // function already copied data to caller's buffer
  1959. // so no further action is necessary
  1960. }
  1961. lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
  1962. } else {
  1963. if (Win32Error != ERROR_SUCCESS) {
  1964. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1965. }
  1966. if (bUnlockObjData) {
  1967. ReleaseMutex (pThisExtObj->hMutex);
  1968. }
  1969. NumObjectTypes = 0; // clear counter
  1970. }// end if function returned successfully
  1971. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1972. Win32Error = GetExceptionCode();
  1973. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1974. bException = TRUE;
  1975. if (bUnlockObjData) {
  1976. ReleaseMutex (pThisExtObj->hMutex);
  1977. bUnlockObjData = FALSE;
  1978. }
  1979. }
  1980. if (bUseSafeBuffer) {
  1981. FREEMEM (m_hObjectHeap, 0, lpExtDataBuffer);
  1982. }
  1983. } else {
  1984. // unable to allocate memory so set error value
  1985. Win32Error = ERROR_OUTOFMEMORY;
  1986. } // end if temp buffer allocated successfully
  1987. //
  1988. // Update the count of the number of object types
  1989. //
  1990. ((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
  1991. if ( Win32Error != ERROR_SUCCESS) {
  1992. if (bException ||
  1993. !((Win32Error == ERROR_MORE_DATA) ||
  1994. (Win32Error == WAIT_TIMEOUT))) {
  1995. // inform on exceptions & illegal error status only
  1996. if (lEventLogLevel >= LOG_USER) {
  1997. // load data for eventlog message
  1998. dwDataIndex = wStringIndex = 0;
  1999. dwRawDataDwords[dwDataIndex++] = Win32Error;
  2000. szMessageArray[wStringIndex++] =
  2001. pThisExtObj->szServiceName;
  2002. szMessageArray[wStringIndex++] =
  2003. pThisExtObj->szLibraryName;
  2004. ReportEventW (hEventLog,
  2005. EVENTLOG_ERROR_TYPE, // error type
  2006. 0, // category (not used)
  2007. (DWORD)WBEMPERF_COLLECT_PROC_EXCEPTION, // event,
  2008. NULL, // SID (not used),
  2009. wStringIndex, // number of strings
  2010. dwDataIndex*sizeof(DWORD), // sizeof raw data
  2011. (LPCWSTR *)szMessageArray, // message text array
  2012. (LPVOID)&dwRawDataDwords[0]); // raw data
  2013. } else {
  2014. // don't report
  2015. }
  2016. }
  2017. // the ext. dll is only supposed to return:
  2018. // ERROR_SUCCESS even if it encountered a problem, OR
  2019. // ERROR_MODE_DATA if the buffer was too small.
  2020. // if it's ERROR_MORE_DATA, then break and return the
  2021. // error now, since it'll just be returned again and again.
  2022. if (Win32Error == ERROR_MORE_DATA) {
  2023. lReturnValue = Win32Error;
  2024. break;
  2025. }
  2026. }
  2027. } // end for each object
  2028. } // else an error occurred so unable to call functions
  2029. Win32Error = DeRegisterExtObjListAccess();
  2030. ((PPERF_DATA_BLOCK) lpData)->TotalByteLength = (DWORD)
  2031. ((LPBYTE)lpDataDefinition - (LPBYTE)lpData);
  2032. }
  2033. return lReturnValue;
  2034. }
  2035. //***************************************************************************
  2036. //
  2037. // CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
  2038. //
  2039. // removes the class from the access object
  2040. //
  2041. //***************************************************************************
  2042. //
  2043. DWORD
  2044. CPerfObjectAccess::RemoveClass(IWbemClassObject *pClass)
  2045. {
  2046. CPerfDataLibrary *pLibEntry = NULL;
  2047. CPerfDataLibrary *pThisLibEntry = NULL;
  2048. DWORD dwIndex = 0;
  2049. DWORD dwEnd;
  2050. LPWSTR szRegistryKey = NULL;
  2051. IWbemQualifierSet *pClassQualifiers = NULL;
  2052. VARIANT vRegistryKey;
  2053. HRESULT hRes;
  2054. DWORD dwReturn = ERROR_SUCCESS;
  2055. DWORD dwPerfIndex;
  2056. VariantInit (&vRegistryKey);
  2057. // get the Qualifier Set for this class
  2058. hRes = pClass->GetQualifierSet(&pClassQualifiers);
  2059. assert (hRes == 0);
  2060. // now get the library and procedure names
  2061. hRes = pClassQualifiers->Get(CBSTR(cszRegistryKey), 0, &vRegistryKey, 0);
  2062. if ((hRes == 0) && (vRegistryKey.vt == VT_BSTR)) {
  2063. szRegistryKey = Macro_CloneLPWSTR(V_BSTR(&vRegistryKey));
  2064. if (szRegistryKey == NULL) {
  2065. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2066. }
  2067. else {
  2068. // now also get the perf index
  2069. VariantClear (&vRegistryKey);
  2070. hRes = pClassQualifiers->Get(CBSTR(cszPerfIndex), 0, &vRegistryKey, 0);
  2071. if (hRes == 0) {
  2072. dwPerfIndex = (DWORD)V_UI4(&vRegistryKey);
  2073. } else {
  2074. // unable to find NtPerfLibrary entry
  2075. dwReturn = ERROR_FILE_NOT_FOUND;
  2076. }
  2077. }
  2078. } else {
  2079. // unable to find NtPerfLibrary entry
  2080. dwReturn = ERROR_FILE_NOT_FOUND;
  2081. }
  2082. if (pClassQualifiers != NULL) pClassQualifiers->Release();
  2083. if (dwReturn == ERROR_SUCCESS) {
  2084. // find matching library in the array
  2085. dwEnd = m_aLibraries.Size();
  2086. if (dwEnd > 0) {
  2087. // walk down the list of libraries
  2088. for (dwIndex = 0; dwIndex < dwEnd; dwIndex++) {
  2089. // see if this library entry is good enough to keep
  2090. // The library is assumed to be a match if the
  2091. // lib. name and all proc's are the same.
  2092. pThisLibEntry = (CPerfDataLibrary *)m_aLibraries[dwIndex];
  2093. assert (pThisLibEntry != NULL); // it should have been removed!
  2094. // make sure it's complete
  2095. assert (pThisLibEntry->pLibInfo->szServiceName != NULL);
  2096. if (lstrcmpiW (szRegistryKey, pThisLibEntry->pLibInfo->szServiceName) == 0) {
  2097. pLibEntry = pThisLibEntry;
  2098. break;
  2099. } else {
  2100. // wrong library
  2101. // so continue
  2102. }
  2103. }
  2104. }
  2105. if (pLibEntry != NULL) {
  2106. // close this class & it's library
  2107. dwReturn = CloseLibrary(pLibEntry);
  2108. if (dwReturn == 0) {
  2109. // then no one wants it
  2110. FREEMEM(m_hObjectHeap, 0, pLibEntry->pLibInfo);
  2111. pLibEntry->pLibInfo = NULL;
  2112. m_aLibraries.RemoveAt(dwIndex);
  2113. m_aLibraries.Compress();
  2114. delete pLibEntry;
  2115. }
  2116. dwReturn = ERROR_SUCCESS;
  2117. } else {
  2118. dwReturn = ERROR_FILE_NOT_FOUND;
  2119. }
  2120. }
  2121. if (szRegistryKey != NULL) delete szRegistryKey;
  2122. VariantClear(&vRegistryKey);
  2123. return dwReturn;
  2124. }