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.

502 lines
14 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. perfgen.c
  5. Abstract:
  6. This is the main file of the WINMGMT perf library.
  7. Created:
  8. davj 17-May-2000
  9. Revision History
  10. --*/
  11. #include <windows.h>
  12. #include <string.h>
  13. #include <winperf.h>
  14. #include <math.h>
  15. #include "genctrs.h" // error message definition
  16. #include "perfmsg.h"
  17. #include "perfutil.h"
  18. #include "datagen.h"
  19. DWORD dwDataSize[MAXVALUES];
  20. // This is the shared data segment which allows wbemcore.dll to be able to set
  21. // the counter values
  22. #pragma data_seg(".shared")
  23. DWORD dwCounterValues[MAXVALUES] = {0,0,0,0,0,0,0,0};
  24. #pragma data_seg()
  25. //
  26. // References to constants which initialize the Object type definitions
  27. //
  28. extern REG_DATA_DEFINITION RegDataDefinition;
  29. DWORD dwOpenCount = 0; // count of "Open" threads
  30. BOOL bInitOK = FALSE; // true = DLL initialized OK
  31. //
  32. // Function Prototypes
  33. //
  34. // these are used to insure that the data collection functions
  35. // accessed by Perflib will have the correct calling format.
  36. //
  37. PM_OPEN_PROC OpenWmiPerformanceData;
  38. PM_COLLECT_PROC CollectWmiPerformanceData;
  39. PM_CLOSE_PROC CloseWmiPerformanceData;
  40. DWORD GetData(DWORD * pData, DWORD dwIndex)
  41. {
  42. *pData = dwCounterValues[dwIndex];
  43. return 4;
  44. }
  45. DWORD APIENTRY
  46. OpenWmiPerformanceData(
  47. LPWSTR lpDeviceNames
  48. )
  49. /*++
  50. Routine Description:
  51. This routine will initialize the data structures used to pass
  52. data back to perfmon
  53. Arguments:
  54. Pointer to object ID of each device to be opened (WMIPerf)
  55. Return Value:
  56. None.
  57. --*/
  58. {
  59. LONG status;
  60. HKEY hKeyDriverPerf;
  61. DWORD size, x;
  62. DWORD type;
  63. DWORD dwFirstCounter;
  64. DWORD dwFirstHelp;
  65. //
  66. // Since WINLOGON is multi-threaded and will call this routine in
  67. // order to service remote performance queries, this library
  68. // must keep track of how many times it has been opened (i.e.
  69. // how many threads have accessed it). the registry routines will
  70. // limit access to the initialization routine to only one thread
  71. // at a time so synchronization (i.e. reentrancy) should not be
  72. // a problem
  73. //
  74. if (!dwOpenCount) {
  75. // open Eventlog interface
  76. hEventLog = MonOpenEventLog();
  77. // get counter and help index base values from registry
  78. // Open key to registry entry
  79. // read First Counter and First Help values
  80. // update static data strucutures by adding base to
  81. // offset value in structure.
  82. status = RegOpenKeyEx (
  83. HKEY_LOCAL_MACHINE,
  84. "SYSTEM\\CurrentControlSet\\Services\\Winmgmt\\Performance",
  85. 0L,
  86. KEY_READ,
  87. &hKeyDriverPerf);
  88. if (status != ERROR_SUCCESS) {
  89. REPORT_ERROR_DATA (GENPERF_UNABLE_OPEN_DRIVER_KEY, LOG_ERROR,
  90. &status, sizeof(status));
  91. // this is fatal, if we can't get the base values of the
  92. // counter or help names, then the names won't be available
  93. // to the requesting application so there's not much
  94. // point in continuing.
  95. goto OpenExitPoint;
  96. }
  97. size = sizeof (DWORD);
  98. status = RegQueryValueEx(
  99. hKeyDriverPerf,
  100. "First Counter",
  101. 0L,
  102. &type,
  103. (LPBYTE)&dwFirstCounter,
  104. &size);
  105. if (status != ERROR_SUCCESS) {
  106. REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_COUNTER, LOG_ERROR,
  107. &status, sizeof(status));
  108. // this is fatal, if we can't get the base values of the
  109. // counter or help names, then the names won't be available
  110. // to the requesting application so there's not much
  111. // point in continuing.
  112. goto OpenExitPoint;
  113. }
  114. size = sizeof (DWORD);
  115. status = RegQueryValueEx(
  116. hKeyDriverPerf,
  117. "First Help",
  118. 0L,
  119. &type,
  120. (LPBYTE)&dwFirstHelp,
  121. &size);
  122. if (status != ERROR_SUCCESS) {
  123. REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_HELP, LOG_ERROR,
  124. &status, sizeof(status));
  125. // this is fatal, if we can't get the base values of the
  126. // counter or help names, then the names won't be available
  127. // to the requesting application so there's not much
  128. // point in continuing.
  129. goto OpenExitPoint;
  130. }
  131. // Set some of the static information into the structure
  132. RegDataDefinition.RegObjectType.ObjectNameTitleIndex += dwFirstCounter;
  133. RegDataDefinition.RegObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  134. for (x=0; x<MAXVALUES; x++)
  135. {
  136. RegDataDefinition.Value[x].CounterNameTitleIndex += dwFirstCounter;
  137. RegDataDefinition.Value[x].CounterHelpTitleIndex += dwFirstHelp;
  138. }
  139. RegCloseKey (hKeyDriverPerf); // close key to registry
  140. bInitOK = TRUE; // ok to use this function
  141. }
  142. dwOpenCount++; // increment OPEN counter
  143. status = ERROR_SUCCESS; // for successful exit
  144. OpenExitPoint:
  145. return status;
  146. }
  147. DWORD APIENTRY
  148. CollectWmiPerformanceData(
  149. IN LPWSTR lpValueName,
  150. IN OUT LPVOID *lppData,
  151. IN OUT LPDWORD lpcbTotalBytes,
  152. IN OUT LPDWORD lpNumObjectTypes
  153. )
  154. /*++
  155. Routine Description:
  156. This routine will return the data for the WINMGMT counters.
  157. Arguments:
  158. IN LPWSTR lpValueName
  159. pointer to a wide character string passed by registry.
  160. IN OUT LPVOID *lppData
  161. IN: pointer to the address of the buffer to receive the completed
  162. PerfDataBlock and subordinate structures. This routine will
  163. append its data to the buffer starting at the point referenced
  164. by *lppData.
  165. OUT: points to the first byte after the data structure added by this
  166. routine. This routine updated the value at lppdata after appending
  167. its data.
  168. IN OUT LPDWORD lpcbTotalBytes
  169. IN: the address of the DWORD that tells the size in bytes of the
  170. buffer referenced by the lppData argument
  171. OUT: the number of bytes added by this routine is writted to the
  172. DWORD pointed to by this argument
  173. IN OUT LPDWORD NumObjectTypes
  174. IN: the address of the DWORD to receive the number of objects added
  175. by this routine
  176. OUT: the number of objects added by this routine is writted to the
  177. DWORD pointed to by this argument
  178. Return Value:
  179. ERROR_MORE_DATA if buffer passed is too small to hold data
  180. any error conditions encountered are reported to the event log if
  181. event logging is enabled.
  182. ERROR_SUCCESS if success or any other error. Errors, however are
  183. also reported to the event log.
  184. --*/
  185. {
  186. // Variables for reformating the data
  187. ULONG SpaceNeeded;
  188. PERF_COUNTER_BLOCK *pPerfCounterBlock;
  189. REG_DATA_DEFINITION *pRegDataDefinition;
  190. PERF_COUNTER_DEFINITION *pRegCounterDefinition;
  191. DWORD dwQueryType;
  192. DWORD x;
  193. DWORD dwTotSize;
  194. DWORD dwDataOffset;
  195. DWORD Data[MAXVALUES];
  196. // before doing anything else, see if Open went OK
  197. if (!bInitOK) {
  198. // unable to continue because open failed
  199. *lpcbTotalBytes = (DWORD) 0;
  200. *lpNumObjectTypes = (DWORD) 0;
  201. return ERROR_SUCCESS; // yes, this is a successful exit
  202. }
  203. // see if this is a foreign (ie non-nt) computer data request
  204. dwQueryType = GetQueryType (lpValueName);
  205. // REPORT_INFORMATION_DATA (COLLECTION_CALLED, LOG_VERBOSE, lpValueName, wcslen(lpValueName) * 2);
  206. if (dwQueryType == QUERY_FOREIGN) {
  207. // this routine does not service requests for data from
  208. // non-nt computers
  209. *lpcbTotalBytes = (DWORD) 0;
  210. *lpNumObjectTypes = (DWORD) 0;
  211. return ERROR_SUCCESS; // yes, this is a successful exit
  212. }
  213. // See if it is asking for our object.
  214. if (dwQueryType == QUERY_ITEMS) {
  215. if ( !(IsNumberInUnicodeList (RegDataDefinition.RegObjectType.ObjectNameTitleIndex,
  216. lpValueName))) {
  217. // request received for data object not provided by this routine
  218. *lpcbTotalBytes = (DWORD) 0;
  219. *lpNumObjectTypes = (DWORD) 0;
  220. return ERROR_SUCCESS; // yes, this is a successful exit
  221. }
  222. }
  223. // It is asking for our data. Currently, there are no instances and so that returned data has
  224. // the following layout.
  225. // PERF_OBJECT_TYPE describes object, in RegDataDefinition
  226. // PERF_COUNTER_DESCRIPTION describes counter 0, also in RegDataDefinition
  227. // .
  228. // .
  229. // PERF_COUNTER_DESCRIPTION describes counter n, also in RegDataDefinition
  230. // PERF_COUNTER_BLOCK four bytes that has the size of the block and all counters
  231. // counter 0
  232. // .
  233. // .
  234. // counter n
  235. // Format and collect the data
  236. dwTotSize = sizeof(PERF_COUNTER_BLOCK);
  237. for (x=0; x<MAXVALUES; x++) {
  238. dwDataSize[x] = GetData(&Data[x], x);
  239. dwTotSize += dwDataSize[x];
  240. }
  241. SpaceNeeded = sizeof(REG_DATA_DEFINITION) + dwTotSize;
  242. if (*lpcbTotalBytes < SpaceNeeded ) {
  243. *lpcbTotalBytes = (DWORD) 0;
  244. *lpNumObjectTypes = (DWORD) 0;
  245. return ERROR_MORE_DATA;
  246. }
  247. pRegDataDefinition = (REG_DATA_DEFINITION *) *lppData;
  248. // Copy the (constant, initialized) Object type and counter definitions
  249. // to the caller's data buffer
  250. memset(pRegDataDefinition, '\0', SpaceNeeded);
  251. memmove(pRegDataDefinition,
  252. &RegDataDefinition,
  253. sizeof(REG_DATA_DEFINITION));
  254. // Position to header of performance data (just after counter definition)
  255. pPerfCounterBlock = (PERF_COUNTER_BLOCK *) &pRegDataDefinition[1];
  256. // Move the values in
  257. // Set input parameter to point just after performance
  258. // data (a requirement for collectdata routines)
  259. // Total length of returned structure
  260. // Set length of performance data
  261. pRegDataDefinition->RegObjectType.TotalByteLength += dwTotSize;
  262. pRegCounterDefinition = (PERF_COUNTER_DEFINITION *) (
  263. ((PBYTE) pRegDataDefinition) + pRegDataDefinition->RegObjectType.HeaderLength);
  264. dwDataOffset = sizeof(PERF_COUNTER_BLOCK);
  265. pPerfCounterBlock->ByteLength = dwTotSize;
  266. for (x=0; x<MAXVALUES; x++) {
  267. pRegCounterDefinition->CounterSize = dwDataSize[x];
  268. pRegCounterDefinition->CounterOffset = dwDataOffset;
  269. memcpy((PBYTE) pPerfCounterBlock + dwDataOffset, &Data[x], dwDataSize[x]);
  270. dwDataOffset += dwDataSize[x];
  271. pRegCounterDefinition++;
  272. }
  273. *lppData = (PBYTE) pRegDataDefinition + pRegDataDefinition->RegObjectType.TotalByteLength;
  274. *lpcbTotalBytes = pRegDataDefinition->RegObjectType.TotalByteLength;
  275. // update arguments for return
  276. *lpNumObjectTypes = 1; // Number of objects returned (objects, not counters)
  277. return ERROR_SUCCESS;
  278. }
  279. DWORD APIENTRY
  280. CloseWmiPerformanceData(
  281. )
  282. /*++
  283. Routine Description:
  284. This routine closes the open handles.
  285. Arguments:
  286. None.
  287. Return Value:
  288. ERROR_SUCCESS
  289. --*/
  290. {
  291. if (!(--dwOpenCount)) { // when this is the last thread...
  292. MonCloseEventLog();
  293. }
  294. return ERROR_SUCCESS;
  295. }
  296. DWORD APIENTRY WriteCounter(DWORD dwCountNum, DWORD dwCountValue)
  297. /*++
  298. Routine Description:
  299. This routine is where wbemcore.dll calls to set a counter value.
  300. Arguments:
  301. IN DWORD dwCountNum
  302. Counter to be set.
  303. IN DWORD dwCountValue
  304. New counter value.
  305. Return Value:
  306. ERROR_SUCCESS
  307. --*/
  308. {
  309. if(dwCountNum < MAXVALUES)
  310. {
  311. dwCounterValues[dwCountNum] = dwCountValue;
  312. return 0;
  313. }
  314. else
  315. return ERROR_INVALID_PARAMETER;
  316. }
  317. //***************************************************************************
  318. //
  319. // DllRegisterServer
  320. //
  321. // Standard OLE entry point for registering the server.
  322. //
  323. // RETURN VALUES:
  324. //
  325. // S_OK Registration was successful
  326. // E_FAIL Registration failed.
  327. //
  328. //***************************************************************************
  329. HRESULT APIENTRY DllRegisterServer(void)
  330. {
  331. HKEY hKey;
  332. DWORD dw = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  333. "SYSTEM\\CurrentControlSet\\Services\\winmgmt\\Performance", 0,
  334. NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
  335. if(dw == ERROR_SUCCESS)
  336. {
  337. RegSetValueEx(hKey,"Library", 0, REG_SZ,"wmiperf.dll", 12);
  338. RegSetValueEx(hKey,"Open", 0, REG_SZ, "OpenWmiPerformanceData", 23);
  339. RegSetValueEx(hKey,"Collect", 0, REG_SZ,"CollectWmiPerformanceData", 26);
  340. RegSetValueEx(hKey,"Close", 0, REG_SZ, "CloseWmiPerformanceData", 24);
  341. RegCloseKey(hKey);
  342. }
  343. else
  344. return E_FAIL;
  345. dw = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  346. "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\wmiperf", 0,
  347. NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
  348. if(dw == ERROR_SUCCESS)
  349. {
  350. DWORD dwTemp = 7;
  351. RegSetValueEx(hKey,"EventMessageFile", 0, REG_EXPAND_SZ,
  352. "%systemroot%\\system32\\wmiperf.dll", 34);
  353. RegSetValueEx(hKey,"TypesSupported", 0, REG_DWORD, (BYTE *)&dwTemp, 4);
  354. RegCloseKey(hKey);
  355. }
  356. else
  357. return E_FAIL;
  358. return S_OK;
  359. }
  360. //***************************************************************************
  361. //
  362. // DllUnregisterServer
  363. //
  364. // Standard OLE entry point for unregistering the server.
  365. //
  366. // RETURN VALUES:
  367. //
  368. // S_OK Unregistration was successful
  369. // E_FAIL Unregistration failed.
  370. //
  371. //***************************************************************************
  372. HRESULT APIENTRY DllUnregisterServer(void)
  373. {
  374. DWORD dw = RegDeleteKey(HKEY_LOCAL_MACHINE,
  375. "SYSTEM\\CurrentControlSet\\Services\\winmgmt\\Performance");
  376. if(dw != ERROR_SUCCESS)
  377. return E_FAIL;
  378. dw = RegDeleteKey(HKEY_LOCAL_MACHINE,
  379. "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\wmiperf");
  380. if(dw != ERROR_SUCCESS)
  381. return E_FAIL;
  382. else
  383. return S_OK;
  384. }