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.

1237 lines
70 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. extinit.c
  5. Abstract:
  6. This file implements all the initialization library routines operating on
  7. extensible performance libraries.
  8. Author:
  9. JeePang
  10. Revision History:
  11. 09/27/2000 - JeePang - Moved from perflib.c
  12. --*/
  13. #define UNICODE
  14. //
  15. // Include files
  16. //
  17. #pragma warning(disable:4306)
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <ntregapi.h>
  22. #include <ntprfctr.h>
  23. #include <windows.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <winperf.h>
  27. #include <rpc.h>
  28. #include "regrpc.h"
  29. #include "ntconreg.h"
  30. #include "prflbmsg.h" // event log messages
  31. #include "perflib.h"
  32. #pragma warning(default:4306)
  33. //
  34. // static constant definitions
  35. //
  36. // constants used by guard page testing
  37. //
  38. #define GUARD_PAGE_SIZE 1024
  39. #define GUARD_PAGE_CHAR 0xA5
  40. #define GUARD_PAGE_DWORD 0xA5A5A5A5
  41. typedef struct _EXT_OBJ_ITEM {
  42. DWORD dwObjId;
  43. DWORD dwFlags;
  44. } EXT_OBJ_LIST, *PEXT_OBJ_LIST;
  45. #define PERF_EOL_ITEM_FOUND ((DWORD)0x00000001)
  46. __inline
  47. DWORD
  48. RegisterExtObjListAccess ()
  49. {
  50. LONG Status;
  51. LARGE_INTEGER liWaitTime;
  52. if (hGlobalDataMutex != NULL) {
  53. liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  54. // wait for access to the list of ext objects
  55. Status = NtWaitForSingleObject (
  56. hGlobalDataMutex,
  57. FALSE,
  58. &liWaitTime);
  59. if (Status != WAIT_TIMEOUT) {
  60. if (hExtObjListIsNotInUse != NULL) {
  61. // indicate that we are going to use the list
  62. InterlockedIncrement ((LONG *)&dwExtObjListRefCount);
  63. if (dwExtObjListRefCount > 0) {
  64. ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
  65. } else {
  66. SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
  67. }
  68. Status = ERROR_SUCCESS;
  69. } else {
  70. Status = ERROR_NOT_READY;
  71. }
  72. ReleaseMutex (hGlobalDataMutex);
  73. } // else return status;
  74. } else {
  75. Status = ERROR_LOCK_FAILED;
  76. }
  77. return Status;
  78. }
  79. __inline
  80. DWORD
  81. DeRegisterExtObjListAccess ()
  82. {
  83. LONG Status;
  84. LARGE_INTEGER liWaitTime;
  85. if (hGlobalDataMutex != NULL) {
  86. liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  87. // wait for access to the list of ext objects
  88. Status = NtWaitForSingleObject (
  89. hGlobalDataMutex,
  90. FALSE,
  91. &liWaitTime);
  92. if (Status != WAIT_TIMEOUT) {
  93. if (hExtObjListIsNotInUse != NULL) {
  94. assert (dwExtObjListRefCount > 0);
  95. // indicate that we are going to use the list
  96. InterlockedDecrement ((LONG *)&dwExtObjListRefCount);
  97. if (dwExtObjListRefCount > 0) {
  98. ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
  99. } else {
  100. SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
  101. }
  102. Status = ERROR_SUCCESS;
  103. } else {
  104. Status = ERROR_NOT_READY;
  105. }
  106. ReleaseMutex (hGlobalDataMutex);
  107. } // else return status;
  108. } else {
  109. Status = ERROR_LOCK_FAILED;
  110. }
  111. return Status;
  112. }
  113. LONG
  114. QueryExtensibleData (
  115. COLLECT_THREAD_DATA * pArgs
  116. )
  117. /*++
  118. QueryExtensibleData - Get data from extensible objects
  119. Inputs:
  120. dwQueryType - Query type (GLOBAL, COSTLY, item list, etc.)
  121. lpValueName - pointer to value string (unused)
  122. lpData - pointer to start of data block
  123. where data is being collected
  124. lpcbData - pointer to size of data buffer
  125. lppDataDefinition - pointer to pointer to where object
  126. definition for this object type should
  127. go
  128. Outputs:
  129. *lppDataDefinition - set to location for next Type
  130. Definition if successful
  131. Returns:
  132. 0 if successful, else Win 32 error code of failure
  133. --*/
  134. {
  135. DWORD dwQueryType = pArgs->dwQueryType;
  136. LPWSTR lpValueName = pArgs->lpValueName;
  137. LPBYTE lpData = pArgs->lpData;
  138. LPDWORD lpcbData = pArgs->lpcbData;
  139. LPVOID *lppDataDefinition = pArgs->lppDataDefinition;
  140. DWORD Win32Error=ERROR_SUCCESS; // Failure code
  141. DWORD BytesLeft;
  142. DWORD InitialBytesLeft;
  143. DWORD NumObjectTypes;
  144. LPVOID lpExtDataBuffer = NULL;
  145. LPVOID lpCallBuffer = NULL;
  146. LPVOID lpLowGuardPage = NULL;
  147. LPVOID lpHiGuardPage = NULL;
  148. LPVOID lpEndPointer = NULL;
  149. LPVOID lpBufferBefore = NULL;
  150. LPVOID lpBufferAfter = NULL;
  151. PUCHAR lpCheckPointer;
  152. LARGE_INTEGER liStartTime, liEndTime, liWaitTime;
  153. PEXT_OBJECT pThisExtObj = NULL;
  154. DWORD dwLibEntry;
  155. BOOL bGuardPageOK;
  156. BOOL bBufferOK;
  157. BOOL bException;
  158. BOOL bUseSafeBuffer;
  159. BOOL bUnlockObjData = FALSE;
  160. LPTSTR szMessageArray[8];
  161. ULONG_PTR dwRawDataDwords[8]; // raw data buffer
  162. DWORD dwDataIndex;
  163. WORD wStringIndex;
  164. LONG lReturnValue = ERROR_SUCCESS;
  165. LONG lDllTestLevel;
  166. LONG lInstIndex;
  167. DWORD lCtrIndex;
  168. PERF_OBJECT_TYPE *pObject, *pNextObject;
  169. PERF_INSTANCE_DEFINITION *pInstance;
  170. PERF_COUNTER_DEFINITION *pCounterDef;
  171. PERF_DATA_BLOCK *pPerfData;
  172. BOOL bForeignDataBuffer;
  173. DWORD dwItemsInArray = 0;
  174. DWORD dwItemsInList = 0;
  175. volatile PEXT_OBJ_LIST pQueryList = NULL;
  176. LPWSTR pwcThisChar;
  177. DWORD dwThisNumber;
  178. DWORD dwIndex, dwEntry;
  179. BOOL bFound;
  180. BOOL bDisabled = FALSE;
  181. BOOL bUseTimer;
  182. DWORD dwType = 0;
  183. DWORD dwValue = 0;
  184. DWORD dwSize = sizeof(DWORD);
  185. DWORD status = 0;
  186. DWORD dwObjectBufSize;
  187. OPEN_PROC_WAIT_INFO opwInfo;
  188. HANDLE hPerflibFuncTimer;
  189. PVOID pOldBuffer;
  190. HEAP_PROBE();
  191. // see if perf data has been disabled
  192. // this is to prevent crashing WINLOGON if the
  193. // system has installed a bogus DLL
  194. assert (ghKeyPerflib != NULL);
  195. dwSize = sizeof(dwValue);
  196. dwValue = dwType = 0;
  197. status = PrivateRegQueryValueExW (
  198. ghKeyPerflib,
  199. DisablePerformanceCounters,
  200. NULL,
  201. &dwType,
  202. (LPBYTE)&dwValue,
  203. &dwSize);
  204. if ((status == ERROR_SUCCESS) &&
  205. (dwType == REG_DWORD) &&
  206. (dwValue == 1)) {
  207. // then DON'T Load any libraries and unload any that have been
  208. // loaded
  209. bDisabled = TRUE;
  210. }
  211. // if data collection is disabled and there's a collection thread
  212. // then close it
  213. if (bDisabled && (hCollectThread != NULL)) {
  214. pArgs->dwActionFlags = CTD_AF_CLOSE_THREAD;
  215. } else if (!bDisabled &&
  216. ((hCollectThread == NULL) && (dwCollectionFlags == COLL_FLAG_USE_SEPARATE_THREAD))) {
  217. // then data collection is enabled and they want a separate collection
  218. // thread, but there's no thread at the moment, so create it here
  219. pArgs->dwActionFlags = CTD_AF_OPEN_THREAD;
  220. }
  221. lReturnValue = RegisterExtObjListAccess();
  222. if (lReturnValue == ERROR_SUCCESS) {
  223. liStartTime.QuadPart = 0;
  224. InitialBytesLeft = 0;
  225. liEndTime.QuadPart = 0;
  226. if ((dwQueryType == QUERY_ITEMS) && (!bDisabled)) {
  227. // alloc the call list
  228. pwcThisChar = lpValueName;
  229. dwThisNumber = 0;
  230. // read the value string and build an object ID list
  231. while (*pwcThisChar != 0) {
  232. dwThisNumber = GetNextNumberFromList (
  233. pwcThisChar, &pwcThisChar);
  234. if (dwThisNumber != 0) {
  235. if (dwItemsInList >= dwItemsInArray) {
  236. dwItemsInArray += 16; // starting point for # of objects
  237. pOldBuffer = NULL;
  238. if (pQueryList == NULL) {
  239. // alloc a new buffer
  240. pQueryList = ALLOCMEM ((sizeof(EXT_OBJ_LIST) * dwItemsInArray));
  241. } else {
  242. // realloc a new buffer
  243. pOldBuffer = pQueryList;
  244. pQueryList = REALLOCMEM(pQueryList,
  245. (sizeof(EXT_OBJ_LIST) * dwItemsInArray));
  246. }
  247. if (pQueryList == NULL) {
  248. // unable to alloc memory so bail
  249. if (pOldBuffer)
  250. FREEMEM(pOldBuffer);
  251. return ERROR_OUTOFMEMORY;
  252. }
  253. }
  254. // then add to the list
  255. pQueryList[dwItemsInList].dwObjId = dwThisNumber;
  256. pQueryList[dwItemsInList].dwFlags = 0;
  257. dwItemsInList++;
  258. }
  259. }
  260. if (Win32Error == ERROR_SUCCESS) {
  261. //
  262. // Walk through list of ext. objects and tag the ones to call
  263. // as the query objects are found
  264. //
  265. for (pThisExtObj = ExtensibleObjects, dwLibEntry = 0;
  266. pThisExtObj != NULL;
  267. pThisExtObj = pThisExtObj->pNext, dwLibEntry++) {
  268. if (pThisExtObj->dwNumObjects > 0) {
  269. // then examine list
  270. for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex++) {
  271. // look at each entry in the list
  272. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  273. if (pQueryList[dwEntry].dwObjId == pThisExtObj->dwObjList[dwIndex]) {
  274. // tag this entry as found
  275. pQueryList[dwEntry].dwFlags |= PERF_EOL_ITEM_FOUND;
  276. // tag the object as needed
  277. pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
  278. }
  279. }
  280. }
  281. } else {
  282. // this entry doesn't list it's supported objects
  283. }
  284. }
  285. assert (dwLibEntry == NumExtensibleObjects);
  286. // see if any in the query list do not have entries
  287. bFound = TRUE;
  288. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  289. if (!(pQueryList[dwEntry].dwFlags & PERF_EOL_ITEM_FOUND)) {
  290. // no matching object found
  291. bFound = FALSE;
  292. break;
  293. }
  294. }
  295. if (!bFound) {
  296. // at least one of the object ID's in the query list was
  297. // not found in an object that supports an object list
  298. // then tag all entries that DO NOT support an object list
  299. // to be called and hope one of them supports it/them.
  300. for (pThisExtObj = ExtensibleObjects;
  301. pThisExtObj != NULL;
  302. pThisExtObj = pThisExtObj->pNext) {
  303. if (pThisExtObj->dwNumObjects == 0) {
  304. // tag this one so it will be called
  305. pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
  306. }
  307. }
  308. }
  309. } // end if first scan was successful
  310. if (pQueryList != NULL) FREEMEM (pQueryList);
  311. } // end if QUERY_ITEMS
  312. if (lReturnValue == ERROR_SUCCESS) {
  313. for (pThisExtObj = ExtensibleObjects;
  314. pThisExtObj != NULL;
  315. pThisExtObj = pThisExtObj->pNext) {
  316. // set the current ext object pointer
  317. pArgs->pCurrentExtObject = pThisExtObj;
  318. // convert timeout value
  319. liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
  320. // close the unused Perf DLL's IF:
  321. // the perflib key is disabled or this is an item query
  322. // and this is an Item (as opposed to a global or foreign) query or
  323. // the requested objects are not it this library or this library is disabled
  324. // and this library has been opened
  325. //
  326. if (((dwQueryType == QUERY_ITEMS) || bDisabled) &&
  327. (bDisabled || (!(pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY)) || (pThisExtObj->dwFlags & PERF_EO_DISABLED)) &&
  328. (pThisExtObj->hLibrary != NULL)) {
  329. // then free this object
  330. if (pThisExtObj->hMutex != NULL) {
  331. NTSTATUS NtStatus = NtWaitForSingleObject (
  332. pThisExtObj->hMutex,
  333. FALSE,
  334. &liWaitTime);
  335. Win32Error = PerfpDosError(NtStatus);
  336. if (NtStatus == STATUS_SUCCESS) {
  337. // then we got a lock
  338. CloseExtObjectLibrary (pThisExtObj, bDisabled);
  339. ReleaseMutex (pThisExtObj->hMutex);
  340. } else {
  341. pThisExtObj->dwLockoutCount++;
  342. DebugPrint((0, "Unable to Lock object for %ws to close in Query\n", pThisExtObj->szServiceName));
  343. }
  344. } else {
  345. Win32Error = ERROR_LOCK_FAILED;
  346. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  347. }
  348. if (hCollectThread != NULL) {
  349. // close the collection thread
  350. }
  351. } else if (((dwQueryType == QUERY_FOREIGN) ||
  352. (dwQueryType == QUERY_GLOBAL) ||
  353. (dwQueryType == QUERY_COSTLY) ||
  354. ((dwQueryType == QUERY_ITEMS) &&
  355. (pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY))) &&
  356. (!(pThisExtObj->dwFlags & PERF_EO_DISABLED))) {
  357. // initialize values to pass to the extensible counter function
  358. NumObjectTypes = 0;
  359. BytesLeft = (DWORD) (*lpcbData - ((LPBYTE) *lppDataDefinition - lpData));
  360. bException = FALSE;
  361. if ((pThisExtObj->hLibrary == NULL) ||
  362. (dwQueryType == QUERY_GLOBAL) ||
  363. (dwQueryType == QUERY_COSTLY)) {
  364. // lock library object
  365. if (pThisExtObj->hMutex != NULL) {
  366. NTSTATUS NtStatus = NtWaitForSingleObject (
  367. pThisExtObj->hMutex,
  368. FALSE,
  369. &liWaitTime);
  370. Win32Error = ERROR_SUCCESS;
  371. if (NtStatus == STATUS_SUCCESS) {
  372. // if this is a global or costly query, then reset the "in query"
  373. // flag for this object. The next ITEMS query will restore it.
  374. if ((dwQueryType == QUERY_GLOBAL) ||
  375. (dwQueryType == QUERY_COSTLY)) {
  376. pThisExtObj->dwFlags &= ~PERF_EO_OBJ_IN_QUERY;
  377. }
  378. // if necessary, open the library
  379. if (pThisExtObj->hLibrary == NULL) {
  380. // make sure the library is open
  381. Win32Error = OpenExtObjectLibrary(pThisExtObj);
  382. if (Win32Error != ERROR_SUCCESS) {
  383. if (Win32Error != ERROR_SERVICE_DISABLED) {
  384. // SERVICE_DISABLED is returned when the
  385. // service has been disabled via ExCtrLst.
  386. // so no point in complaining about it.
  387. // assume error has been posted
  388. DebugPrint((0, "Unable to open perf counter library for %ws, Error: 0x%8.8x\n",
  389. pThisExtObj->szServiceName, Win32Error));
  390. }
  391. ReleaseMutex (pThisExtObj->hMutex);
  392. continue; // to next entry
  393. }
  394. }
  395. ReleaseMutex (pThisExtObj->hMutex);
  396. } else {
  397. Win32Error = PerfpDosError(NtStatus);
  398. pThisExtObj->dwLockoutCount++;
  399. DebugPrint((0, "Unable to Lock object for %ws to open for Query\n", pThisExtObj->szServiceName));
  400. }
  401. } else {
  402. Win32Error = ERROR_LOCK_FAILED;
  403. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  404. }
  405. } else {
  406. // library should be ready to use
  407. }
  408. // if this dll is trusted, then use the system
  409. // defined test level, otherwise, test it
  410. // thorourghly
  411. bUseTimer = TRUE; // default
  412. if (!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) {
  413. if (pThisExtObj->dwFlags & PERF_EO_TRUSTED) {
  414. lDllTestLevel = lExtCounterTestLevel;
  415. bUseTimer = FALSE; // Trusted DLL's are not timed
  416. } else {
  417. // not trusted so use full test
  418. lDllTestLevel = EXT_TEST_ALL;
  419. }
  420. } else {
  421. // disable DLL testing
  422. lDllTestLevel = EXT_TEST_NOMEMALLOC;
  423. bUseTimer = FALSE; // Timing is disabled as well
  424. }
  425. if (lDllTestLevel < EXT_TEST_NOMEMALLOC) {
  426. bUseSafeBuffer = TRUE;
  427. } else {
  428. bUseSafeBuffer = FALSE;
  429. }
  430. // allocate a local block of memory to pass to the
  431. // extensible counter function.
  432. if (bUseSafeBuffer) {
  433. lpExtDataBuffer = ALLOCMEM (BytesLeft + (2*GUARD_PAGE_SIZE));
  434. } else {
  435. lpExtDataBuffer =
  436. lpCallBuffer = *lppDataDefinition;
  437. }
  438. if (lpExtDataBuffer != NULL) {
  439. if (bUseSafeBuffer) {
  440. // set buffer pointers
  441. lpLowGuardPage = lpExtDataBuffer;
  442. lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
  443. lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
  444. lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
  445. // initialize GuardPage Data
  446. memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  447. memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  448. }
  449. lpBufferBefore = lpCallBuffer;
  450. lpBufferAfter = NULL;
  451. hPerflibFuncTimer = NULL;
  452. try {
  453. //
  454. // Collect data from extensible objects
  455. //
  456. if (pThisExtObj->hMutex != NULL) {
  457. NTSTATUS NtStatus = NtWaitForSingleObject (
  458. pThisExtObj->hMutex,
  459. FALSE,
  460. &liWaitTime);
  461. Win32Error = PerfpDosError(NtStatus);
  462. if ((NtStatus == STATUS_SUCCESS) &&
  463. (pThisExtObj->CollectProc != NULL)) {
  464. bUnlockObjData = TRUE;
  465. opwInfo.pNext = NULL;
  466. opwInfo.szLibraryName = pThisExtObj->szLibraryName;
  467. opwInfo.szServiceName = pThisExtObj->szServiceName;
  468. opwInfo.dwWaitTime = pThisExtObj->dwCollectTimeout;
  469. opwInfo.dwEventMsg = PERFLIB_COLLECTION_HUNG;
  470. opwInfo.pData = (LPVOID)pThisExtObj;
  471. if (bUseTimer) {
  472. hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
  473. // if no timer, continue anyway, even though things may
  474. // hang, it's better than not loading the DLL since they
  475. // usually load OK
  476. //
  477. if (hPerflibFuncTimer == NULL) {
  478. // unable to get a timer entry
  479. DebugPrint((0, "Unable to acquire timer for Collect Proc\n"));
  480. }
  481. } else {
  482. hPerflibFuncTimer = NULL;
  483. }
  484. InitialBytesLeft = BytesLeft;
  485. QueryPerformanceCounter (&liStartTime);
  486. Win32Error = (*pThisExtObj->CollectProc) (
  487. lpValueName,
  488. &lpCallBuffer,
  489. &BytesLeft,
  490. &NumObjectTypes);
  491. QueryPerformanceCounter (&liEndTime);
  492. if (hPerflibFuncTimer != NULL) {
  493. // kill timer
  494. KillPerflibFunctionTimer (hPerflibFuncTimer);
  495. hPerflibFuncTimer = NULL;
  496. }
  497. // update statistics
  498. pThisExtObj->dwLastBufferSize = BytesLeft;
  499. if (BytesLeft > pThisExtObj->dwMaxBufferSize) {
  500. pThisExtObj->dwMaxBufferSize = BytesLeft;
  501. }
  502. if ((Win32Error == ERROR_MORE_DATA) &&
  503. (InitialBytesLeft > pThisExtObj->dwMaxBufferRejected)) {
  504. pThisExtObj->dwMaxBufferRejected = InitialBytesLeft;
  505. }
  506. lpBufferAfter = lpCallBuffer;
  507. pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
  508. ReleaseMutex (pThisExtObj->hMutex);
  509. bUnlockObjData = FALSE;
  510. } else {
  511. if ((pThisExtObj->CollectProc != NULL) &&
  512. (lEventLogLevel >= LOG_USER)) {
  513. DebugPrint((0,
  514. "Unable to Lock object for %ws to Collect data\n",
  515. pThisExtObj->szServiceName));
  516. dwDataIndex = wStringIndex = 0;
  517. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  518. dwRawDataDwords[dwDataIndex++] =
  519. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  520. szMessageArray[wStringIndex++] =
  521. pThisExtObj->szServiceName;
  522. szMessageArray[wStringIndex++] =
  523. pThisExtObj->szLibraryName;
  524. ReportEvent (hEventLog,
  525. EVENTLOG_WARNING_TYPE, // error type
  526. 0, // category (not used)
  527. (DWORD)PERFLIB_COLLECTION_HUNG, // event,
  528. NULL, // SID (not used),
  529. wStringIndex, // number of strings
  530. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  531. szMessageArray, // message text array
  532. (LPVOID)&dwRawDataDwords[0]); // raw data
  533. pThisExtObj->dwLockoutCount++;
  534. } else {
  535. // else it's not open so ignore.
  536. BytesLeft = 0;
  537. NumObjectTypes = 0;
  538. }
  539. }
  540. } else {
  541. Win32Error = ERROR_LOCK_FAILED;
  542. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  543. }
  544. if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
  545. // increment perf counters
  546. if ((BytesLeft > InitialBytesLeft) &&
  547. (lEventLogLevel >= LOG_USER)) {
  548. // memory error
  549. dwDataIndex = wStringIndex = 0;
  550. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)InitialBytesLeft;
  551. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
  552. szMessageArray[wStringIndex++] =
  553. pThisExtObj->szServiceName;
  554. szMessageArray[wStringIndex++] =
  555. pThisExtObj->szLibraryName;
  556. ReportEvent (hEventLog,
  557. EVENTLOG_ERROR_TYPE, // error type
  558. 0, // category (not used)
  559. (DWORD)PERFLIB_INVALID_SIZE_RETURNED, // event,
  560. NULL, // SID (not used),
  561. wStringIndex, // number of strings
  562. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  563. szMessageArray, // message text array
  564. (LPVOID)&dwRawDataDwords[0]); // raw data
  565. // disable the dll unless:
  566. // testing has been disabled.
  567. // or this is a trusted DLL (which are never disabled)
  568. // the event log message should be reported in any case since
  569. // this is a serious error
  570. //
  571. if ((!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) &&
  572. (!(pThisExtObj->dwFlags & PERF_EO_TRUSTED))) {
  573. DisablePerfLibrary (pThisExtObj);
  574. }
  575. // set error values to correct entries
  576. BytesLeft = 0;
  577. NumObjectTypes = 0;
  578. } else {
  579. // the buffer seems ok so far, so validate it
  580. InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
  581. pThisExtObj->llElapsedTime +=
  582. liEndTime.QuadPart - liStartTime.QuadPart;
  583. // test all returned buffers for correct alignment
  584. if ((((ULONG_PTR)BytesLeft & (ULONG_PTR)0x07)) &&
  585. !(lPerflibConfigFlags & PLCF_NO_ALIGN_ERRORS)) {
  586. if (((pThisExtObj->dwFlags & PERF_EO_ALIGN_ERR_POSTED) == 0) &&
  587. (lEventLogLevel >= LOG_USER)) {
  588. dwDataIndex = wStringIndex = 0;
  589. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)lpCallBuffer;
  590. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
  591. szMessageArray[wStringIndex++] =
  592. pThisExtObj->szServiceName;
  593. szMessageArray[wStringIndex++] =
  594. pThisExtObj->szLibraryName;
  595. ReportEvent (hEventLog,
  596. EVENTLOG_WARNING_TYPE, // error type
  597. 0, // category (not used)
  598. (DWORD)PERFLIB_BUFFER_ALIGNMENT_ERROR, // event,
  599. NULL, // SID (not used),
  600. wStringIndex, // number of strings
  601. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  602. szMessageArray, // message text array
  603. (LPVOID)&dwRawDataDwords[0]); // raw data
  604. pThisExtObj->dwFlags |= PERF_EO_ALIGN_ERR_POSTED;
  605. }
  606. }
  607. if (bUseSafeBuffer) {
  608. // a data buffer was returned and
  609. // the function returned OK so see how things
  610. // turned out...
  611. //
  612. //
  613. // check for buffer corruption here
  614. //
  615. bBufferOK = TRUE; // assume it's ok until a check fails
  616. //
  617. if (lDllTestLevel <= EXT_TEST_BASIC) {
  618. //
  619. // check 1: bytes left should be the same as
  620. // new data buffer ptr - orig data buffer ptr
  621. //
  622. if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
  623. if (lEventLogLevel >= LOG_USER) {
  624. // issue WARNING, that bytes left param is incorrect
  625. // load data for eventlog message
  626. // since this error is correctable (though with
  627. // some risk) this won't be reported at LOG_USER
  628. // level
  629. dwDataIndex = wStringIndex = 0;
  630. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  631. dwRawDataDwords[dwDataIndex++] =
  632. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  633. szMessageArray[wStringIndex++] =
  634. pThisExtObj->szServiceName;
  635. szMessageArray[wStringIndex++] =
  636. pThisExtObj->szLibraryName;
  637. ReportEvent (hEventLog,
  638. EVENTLOG_WARNING_TYPE, // error type
  639. 0, // category (not used)
  640. (DWORD)PERFLIB_BUFFER_POINTER_MISMATCH, // event,
  641. NULL, // SID (not used),
  642. wStringIndex, // number of strings
  643. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  644. szMessageArray, // message text array
  645. (LPVOID)&dwRawDataDwords[0]); // raw data
  646. }
  647. // toss this buffer
  648. bBufferOK = FALSE;
  649. DisablePerfLibrary (pThisExtObj);
  650. // <<old code>>
  651. // we'll keep the buffer, since the returned bytes left
  652. // value is ignored anyway, in order to make the
  653. // rest of this function work, we'll fix it here
  654. // BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  655. // << end old code >>
  656. }
  657. //
  658. // check 2: buffer after ptr should be < hi Guard page ptr
  659. //
  660. if (((LPBYTE)lpBufferAfter > (LPBYTE)lpHiGuardPage) && bBufferOK) {
  661. // see if they exceeded the allocated memory
  662. if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
  663. // this is very serious since they've probably trashed
  664. // the heap by overwriting the heap sig. block
  665. // issue ERROR, buffer overrun
  666. if (lEventLogLevel >= LOG_USER) {
  667. // load data for eventlog message
  668. dwDataIndex = wStringIndex = 0;
  669. dwRawDataDwords[dwDataIndex++] =
  670. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  671. szMessageArray[wStringIndex++] =
  672. pThisExtObj->szLibraryName;
  673. szMessageArray[wStringIndex++] =
  674. pThisExtObj->szServiceName;
  675. ReportEvent (hEventLog,
  676. EVENTLOG_ERROR_TYPE, // error type
  677. 0, // category (not used)
  678. (DWORD)PERFLIB_HEAP_ERROR, // event,
  679. NULL, // SID (not used),
  680. wStringIndex, // number of strings
  681. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  682. szMessageArray, // message text array
  683. (LPVOID)&dwRawDataDwords[0]); // raw data
  684. }
  685. } else {
  686. // issue ERROR, buffer overrun
  687. if (lEventLogLevel >= LOG_USER) {
  688. // load data for eventlog message
  689. dwDataIndex = wStringIndex = 0;
  690. dwRawDataDwords[dwDataIndex++] =
  691. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  692. szMessageArray[wStringIndex++] =
  693. pThisExtObj->szLibraryName;
  694. szMessageArray[wStringIndex++] =
  695. pThisExtObj->szServiceName;
  696. ReportEvent (hEventLog,
  697. EVENTLOG_ERROR_TYPE, // error type
  698. 0, // category (not used)
  699. (DWORD)PERFLIB_BUFFER_OVERFLOW, // event,
  700. NULL, // SID (not used),
  701. wStringIndex, // number of strings
  702. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  703. szMessageArray, // message text array
  704. (LPVOID)&dwRawDataDwords[0]); // raw data
  705. }
  706. }
  707. bBufferOK = FALSE;
  708. DisablePerfLibrary (pThisExtObj);
  709. // since the DLL overran the buffer, the buffer
  710. // must be too small (no comments about the DLL
  711. // will be made here) so the status will be
  712. // changed to ERROR_MORE_DATA and the function
  713. // will return.
  714. Win32Error = ERROR_MORE_DATA;
  715. }
  716. //
  717. // check 3: check lo guard page for corruption
  718. //
  719. if (bBufferOK) {
  720. bGuardPageOK = TRUE;
  721. for (lpCheckPointer = (PUCHAR)lpLowGuardPage;
  722. lpCheckPointer < (PUCHAR)lpBufferBefore;
  723. lpCheckPointer++) {
  724. if (*lpCheckPointer != GUARD_PAGE_CHAR) {
  725. bGuardPageOK = FALSE;
  726. break;
  727. }
  728. }
  729. if (!bGuardPageOK) {
  730. // issue ERROR, Lo Guard Page corrupted
  731. if (lEventLogLevel >= LOG_USER) {
  732. // load data for eventlog message
  733. dwDataIndex = wStringIndex = 0;
  734. szMessageArray[wStringIndex++] =
  735. pThisExtObj->szLibraryName;
  736. szMessageArray[wStringIndex++] =
  737. pThisExtObj->szServiceName;
  738. ReportEvent (hEventLog,
  739. EVENTLOG_ERROR_TYPE, // error type
  740. 0, // category (not used)
  741. (DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event
  742. NULL, // SID (not used),
  743. wStringIndex, // number of strings
  744. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  745. szMessageArray, // message text array
  746. (LPVOID)&dwRawDataDwords[0]); // raw data
  747. }
  748. bBufferOK = FALSE;
  749. DisablePerfLibrary (pThisExtObj);
  750. }
  751. }
  752. //
  753. // check 4: check hi guard page for corruption
  754. //
  755. if (bBufferOK) {
  756. bGuardPageOK = TRUE;
  757. for (lpCheckPointer = (PUCHAR)lpHiGuardPage;
  758. lpCheckPointer < (PUCHAR)lpEndPointer;
  759. lpCheckPointer++) {
  760. if (*lpCheckPointer != GUARD_PAGE_CHAR) {
  761. bGuardPageOK = FALSE;
  762. break;
  763. }
  764. }
  765. if (!bGuardPageOK) {
  766. // issue ERROR, Hi Guard Page corrupted
  767. if (lEventLogLevel >= LOG_USER) {
  768. // load data for eventlog message
  769. dwDataIndex = wStringIndex = 0;
  770. szMessageArray[wStringIndex++] =
  771. pThisExtObj->szLibraryName;
  772. szMessageArray[wStringIndex++] =
  773. pThisExtObj->szServiceName;
  774. ReportEvent (hEventLog,
  775. EVENTLOG_ERROR_TYPE, // error type
  776. 0, // category (not used)
  777. (DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event,
  778. NULL, // SID (not used),
  779. wStringIndex, // number of strings
  780. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  781. szMessageArray, // message text array
  782. (LPVOID)&dwRawDataDwords[0]); // raw data
  783. }
  784. bBufferOK = FALSE;
  785. DisablePerfLibrary (pThisExtObj);
  786. }
  787. }
  788. //
  789. if ((lDllTestLevel <= EXT_TEST_ALL) && bBufferOK) {
  790. //
  791. // Internal consistency checks
  792. //
  793. //
  794. // Check 5: Check object length field values
  795. //
  796. // first test to see if this is a foreign
  797. // computer data block or not
  798. //
  799. pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
  800. if ((pPerfData->Signature[0] == (WCHAR)'P') &&
  801. (pPerfData->Signature[1] == (WCHAR)'E') &&
  802. (pPerfData->Signature[2] == (WCHAR)'R') &&
  803. (pPerfData->Signature[3] == (WCHAR)'F')) {
  804. // if this is a foreign computer data block, then the
  805. // first object is after the header
  806. pObject = (PERF_OBJECT_TYPE *) (
  807. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  808. bForeignDataBuffer = TRUE;
  809. } else {
  810. // otherwise, if this is just a buffer from
  811. // an extensible counter, the object starts
  812. // at the beginning of the buffer
  813. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  814. bForeignDataBuffer = FALSE;
  815. }
  816. // go to where the pointers say the end of the
  817. // buffer is and then see if it's where it
  818. // should be
  819. dwObjectBufSize = 0;
  820. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  821. dwObjectBufSize += pObject->TotalByteLength;
  822. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  823. pObject->TotalByteLength);
  824. }
  825. if (((LPBYTE)pObject != (LPBYTE)lpCallBuffer) ||
  826. (dwObjectBufSize > BytesLeft)) {
  827. // then a length field is incorrect. This is FATAL
  828. // since it can corrupt the rest of the buffer
  829. // and render the buffer unusable.
  830. if (lEventLogLevel >= LOG_USER) {
  831. // load data for eventlog message
  832. dwDataIndex = wStringIndex = 0;
  833. dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
  834. szMessageArray[wStringIndex++] =
  835. pThisExtObj->szLibraryName;
  836. szMessageArray[wStringIndex++] =
  837. pThisExtObj->szServiceName;
  838. ReportEvent (hEventLog,
  839. EVENTLOG_ERROR_TYPE, // error type
  840. 0, // category (not used)
  841. (DWORD)PERFLIB_INCORRECT_OBJECT_LENGTH, // event,
  842. NULL, // SID (not used),
  843. wStringIndex, // number of strings
  844. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  845. szMessageArray, // message text array
  846. (LPVOID)&dwRawDataDwords[0]); // raw data
  847. }
  848. bBufferOK = FALSE;
  849. DisablePerfLibrary (pThisExtObj);
  850. }
  851. //
  852. // Test 6: Test Object definitions fields
  853. //
  854. if (bBufferOK) {
  855. // set object pointer
  856. if (bForeignDataBuffer) {
  857. pObject = (PERF_OBJECT_TYPE *) (
  858. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  859. } else {
  860. // otherwise, if this is just a buffer from
  861. // an extensible counter, the object starts
  862. // at the beginning of the buffer
  863. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  864. }
  865. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  866. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  867. pObject->DefinitionLength);
  868. if (pObject->NumCounters != 0) {
  869. pCounterDef = (PERF_COUNTER_DEFINITION *)
  870. ((LPBYTE)pObject + pObject->HeaderLength);
  871. lCtrIndex = 0;
  872. while (lCtrIndex < pObject->NumCounters) {
  873. if ((LPBYTE)pCounterDef < (LPBYTE)pNextObject) {
  874. // still ok so go to next counter
  875. pCounterDef = (PERF_COUNTER_DEFINITION *)
  876. ((LPBYTE)pCounterDef + pCounterDef->ByteLength);
  877. lCtrIndex++;
  878. } else {
  879. bBufferOK = FALSE;
  880. break;
  881. }
  882. }
  883. if ((LPBYTE)pCounterDef != (LPBYTE)pNextObject) {
  884. bBufferOK = FALSE;
  885. }
  886. }
  887. if (!bBufferOK) {
  888. break;
  889. } else {
  890. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  891. pObject->TotalByteLength);
  892. }
  893. }
  894. if (!bBufferOK) {
  895. if (lEventLogLevel >= LOG_USER) {
  896. // load data for eventlog message
  897. dwDataIndex = wStringIndex = 0;
  898. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  899. szMessageArray[wStringIndex++] =
  900. pThisExtObj->szLibraryName;
  901. szMessageArray[wStringIndex++] =
  902. pThisExtObj->szServiceName;
  903. ReportEvent (hEventLog,
  904. EVENTLOG_ERROR_TYPE, // error type
  905. 0, // category (not used)
  906. (DWORD)PERFLIB_INVALID_DEFINITION_BLOCK, // event,
  907. NULL, // SID (not used),
  908. wStringIndex, // number of strings
  909. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  910. szMessageArray, // message text array
  911. (LPVOID)&dwRawDataDwords[0]); // raw data
  912. }
  913. DisablePerfLibrary (pThisExtObj);
  914. }
  915. }
  916. //
  917. // Test 7: Test instance field size values
  918. //
  919. if (bBufferOK) {
  920. // set object pointer
  921. if (bForeignDataBuffer) {
  922. pObject = (PERF_OBJECT_TYPE *) (
  923. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  924. } else {
  925. // otherwise, if this is just a buffer from
  926. // an extensible counter, the object starts
  927. // at the beginning of the buffer
  928. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  929. }
  930. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  931. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  932. pObject->TotalByteLength);
  933. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  934. pInstance = (PERF_INSTANCE_DEFINITION *)
  935. ((LPBYTE)pObject + pObject->DefinitionLength);
  936. lInstIndex = 0;
  937. while (lInstIndex < pObject->NumInstances) {
  938. PERF_COUNTER_BLOCK *pCounterBlock;
  939. pCounterBlock = (PERF_COUNTER_BLOCK *)
  940. ((PCHAR) pInstance + pInstance->ByteLength);
  941. pInstance = (PERF_INSTANCE_DEFINITION *)
  942. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  943. lInstIndex++;
  944. }
  945. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  946. bBufferOK = FALSE;
  947. }
  948. }
  949. if (!bBufferOK) {
  950. break;
  951. } else {
  952. pObject = pNextObject;
  953. }
  954. }
  955. if (!bBufferOK) {
  956. if (lEventLogLevel >= LOG_USER) {
  957. // load data for eventlog message
  958. dwDataIndex = wStringIndex = 0;
  959. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  960. szMessageArray[wStringIndex++] =
  961. pThisExtObj->szLibraryName;
  962. szMessageArray[wStringIndex++] =
  963. pThisExtObj->szServiceName;
  964. ReportEvent (hEventLog,
  965. EVENTLOG_ERROR_TYPE, // error type
  966. 0, // category (not used)
  967. (DWORD)PERFLIB_INCORRECT_INSTANCE_LENGTH, // event,
  968. NULL, // SID (not used),
  969. wStringIndex, // number of strings
  970. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  971. szMessageArray, // message text array
  972. (LPVOID)&dwRawDataDwords[0]); // raw data
  973. }
  974. DisablePerfLibrary (pThisExtObj);
  975. }
  976. }
  977. }
  978. }
  979. //
  980. // if all the tests pass,then copy the data to the
  981. // original buffer and update the pointers
  982. if (bBufferOK) {
  983. RtlMoveMemory (*lppDataDefinition,
  984. lpBufferBefore,
  985. BytesLeft); // returned buffer size
  986. } else {
  987. NumObjectTypes = 0; // since this buffer was tossed
  988. BytesLeft = 0; // reset the size value since the buffer wasn't used
  989. }
  990. } else {
  991. // function already copied data to caller's buffer
  992. // so no further action is necessary
  993. }
  994. *lppDataDefinition = (LPVOID)((LPBYTE)(*lppDataDefinition) + BytesLeft); // update data pointer
  995. }
  996. } else {
  997. if (Win32Error != ERROR_SUCCESS) {
  998. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  999. }
  1000. if (bUnlockObjData) {
  1001. ReleaseMutex (pThisExtObj->hMutex);
  1002. }
  1003. NumObjectTypes = 0; // clear counter
  1004. }// end if function returned successfully
  1005. } except (EXCEPTION_EXECUTE_HANDLER) {
  1006. Win32Error = GetExceptionCode();
  1007. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1008. bException = TRUE;
  1009. if (bUnlockObjData) {
  1010. ReleaseMutex (pThisExtObj->hMutex);
  1011. bUnlockObjData = FALSE;
  1012. }
  1013. if (hPerflibFuncTimer != NULL) {
  1014. // kill timer
  1015. KillPerflibFunctionTimer (hPerflibFuncTimer);
  1016. hPerflibFuncTimer = NULL;
  1017. }
  1018. }
  1019. if (bUseSafeBuffer) {
  1020. FREEMEM (lpExtDataBuffer);
  1021. }
  1022. } else {
  1023. // unable to allocate memory so set error value
  1024. Win32Error = ERROR_OUTOFMEMORY;
  1025. } // end if temp buffer allocated successfully
  1026. //
  1027. // Update the count of the number of object types
  1028. //
  1029. ((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
  1030. if ( Win32Error != ERROR_SUCCESS) {
  1031. if (bException ||
  1032. !((Win32Error == ERROR_MORE_DATA) ||
  1033. (Win32Error == WAIT_TIMEOUT))) {
  1034. // inform on exceptions & illegal error status only
  1035. if (lEventLogLevel >= LOG_USER) {
  1036. // load data for eventlog message
  1037. dwDataIndex = wStringIndex = 0;
  1038. dwRawDataDwords[dwDataIndex++] = Win32Error;
  1039. szMessageArray[wStringIndex++] =
  1040. pThisExtObj->szServiceName;
  1041. szMessageArray[wStringIndex++] =
  1042. pThisExtObj->szLibraryName;
  1043. ReportEvent (hEventLog,
  1044. EVENTLOG_ERROR_TYPE, // error type
  1045. 0, // category (not used)
  1046. (DWORD)PERFLIB_COLLECT_PROC_EXCEPTION, // event,
  1047. NULL, // SID (not used),
  1048. wStringIndex, // number of strings
  1049. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  1050. szMessageArray, // message text array
  1051. (LPVOID)&dwRawDataDwords[0]); // raw data
  1052. } else {
  1053. if (bException) {
  1054. DebugPrint((0, "Extensible Counter %d generated an exception code: 0x%8.8x (%dL)\n",
  1055. NumObjectTypes, Win32Error, Win32Error));
  1056. } else {
  1057. DebugPrint((0, "Extensible Counter %d returned error code: 0x%8.8x (%dL)\n",
  1058. NumObjectTypes, Win32Error, Win32Error));
  1059. }
  1060. }
  1061. if (bException) {
  1062. DisablePerfLibrary (pThisExtObj);
  1063. }
  1064. }
  1065. // the ext. dll is only supposed to return:
  1066. // ERROR_SUCCESS even if it encountered a problem, OR
  1067. // ERROR_MODE_DATA if the buffer was too small.
  1068. // if it's ERROR_MORE_DATA, then break and return the
  1069. // error now, since it'll just be returned again and again.
  1070. if (Win32Error == ERROR_MORE_DATA) {
  1071. lReturnValue = Win32Error;
  1072. break;
  1073. }
  1074. }
  1075. // update perf data in global section
  1076. if (pThisExtObj->pPerfSectionEntry != NULL) {
  1077. pThisExtObj->pPerfSectionEntry->llElapsedTime =
  1078. pThisExtObj->llElapsedTime;
  1079. pThisExtObj->pPerfSectionEntry->dwCollectCount =
  1080. pThisExtObj->dwCollectCount;
  1081. pThisExtObj->pPerfSectionEntry->dwOpenCount =
  1082. pThisExtObj->dwOpenCount;
  1083. pThisExtObj->pPerfSectionEntry->dwCloseCount =
  1084. pThisExtObj->dwCloseCount;
  1085. pThisExtObj->pPerfSectionEntry->dwLockoutCount =
  1086. pThisExtObj->dwLockoutCount;
  1087. pThisExtObj->pPerfSectionEntry->dwErrorCount =
  1088. pThisExtObj->dwErrorCount;
  1089. pThisExtObj->pPerfSectionEntry->dwLastBufferSize =
  1090. pThisExtObj->dwLastBufferSize;
  1091. pThisExtObj->pPerfSectionEntry->dwMaxBufferSize =
  1092. pThisExtObj->dwMaxBufferSize;
  1093. pThisExtObj->pPerfSectionEntry->dwMaxBufferRejected =
  1094. pThisExtObj->dwMaxBufferRejected;
  1095. } else {
  1096. // no data section was initialized so skip
  1097. }
  1098. } // end if this object is to be called
  1099. } // end for each object
  1100. } // else an error occurred so unable to call functions
  1101. Win32Error = DeRegisterExtObjListAccess();
  1102. } // else unable to access ext object list
  1103. HEAP_PROBE();
  1104. if (bDisabled) lReturnValue = ERROR_SERVICE_DISABLED;
  1105. return lReturnValue;
  1106. }