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.

1121 lines
42 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. // used for error logging control
  35. #define DEFAULT_ERROR_LIMIT 1000
  36. DWORD dwExtCtrOpenProcWaitMs = OPEN_PROC_WAIT_TIME;
  37. LONG lExtCounterTestLevel = EXT_TEST_UNDEFINED;
  38. PEXT_OBJECT
  39. AllocateAndInitializeExtObject (
  40. HKEY hServicesKey,
  41. HKEY hPerfKey,
  42. PUNICODE_STRING usServiceName
  43. )
  44. /*++
  45. AllocateAndInitializeExtObject
  46. allocates and initializes an extensible object information entry
  47. for use by the performance library.
  48. a pointer to the initialized block is returned if all goes well,
  49. otherwise no memory is allocated and a null pointer is returned.
  50. The calling function must close the open handles and free this
  51. memory block when it is no longer needed.
  52. Arguments:
  53. hServicesKey -- open registry handle to the
  54. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services hey
  55. hPerfKey -- the open registry key to the Performance sub-key under
  56. the selected service
  57. szServiceName -- The name of the service
  58. --*/
  59. {
  60. LONG Status;
  61. HKEY hKeyLinkage;
  62. BOOL bUseQueryFn = FALSE;
  63. PEXT_OBJECT pReturnObject = NULL;
  64. DWORD dwType;
  65. DWORD dwSize;
  66. DWORD dwFlags = 0;
  67. DWORD dwKeep;
  68. DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
  69. DWORD dwObjIndex = 0;
  70. DWORD dwMemBlockSize = sizeof(EXT_OBJECT);
  71. DWORD dwLinkageStringLen = 0;
  72. DWORD dwErrorLimit;
  73. CHAR szOpenProcName[MAX_PATH];
  74. CHAR szCollectProcName[MAX_PATH];
  75. CHAR szCloseProcName[MAX_PATH];
  76. WCHAR szLibraryString[MAX_PATH];
  77. WCHAR szLibraryExpPath[MAX_PATH];
  78. WCHAR mszObjectList[MAX_PATH];
  79. WCHAR szLinkageKeyPath[MAX_PATH];
  80. LPWSTR szLinkageString = NULL; // max path wasn't enough for some paths
  81. DLL_VALIDATION_DATA DllVD;
  82. FILETIME LocalftLastGoodDllFileDate;
  83. DWORD dwOpenTimeout;
  84. DWORD dwCollectTimeout;
  85. LPWSTR szThisObject;
  86. LPWSTR szThisChar;
  87. LPSTR pNextStringA;
  88. LPWSTR pNextStringW;
  89. WCHAR szMutexName[MAX_PATH];
  90. WCHAR szPID[32];
  91. WORD wStringIndex;
  92. LPWSTR szMessageArray[2];
  93. BOOL bDisable = FALSE;
  94. LPWSTR szServiceName;
  95. // read the performance DLL name
  96. szServiceName = (LPWSTR) usServiceName->Buffer;
  97. dwType = 0;
  98. dwSize = sizeof(szLibraryString);
  99. memset (szLibraryString, 0, sizeof(szLibraryString));
  100. memset (szLibraryString, 0, sizeof(szLibraryExpPath));
  101. LocalftLastGoodDllFileDate.dwLowDateTime = 0;
  102. LocalftLastGoodDllFileDate.dwHighDateTime = 0;
  103. memset (&DllVD, 0, sizeof(DllVD));
  104. dwErrorLimit = DEFAULT_ERROR_LIMIT;
  105. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  106. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  107. Status = PrivateRegQueryValueExW (hPerfKey,
  108. DLLValue,
  109. NULL,
  110. &dwType,
  111. (LPBYTE)szLibraryString,
  112. &dwSize);
  113. if (Status == ERROR_SUCCESS) {
  114. if (dwType == REG_EXPAND_SZ) {
  115. // expand any environment vars
  116. dwSize = ExpandEnvironmentStringsW(
  117. szLibraryString,
  118. szLibraryExpPath,
  119. MAX_PATH);
  120. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  121. Status = ERROR_INVALID_DLL;
  122. } else {
  123. dwSize += 1;
  124. dwSize *= sizeof(WCHAR);
  125. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  126. }
  127. } else if (dwType == REG_SZ) {
  128. // look for dll and save full file Path
  129. dwSize = SearchPathW (
  130. NULL, // use standard system search path
  131. szLibraryString,
  132. NULL,
  133. MAX_PATH,
  134. szLibraryExpPath,
  135. NULL);
  136. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  137. Status = ERROR_INVALID_DLL;
  138. } else {
  139. dwSize += 1;
  140. dwSize *= sizeof(WCHAR);
  141. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  142. }
  143. } else {
  144. Status = ERROR_INVALID_DLL;
  145. TRACE((WINPERF_DBG_TRACE_FATAL),
  146. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  147. }
  148. if (Status == ERROR_SUCCESS) {
  149. // we have the DLL name so get the procedure names
  150. dwType = 0;
  151. dwSize = sizeof(szOpenProcName);
  152. memset (szOpenProcName, 0, sizeof(szOpenProcName));
  153. Status = PrivateRegQueryValueExA (hPerfKey,
  154. OpenValue,
  155. NULL,
  156. &dwType,
  157. (LPBYTE)szOpenProcName,
  158. &dwSize);
  159. if (((Status != ERROR_SUCCESS) || (szOpenProcName[0] == 0)) &&
  160. (lEventLogLevel >= LOG_USER)) {
  161. if (szServiceName != NULL) {
  162. TRACE((WINPERF_DBG_TRACE_FATAL),
  163. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  164. ARG_TYPE_WSTR, Status,
  165. szServiceName, usServiceName->MaximumLength, NULL));
  166. }
  167. else {
  168. TRACE((WINPERF_DBG_TRACE_FATAL),
  169. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  170. }
  171. // DebugPrint((1, "No open procedure for %ws %d\n",
  172. // szServiceName, Status));
  173. bDisable = TRUE;
  174. wStringIndex = 0;
  175. szMessageArray[wStringIndex++] = (LPWSTR) L"Open";
  176. szMessageArray[wStringIndex++] = szServiceName;
  177. ReportEvent(hEventLog,
  178. EVENTLOG_ERROR_TYPE,
  179. 0,
  180. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  181. NULL,
  182. wStringIndex,
  183. 0,
  184. szMessageArray,
  185. NULL);
  186. }
  187. #ifdef DBG
  188. else {
  189. DebugPrint((2, "Found %s for %ws\n",
  190. szOpenProcName, szServiceName));
  191. }
  192. #endif
  193. }
  194. #ifdef DBG
  195. else {
  196. DebugPrint((1, "Invalid DLL found for %ws\n",
  197. szServiceName));
  198. }
  199. #endif
  200. if (Status == ERROR_SUCCESS) {
  201. // add in size of previous string
  202. // the size value includes the Term. NULL
  203. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  204. // we have the procedure name so get the timeout value
  205. dwType = 0;
  206. dwSize = sizeof(dwOpenTimeout);
  207. Status = PrivateRegQueryValueExW (hPerfKey,
  208. OpenTimeout,
  209. NULL,
  210. &dwType,
  211. (LPBYTE)&dwOpenTimeout,
  212. &dwSize);
  213. // if error, then apply default
  214. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  215. dwOpenTimeout = dwExtCtrOpenProcWaitMs;
  216. Status = ERROR_SUCCESS;
  217. }
  218. }
  219. if (Status == ERROR_SUCCESS) {
  220. // get next string
  221. dwType = 0;
  222. dwSize = sizeof(szCloseProcName);
  223. memset (szCloseProcName, 0, sizeof(szCloseProcName));
  224. Status = PrivateRegQueryValueExA (hPerfKey,
  225. CloseValue,
  226. NULL,
  227. &dwType,
  228. (LPBYTE)szCloseProcName,
  229. &dwSize);
  230. if (((Status != ERROR_SUCCESS) || (szCloseProcName[0] == 0)) &&
  231. (lEventLogLevel >= LOG_USER)) {
  232. if (szServiceName != NULL) {
  233. TRACE((WINPERF_DBG_TRACE_FATAL),
  234. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  235. ARG_TYPE_WSTR, Status,
  236. szServiceName, usServiceName->MaximumLength, NULL));
  237. }
  238. else {
  239. TRACE((WINPERF_DBG_TRACE_FATAL),
  240. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  241. }
  242. // DebugPrint((1, "No close procedure for %ws\n",
  243. // szServiceName));
  244. wStringIndex = 0;
  245. szMessageArray[wStringIndex++] = (LPWSTR) L"Close";
  246. szMessageArray[wStringIndex++] = szServiceName;
  247. ReportEvent(hEventLog,
  248. EVENTLOG_ERROR_TYPE,
  249. 0,
  250. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  251. NULL,
  252. wStringIndex,
  253. 0,
  254. szMessageArray,
  255. NULL);
  256. bDisable = TRUE;
  257. }
  258. #ifdef DBG
  259. else {
  260. DebugPrint((2, "Found %s for %ws\n",
  261. szCloseProcName, szServiceName));
  262. }
  263. #endif
  264. }
  265. if (Status == ERROR_SUCCESS) {
  266. // add in size of previous string
  267. // the size value includes the Term. NULL
  268. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  269. // try to look up the query function which is the
  270. // preferred interface if it's not found, then
  271. // try the collect function name. If that's not found,
  272. // then bail
  273. dwType = 0;
  274. dwSize = sizeof(szCollectProcName);
  275. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  276. Status = PrivateRegQueryValueExA (hPerfKey,
  277. QueryValue,
  278. NULL,
  279. &dwType,
  280. (LPBYTE)szCollectProcName,
  281. &dwSize);
  282. if (Status == ERROR_SUCCESS) {
  283. // add in size of the Query Function Name
  284. // the size value includes the Term. NULL
  285. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  286. // get next string
  287. bUseQueryFn = TRUE;
  288. // the query function can support a static object list
  289. // so look it up
  290. } else {
  291. // the QueryFunction wasn't found so look up the
  292. // Collect Function name instead
  293. dwType = 0;
  294. dwSize = sizeof(szCollectProcName);
  295. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  296. Status = PrivateRegQueryValueExA (hPerfKey,
  297. CollectValue,
  298. NULL,
  299. &dwType,
  300. (LPBYTE)szCollectProcName,
  301. &dwSize);
  302. if (Status == ERROR_SUCCESS) {
  303. // add in size of Collect Function Name
  304. // the size value includes the Term. NULL
  305. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  306. }
  307. }
  308. if (((Status != ERROR_SUCCESS) || (szCollectProcName[0] == 0)) &&
  309. (lEventLogLevel >= LOG_USER)) {
  310. if (szServiceName != NULL) {
  311. TRACE((WINPERF_DBG_TRACE_FATAL),
  312. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  313. ARG_TYPE_WSTR, Status,
  314. szServiceName, usServiceName->MaximumLength, NULL));
  315. }
  316. else {
  317. TRACE((WINPERF_DBG_TRACE_FATAL),
  318. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  319. }
  320. DebugPrint((1, "No collect procedure for %ws\n",
  321. szServiceName));
  322. wStringIndex = 0;
  323. bDisable = TRUE;
  324. szMessageArray[wStringIndex++] = (LPWSTR) L"Collect";
  325. szMessageArray[wStringIndex++] = szServiceName;
  326. ReportEvent(hEventLog,
  327. EVENTLOG_ERROR_TYPE,
  328. 0,
  329. (DWORD)PERFLIB_PROC_NAME_NOT_FOUND,
  330. NULL,
  331. wStringIndex,
  332. 0,
  333. szMessageArray,
  334. NULL);
  335. }
  336. #ifdef DBG
  337. else {
  338. DebugPrint((2, "Found %s for %ws\n",
  339. szCollectProcName, szServiceName));
  340. }
  341. #endif
  342. if (Status == ERROR_SUCCESS) {
  343. // we have the procedure name so get the timeout value
  344. dwType = 0;
  345. dwSize = sizeof(dwCollectTimeout);
  346. Status = PrivateRegQueryValueExW (hPerfKey,
  347. CollectTimeout,
  348. NULL,
  349. &dwType,
  350. (LPBYTE)&dwCollectTimeout,
  351. &dwSize);
  352. // if error, then apply default
  353. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  354. dwCollectTimeout = dwExtCtrOpenProcWaitMs;
  355. Status = ERROR_SUCCESS;
  356. }
  357. }
  358. // get the list of supported objects if provided by the registry
  359. dwType = 0;
  360. dwSize = sizeof(mszObjectList);
  361. memset (mszObjectList, 0, sizeof(mszObjectList));
  362. Status = PrivateRegQueryValueExW (hPerfKey,
  363. ObjListValue,
  364. NULL,
  365. &dwType,
  366. (LPBYTE)mszObjectList,
  367. &dwSize);
  368. if (Status == ERROR_SUCCESS) {
  369. if (dwType != REG_MULTI_SZ) {
  370. // convert space delimited list to msz
  371. for (szThisChar = mszObjectList; *szThisChar != 0; szThisChar++) {
  372. if (*szThisChar == L' ') *szThisChar = L'\0';
  373. }
  374. ++szThisChar;
  375. *szThisChar = 0; // add MSZ term Null
  376. }
  377. for (szThisObject = mszObjectList, dwObjIndex = 0;
  378. (*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
  379. szThisObject += lstrlenW(szThisObject) + 1) {
  380. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  381. dwObjIndex++;
  382. }
  383. if ((*szThisObject != 0) &&
  384. (lEventLogLevel >= LOG_USER)) {
  385. TRACE((WINPERF_DBG_TRACE_FATAL),
  386. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, 0, NULL));
  387. ReportEvent (hEventLog,
  388. EVENTLOG_ERROR_TYPE, // error type
  389. 0, // category (not used
  390. (DWORD)PERFLIB_TOO_MANY_OBJECTS, // event,
  391. NULL, // SID (not used),
  392. 0, // number of strings
  393. 0, // sizeof raw data
  394. NULL, // message text array
  395. NULL); // raw data
  396. }
  397. } else {
  398. // reset status since not having this is
  399. // not a showstopper
  400. Status = ERROR_SUCCESS;
  401. }
  402. if (Status == ERROR_SUCCESS) {
  403. dwType = 0;
  404. dwKeep = 0;
  405. dwSize = sizeof(dwKeep);
  406. Status = PrivateRegQueryValueExW (hPerfKey,
  407. KeepResident,
  408. NULL,
  409. &dwType,
  410. (LPBYTE)&dwKeep,
  411. &dwSize);
  412. if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  413. if (dwKeep == 1) {
  414. dwFlags |= PERF_EO_KEEP_RESIDENT;
  415. } else {
  416. // no change.
  417. }
  418. } else {
  419. // not fatal, just use the defaults.
  420. Status = ERROR_SUCCESS;
  421. }
  422. }
  423. if (Status == ERROR_SUCCESS) {
  424. dwType = REG_DWORD;
  425. dwSize = sizeof(DWORD);
  426. PrivateRegQueryValueExW(
  427. hPerfKey,
  428. cszFailureLimit,
  429. NULL,
  430. &dwType,
  431. (LPBYTE)&dwErrorLimit,
  432. &dwSize);
  433. }
  434. }
  435. }
  436. else {
  437. if (szLibraryString != NULL) {
  438. TRACE((WINPERF_DBG_TRACE_FATAL),
  439. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT,
  440. ARG_TYPE_WSTR, Status,
  441. szLibraryString, WSTRSIZE(szLibraryString), NULL));
  442. }
  443. else {
  444. TRACE((WINPERF_DBG_TRACE_FATAL),
  445. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  446. }
  447. // DebugPrint((1, "Cannot key for %ws. Error=%d\n",
  448. // szLibraryString, Status));
  449. }
  450. if (Status == ERROR_SUCCESS) {
  451. // get Library validation time
  452. dwType = 0;
  453. dwSize = sizeof(DllVD);
  454. Status = PrivateRegQueryValueExW (hPerfKey,
  455. cszLibraryValidationData,
  456. NULL,
  457. &dwType,
  458. (LPBYTE)&DllVD,
  459. &dwSize);
  460. if ((Status != ERROR_SUCCESS) ||
  461. (dwType != REG_BINARY) ||
  462. (dwSize != sizeof (DllVD))){
  463. // then set this entry to be 0
  464. TRACE((WINPERF_DBG_TRACE_INFO),
  465. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  466. &dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
  467. memset (&DllVD, 0, sizeof(DllVD));
  468. // and clear the error
  469. Status = ERROR_SUCCESS;
  470. }
  471. }
  472. if (Status == ERROR_SUCCESS) {
  473. // get the file timestamp of the last successfully accessed file
  474. dwType = 0;
  475. dwSize = sizeof(LocalftLastGoodDllFileDate);
  476. memset (&LocalftLastGoodDllFileDate, 0, sizeof(LocalftLastGoodDllFileDate));
  477. Status = PrivateRegQueryValueExW (hPerfKey,
  478. cszSuccessfulFileData,
  479. NULL,
  480. &dwType,
  481. (LPBYTE)&LocalftLastGoodDllFileDate,
  482. &dwSize);
  483. if ((Status != ERROR_SUCCESS) ||
  484. (dwType != REG_BINARY) ||
  485. (dwSize != sizeof (LocalftLastGoodDllFileDate))) {
  486. // then set this entry to be Invalid
  487. memset (&LocalftLastGoodDllFileDate, 0xFF, sizeof(LocalftLastGoodDllFileDate));
  488. // and clear the error
  489. TRACE((WINPERF_DBG_TRACE_INFO),
  490. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  491. &dwType, sizeof(dwType), &dwSize, sizeof(dwSize), NULL));
  492. Status = ERROR_SUCCESS;
  493. }
  494. }
  495. if (Status == ERROR_SUCCESS) {
  496. lstrcpyW (szLinkageKeyPath, szServiceName);
  497. lstrcatW (szLinkageKeyPath, LinkageKey);
  498. Status = RegOpenKeyExW (
  499. hServicesKey,
  500. szLinkageKeyPath,
  501. 0L,
  502. KEY_READ,
  503. &hKeyLinkage);
  504. if (Status == ERROR_SUCCESS) {
  505. // look up export value string
  506. dwSize = 0;
  507. dwType = 0;
  508. Status = PrivateRegQueryValueExW (
  509. hKeyLinkage,
  510. ExportValue,
  511. NULL,
  512. &dwType,
  513. NULL,
  514. &dwSize);
  515. // get size of string
  516. if (((Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA)) ||
  517. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  518. dwLinkageStringLen = 0;
  519. szLinkageString = NULL;
  520. // not finding a linkage key is not fatal so correct
  521. // status
  522. Status = ERROR_SUCCESS;
  523. } else {
  524. // allocate buffer
  525. szLinkageString = (LPWSTR)ALLOCMEM(dwSize);
  526. if (szLinkageString != NULL) {
  527. // read string into buffer
  528. dwType = 0;
  529. Status = PrivateRegQueryValueExW (
  530. hKeyLinkage,
  531. ExportValue,
  532. NULL,
  533. &dwType,
  534. (LPBYTE)szLinkageString,
  535. &dwSize);
  536. if ((Status != ERROR_SUCCESS) ||
  537. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  538. // clear & release buffer
  539. FREEMEM (szLinkageString);
  540. szLinkageString = NULL;
  541. dwLinkageStringLen = 0;
  542. // not finding a linkage key is not fatal so correct
  543. // status
  544. Status = ERROR_SUCCESS;
  545. } else {
  546. // add size of linkage string to buffer
  547. // the size value includes the Term. NULL
  548. dwLinkageStringLen = dwSize;
  549. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  550. }
  551. } else {
  552. // clear & release buffer
  553. FREEMEM (szLinkageString);
  554. szLinkageString = NULL;
  555. dwLinkageStringLen = 0;
  556. Status = ERROR_OUTOFMEMORY;
  557. TRACE((WINPERF_DBG_TRACE_FATAL),
  558. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status,
  559. &dwSize, sizeof(dwSize), NULL));
  560. }
  561. }
  562. RegCloseKey (hKeyLinkage);
  563. } else {
  564. // not finding a linkage key is not fatal so correct
  565. // status
  566. // clear & release buffer
  567. szLinkageString = NULL;
  568. dwLinkageStringLen = 0;
  569. Status = ERROR_SUCCESS;
  570. }
  571. }
  572. if (Status == ERROR_SUCCESS) {
  573. // add in size of service name
  574. /* dwSize = lstrlenW (szServiceName);
  575. dwSize += 1;
  576. dwSize *= sizeof(WCHAR);
  577. */
  578. dwSize = usServiceName->MaximumLength;
  579. dwMemBlockSize += QWORD_MULTIPLE(dwSize);
  580. // allocate and initialize a new ext. object block
  581. pReturnObject = ALLOCMEM (dwMemBlockSize);
  582. if (pReturnObject != NULL) {
  583. // copy values to new buffer (all others are NULL)
  584. pNextStringA = (LPSTR)&pReturnObject[1];
  585. // copy Open Procedure Name
  586. pReturnObject->szOpenProcName = pNextStringA;
  587. lstrcpyA (pNextStringA, szOpenProcName);
  588. pNextStringA += lstrlenA (pNextStringA) + 1;
  589. pNextStringA = ALIGN_ON_QWORD(pNextStringA);
  590. pReturnObject->dwOpenTimeout = dwOpenTimeout;
  591. // copy collect function or query function, depending
  592. pReturnObject->szCollectProcName = pNextStringA;
  593. lstrcpyA (pNextStringA, szCollectProcName);
  594. pNextStringA += lstrlenA (pNextStringA) + 1;
  595. pNextStringA = ALIGN_ON_QWORD(pNextStringA);
  596. pReturnObject->dwCollectTimeout = dwCollectTimeout;
  597. // copy Close Procedure Name
  598. pReturnObject->szCloseProcName = pNextStringA;
  599. lstrcpyA (pNextStringA, szCloseProcName);
  600. pNextStringA += lstrlenA (pNextStringA) + 1;
  601. pNextStringA = ALIGN_ON_QWORD(pNextStringA);
  602. // copy Library path
  603. pNextStringW = (LPWSTR)pNextStringA;
  604. pReturnObject->szLibraryName = pNextStringW;
  605. lstrcpyW (pNextStringW, szLibraryExpPath);
  606. pNextStringW += lstrlenW (pNextStringW) + 1;
  607. pNextStringW = ALIGN_ON_QWORD(pNextStringW);
  608. // copy Linkage String if there is one
  609. if (szLinkageString != NULL) {
  610. pReturnObject->szLinkageString = pNextStringW;
  611. memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
  612. // length includes extra NULL char and is in BYTES
  613. pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
  614. pNextStringW = ALIGN_ON_QWORD(pNextStringW);
  615. // release the buffer now that it's been copied
  616. FREEMEM (szLinkageString);
  617. szLinkageString = NULL;
  618. }
  619. // copy Service name
  620. pReturnObject->szServiceName = pNextStringW;
  621. lstrcpyW (pNextStringW, szServiceName);
  622. pNextStringW += lstrlenW (pNextStringW) + 1;
  623. pNextStringW = ALIGN_ON_QWORD(pNextStringW);
  624. // load flags
  625. if (bUseQueryFn) {
  626. dwFlags |= PERF_EO_QUERY_FUNC;
  627. }
  628. pReturnObject->dwFlags = dwFlags;
  629. pReturnObject->hPerfKey = hPerfKey;
  630. pReturnObject->LibData = DllVD; // validation data
  631. pReturnObject->ftLastGoodDllFileDate = LocalftLastGoodDllFileDate;
  632. // the default test level is "all tests"
  633. // if the file and timestamp work out OK, this can
  634. // be reset to the system test level
  635. pReturnObject->dwValidationLevel = EXT_TEST_ALL;
  636. // load Object array
  637. if (dwObjIndex > 0) {
  638. pReturnObject->dwNumObjects = dwObjIndex;
  639. memcpy (pReturnObject->dwObjList,
  640. dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
  641. }
  642. pReturnObject->llLastUsedTime = 0;
  643. // create Mutex name
  644. lstrcpyW (szMutexName, szServiceName);
  645. lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
  646. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  647. lstrcatW (szMutexName, szPID);
  648. pReturnObject->hMutex = CreateMutexW(NULL, FALSE, szMutexName);
  649. pReturnObject->dwErrorLimit = dwErrorLimit;
  650. if ( pReturnObject->hMutex != NULL
  651. && GetLastError() == ERROR_ALREADY_EXISTS) {
  652. Status = ERROR_SUCCESS;
  653. }
  654. else {
  655. Status = GetLastError();
  656. }
  657. } else {
  658. Status = ERROR_OUTOFMEMORY;
  659. TRACE((WINPERF_DBG_TRACE_FATAL),
  660. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, dwMemBlockSize, NULL));
  661. }
  662. }
  663. if ((Status == ERROR_SUCCESS) && (lpPerflibSectionAddr != NULL)) {
  664. PPERFDATA_SECTION_HEADER pHead;
  665. DWORD dwEntry;
  666. PPERFDATA_SECTION_RECORD pEntry;
  667. // init perf data section
  668. pHead = (PPERFDATA_SECTION_HEADER)lpPerflibSectionAddr;
  669. pEntry = (PPERFDATA_SECTION_RECORD)lpPerflibSectionAddr;
  670. // get the entry first
  671. // the "0" entry is the header
  672. if (pHead->dwEntriesInUse < pHead->dwMaxEntries) {
  673. dwEntry = ++pHead->dwEntriesInUse;
  674. pReturnObject->pPerfSectionEntry = &pEntry[dwEntry];
  675. lstrcpynW (pReturnObject->pPerfSectionEntry->szServiceName,
  676. pReturnObject->szServiceName, PDSR_SERVICE_NAME_LEN);
  677. } else {
  678. // the list is full so bump the missing entry count
  679. pHead->dwMissingEntries++;
  680. pReturnObject->pPerfSectionEntry = NULL;
  681. }
  682. }
  683. if (Status != ERROR_SUCCESS) {
  684. SetLastError (Status);
  685. TRACE((WINPERF_DBG_TRACE_FATAL),
  686. (&PerflibGuid, __LINE__, PERF_ALLOC_INIT_EXT, 0, Status, NULL));
  687. if (bDisable) {
  688. DisableLibrary(hPerfKey, szServiceName);
  689. }
  690. if (pReturnObject) {
  691. FREEMEM(pReturnObject);
  692. pReturnObject = NULL;
  693. }
  694. if (szLinkageString) {
  695. FREEMEM(szLinkageString);
  696. }
  697. }
  698. return pReturnObject;
  699. }
  700. void
  701. OpenExtensibleObjects (
  702. )
  703. /*++
  704. Routine Description:
  705. This routine will search the Configuration Registry for modules
  706. which will return data at data collection time. If any are found,
  707. and successfully opened, data structures are allocated to hold
  708. handles to them.
  709. The global data access in this section is protected by the
  710. hGlobalDataMutex acquired by the calling function.
  711. Arguments:
  712. None.
  713. successful open.
  714. Return Value:
  715. None.
  716. --*/
  717. {
  718. DWORD dwIndex; // index for enumerating services
  719. ULONG KeyBufferLength; // length of buffer for reading key data
  720. ULONG ValueBufferLength; // length of buffer for reading value data
  721. ULONG ResultLength; // length of data returned by Query call
  722. HANDLE hPerfKey; // Root of queries for performance info
  723. HANDLE hServicesKey; // Root of services
  724. REGSAM samDesired; // access needed to query
  725. NTSTATUS Status; // generally used for Nt call result status
  726. ANSI_STRING AnsiValueData; // Ansi version of returned strings
  727. UNICODE_STRING ServiceName; // name of service returned by enumeration
  728. UNICODE_STRING PathName; // path name to services
  729. UNICODE_STRING PerformanceName; // name of key holding performance data
  730. UNICODE_STRING ValueDataName; // result of query of value is this name
  731. OBJECT_ATTRIBUTES ObjectAttributes; // general use for opening keys
  732. PKEY_BASIC_INFORMATION KeyInformation; // data from query key goes here
  733. WCHAR szServiceName[MAX_PATH];
  734. UNICODE_STRING usServiceName;
  735. LPTSTR szMessageArray[8];
  736. DWORD dwRawDataDwords[8]; // raw data buffer
  737. DWORD dwDataIndex;
  738. WORD wStringIndex;
  739. DWORD dwDefaultValue;
  740. HANDLE hTimeOutEvent;
  741. PEXT_OBJECT pLastObject = NULL;
  742. PEXT_OBJECT pThisObject = NULL;
  743. // Initialize do failure can deallocate if allocated
  744. ServiceName.Buffer = NULL;
  745. KeyInformation = NULL;
  746. ValueDataName.Buffer = NULL;
  747. AnsiValueData.Buffer = NULL;
  748. dwIndex = 0;
  749. RtlInitUnicodeString(&PathName, ExtPath);
  750. RtlInitUnicodeString(&PerformanceName, PerfSubKey);
  751. try {
  752. // get current event log level
  753. dwDefaultValue = LOG_NONE;
  754. Status = GetPerflibKeyValue (
  755. EventLogLevel,
  756. REG_DWORD,
  757. sizeof(DWORD),
  758. (LPVOID)&lEventLogLevel,
  759. sizeof(DWORD),
  760. (LPVOID)&dwDefaultValue);
  761. dwDefaultValue = EXT_TEST_ALL;
  762. Status = GetPerflibKeyValue (
  763. ExtCounterTestLevel,
  764. REG_DWORD,
  765. sizeof(DWORD),
  766. (LPVOID)&lExtCounterTestLevel,
  767. sizeof(DWORD),
  768. (LPVOID)&dwDefaultValue);
  769. dwDefaultValue = OPEN_PROC_WAIT_TIME;
  770. Status = GetPerflibKeyValue (
  771. OpenProcedureWaitTime,
  772. REG_DWORD,
  773. sizeof(DWORD),
  774. (LPVOID)&dwExtCtrOpenProcWaitMs,
  775. sizeof(DWORD),
  776. (LPVOID)&dwDefaultValue);
  777. dwDefaultValue = PERFLIB_TIMING_THREAD_TIMEOUT;
  778. Status = GetPerflibKeyValue (
  779. LibraryUnloadTime,
  780. REG_DWORD,
  781. sizeof(DWORD),
  782. (LPVOID)&dwThreadAndLibraryTimeout,
  783. sizeof(DWORD),
  784. (LPVOID)&dwDefaultValue);
  785. // register as an event log source if not already done.
  786. if (hEventLog == NULL) {
  787. hEventLog = RegisterEventSource (NULL, (LPCWSTR)TEXT("Perflib"));
  788. }
  789. if (ExtensibleObjects == NULL) {
  790. // create a list of the known performance data objects
  791. ServiceName.Length =
  792. ServiceName.MaximumLength = (WORD)(MAX_KEY_NAME_LENGTH +
  793. PerformanceName.MaximumLength +
  794. sizeof(UNICODE_NULL));
  795. ServiceName.Buffer = ALLOCMEM(ServiceName.MaximumLength);
  796. InitializeObjectAttributes(&ObjectAttributes,
  797. &PathName,
  798. OBJ_CASE_INSENSITIVE,
  799. NULL,
  800. NULL);
  801. samDesired = KEY_READ;
  802. Status = NtOpenKey(&hServicesKey,
  803. samDesired,
  804. &ObjectAttributes);
  805. KeyBufferLength = sizeof(KEY_BASIC_INFORMATION) + MAX_KEY_NAME_LENGTH;
  806. KeyInformation = ALLOCMEM(KeyBufferLength);
  807. ValueBufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
  808. MAX_VALUE_NAME_LENGTH +
  809. MAX_VALUE_DATA_LENGTH;
  810. ValueDataName.MaximumLength = MAX_VALUE_DATA_LENGTH;
  811. ValueDataName.Buffer = ALLOCMEM(ValueDataName.MaximumLength);
  812. AnsiValueData.MaximumLength = MAX_VALUE_DATA_LENGTH/sizeof(WCHAR);
  813. AnsiValueData.Buffer = ALLOCMEM(AnsiValueData.MaximumLength);
  814. //
  815. // Check for successful NtOpenKey and allocation of dynamic buffers
  816. //
  817. if ( NT_SUCCESS(Status) &&
  818. ServiceName.Buffer != NULL &&
  819. KeyInformation != NULL &&
  820. ValueDataName.Buffer != NULL &&
  821. AnsiValueData.Buffer != NULL ) {
  822. dwIndex = 0;
  823. hTimeOutEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
  824. // wait longer than the thread to give the timing thread
  825. // a chance to finish on it's own. This is really just a
  826. // failsafe step.
  827. while (NT_SUCCESS(Status)) {
  828. Status = NtEnumerateKey(hServicesKey,
  829. dwIndex,
  830. KeyBasicInformation,
  831. KeyInformation,
  832. KeyBufferLength,
  833. &ResultLength);
  834. dwIndex++; // next time, get the next key
  835. if( !NT_SUCCESS(Status) ) {
  836. // This is the normal exit: Status should be
  837. // STATUS_NO_MORE_VALUES
  838. break;
  839. }
  840. // Concatenate Service name with "\\Performance" to form Subkey
  841. if ( ServiceName.MaximumLength >=
  842. (USHORT)( KeyInformation->NameLength + sizeof(UNICODE_NULL) ) ) {
  843. ServiceName.Length = (USHORT) KeyInformation->NameLength;
  844. RtlMoveMemory(ServiceName.Buffer,
  845. KeyInformation->Name,
  846. ServiceName.Length);
  847. ServiceName.Buffer[(ServiceName.Length/sizeof(WCHAR))] = 0; // null term
  848. lstrcpyW (szServiceName, ServiceName.Buffer);
  849. RtlInitUnicodeString(&usServiceName, szServiceName);
  850. // zero terminate the buffer if space allows
  851. RtlAppendUnicodeStringToString(&ServiceName,
  852. &PerformanceName);
  853. // Open Service\Performance Subkey
  854. InitializeObjectAttributes(&ObjectAttributes,
  855. &ServiceName,
  856. OBJ_CASE_INSENSITIVE,
  857. hServicesKey,
  858. NULL);
  859. samDesired = KEY_WRITE | KEY_READ; // to be able to disable perf DLL's
  860. Status = NtOpenKey(&hPerfKey,
  861. samDesired,
  862. &ObjectAttributes);
  863. if(! NT_SUCCESS(Status) ) {
  864. samDesired = KEY_READ; // try read only access
  865. Status = NtOpenKey(&hPerfKey,
  866. samDesired,
  867. &ObjectAttributes);
  868. }
  869. if( NT_SUCCESS(Status) ) {
  870. // this has a performance key so read the info
  871. // and add the entry to the list
  872. pThisObject = AllocateAndInitializeExtObject (
  873. hServicesKey, hPerfKey, &usServiceName);
  874. if (pThisObject != NULL) {
  875. if (ExtensibleObjects == NULL) {
  876. // set head pointer
  877. pLastObject =
  878. ExtensibleObjects = pThisObject;
  879. NumExtensibleObjects = 1;
  880. } else {
  881. pLastObject->pNext = pThisObject;
  882. pLastObject = pThisObject;
  883. NumExtensibleObjects++;
  884. }
  885. } else {
  886. if (szServiceName != NULL) {
  887. TRACE((WINPERF_DBG_TRACE_FATAL),
  888. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, 0,
  889. szServiceName, usServiceName.MaximumLength, NULL));
  890. }
  891. else {
  892. TRACE((WINPERF_DBG_TRACE_FATAL),
  893. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, 0, 0, NULL));
  894. }
  895. // the object wasn't initialized so toss
  896. // the perf subkey handle.
  897. // otherwise keep it open for later
  898. // use and it will be closed when
  899. // this extensible object is closed
  900. NtClose (hPerfKey);
  901. }
  902. } else {
  903. if (szServiceName != NULL) {
  904. TRACE((WINPERF_DBG_TRACE_FATAL),
  905. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, ARG_TYPE_WSTR, Status,
  906. szServiceName, usServiceName.MaximumLength, NULL));
  907. }
  908. else {
  909. TRACE((WINPERF_DBG_TRACE_FATAL),
  910. (&PerflibGuid, __LINE__, PERF_OPEN_EXT_OBJS, 0, Status, NULL));
  911. }
  912. // *** NEW FEATURE CODE ***
  913. // unable to open the performance subkey
  914. if (((Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
  915. (lEventLogLevel >= LOG_USER)) ||
  916. (lEventLogLevel >= LOG_DEBUG)) {
  917. // an error other than OBJECT_NOT_FOUND should be
  918. // displayed if error logging is enabled
  919. // if DEBUG level is selected, then write all
  920. // non-success status returns to the event log
  921. //
  922. dwDataIndex = wStringIndex = 0;
  923. dwRawDataDwords[dwDataIndex++] = PerfpDosError(Status);
  924. if (lEventLogLevel >= LOG_DEBUG) {
  925. // if this is DEBUG mode, then log
  926. // the NT status as well.
  927. dwRawDataDwords[dwDataIndex++] =
  928. (DWORD)Status;
  929. }
  930. szMessageArray[wStringIndex++] =
  931. szServiceName;
  932. ReportEvent (hEventLog,
  933. EVENTLOG_WARNING_TYPE, // error type
  934. 0, // category (not used)
  935. (DWORD)PERFLIB_NO_PERFORMANCE_SUBKEY, // event,
  936. NULL, // SID (not used),
  937. wStringIndex, // number of strings
  938. dwDataIndex*sizeof(DWORD), // sizeof raw data
  939. szMessageArray, // message text array
  940. (LPVOID)&dwRawDataDwords[0]); // raw data
  941. }
  942. }
  943. }
  944. Status = STATUS_SUCCESS; // allow loop to continue
  945. }
  946. if (hTimeOutEvent != NULL) NtClose (hTimeOutEvent);
  947. NtClose (hServicesKey);
  948. }
  949. }
  950. } finally {
  951. if ( ServiceName.Buffer )
  952. FREEMEM(ServiceName.Buffer);
  953. if ( KeyInformation )
  954. FREEMEM(KeyInformation);
  955. if ( ValueDataName.Buffer )
  956. FREEMEM(ValueDataName.Buffer);
  957. if ( AnsiValueData.Buffer )
  958. FREEMEM(AnsiValueData.Buffer);
  959. }
  960. }