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.

561 lines
15 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. Utility functions used by the performance library functions
  7. Author:
  8. Russ Blake 11/15/91
  9. Revision History:
  10. 8-Jun-98 bobw revised for use with WBEM functions
  11. --*/
  12. #define UNICODE
  13. //
  14. // Include files
  15. //
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <winperf.h>
  21. //#include <prflbmsg.h>
  22. //#include <regrpc.h>
  23. #include "PerfAcc.h"
  24. #include "strings.h"
  25. #include "utils.h"
  26. #include "wbprfmsg.h"
  27. // test for delimiter, end of line and non-digit characters
  28. // used by IsNumberInUnicodeList routine
  29. //
  30. #define DIGIT 1
  31. #define DELIMITER 2
  32. #define INVALID 3
  33. #define EvalThisChar(c,d) ( \
  34. (c == d) ? DELIMITER : \
  35. (c == 0) ? DELIMITER : \
  36. (c < '0') ? INVALID : \
  37. (c > '9') ? INVALID : \
  38. DIGIT)
  39. // the length of "ADDEXPLAIN" in chars
  40. #define MAX_KEYWORD_LEN 10
  41. // minimum length to hold a value name understood by Perflib
  42. // "foreign" is the longest "string" value understood
  43. const DWORD VALUE_NAME_LENGTH = ((7 + 1) * sizeof(WCHAR));
  44. HANDLE hEventLog = NULL;
  45. static WCHAR LocalComputerName[MAX_PATH];
  46. static LPWSTR pComputerName = &LocalComputerName[0];
  47. static DWORD ComputerNameLength = 0;
  48. BOOL
  49. MonBuildPerfDataBlock(
  50. PERF_DATA_BLOCK *pBuffer,
  51. PVOID *pBufferNext,
  52. DWORD NumObjectTypes,
  53. DWORD DefaultObject
  54. )
  55. /*++
  56. MonBuildPerfDataBlock - build the PERF_DATA_BLOCK structure
  57. Inputs:
  58. pBuffer - where the data block should be placed
  59. pBufferNext - where pointer to next byte of data block
  60. is to begin; DWORD aligned
  61. NumObjectTypes - number of types of objects being reported
  62. DefaultObject - object to display by default when
  63. this system is selected; this is the
  64. object type title index
  65. --*/
  66. {
  67. LARGE_INTEGER Time, TimeX10000;
  68. // Initialize Signature and version ID for this data structure
  69. pBuffer->Signature[0] = wc_P;
  70. pBuffer->Signature[1] = wc_E;
  71. pBuffer->Signature[2] = wc_R;
  72. pBuffer->Signature[3] = wc_F;
  73. pBuffer->LittleEndian = 1;
  74. pBuffer->Version = PERF_DATA_VERSION;
  75. pBuffer->Revision = PERF_DATA_REVISION;
  76. //
  77. // The next field will be filled in at the end when the length
  78. // of the return data is known
  79. //
  80. pBuffer->TotalByteLength = 0;
  81. pBuffer->NumObjectTypes = NumObjectTypes;
  82. pBuffer->DefaultObject = DefaultObject;
  83. GetSystemTime(&pBuffer->SystemTime);
  84. NtQueryPerformanceCounter(&pBuffer->PerfTime,&pBuffer->PerfFreq);
  85. TimeX10000.QuadPart = pBuffer->PerfTime.QuadPart * 10000L;
  86. Time.QuadPart = TimeX10000.QuadPart / pBuffer->PerfFreq.LowPart;
  87. pBuffer->PerfTime100nSec.QuadPart = Time.QuadPart * 1000L;
  88. if ( ComputerNameLength == 0) {
  89. // load the name
  90. ComputerNameLength = sizeof (LocalComputerName) / sizeof(LocalComputerName[0]);
  91. if (!GetComputerNameW(pComputerName, &ComputerNameLength)) {
  92. // name look up failed so reset length
  93. ComputerNameLength = 0;
  94. }
  95. assert (ComputerNameLength > 0);
  96. }
  97. // There is a Computer name: i.e., the network is installed
  98. pBuffer->SystemNameLength = ComputerNameLength;
  99. pBuffer->SystemNameOffset = sizeof(PERF_DATA_BLOCK);
  100. RtlMoveMemory(&pBuffer[1],
  101. pComputerName,
  102. ComputerNameLength);
  103. *pBufferNext = (PVOID) ((PCHAR) &pBuffer[1] +
  104. QWORD_MULTIPLE(ComputerNameLength));
  105. pBuffer->HeaderLength = (DWORD)((PCHAR) *pBufferNext - (PCHAR) pBuffer);
  106. return 0;
  107. }
  108. //
  109. // Perflib functions:
  110. //
  111. LONG
  112. GetPerflibKeyValue (
  113. LPCWSTR szItem,
  114. DWORD dwRegType,
  115. DWORD dwMaxSize, // ... of pReturnBuffer in bytes
  116. LPVOID pReturnBuffer,
  117. DWORD dwDefaultSize, // ... of pDefault in bytes
  118. LPVOID pDefault
  119. )
  120. /*++
  121. read and return the current value of the specified value
  122. under the Perflib registry key. If unable to read the value
  123. return the default value from the argument list.
  124. the value is returned in the pReturnBuffer.
  125. --*/
  126. {
  127. HKEY hPerflibKey;
  128. OBJECT_ATTRIBUTES Obja;
  129. NTSTATUS Status;
  130. UNICODE_STRING PerflibSubKeyString;
  131. UNICODE_STRING ValueNameString;
  132. LONG lReturn = STATUS_SUCCESS;
  133. PKEY_VALUE_PARTIAL_INFORMATION pValueInformation;
  134. ULONG ValueBufferLength;
  135. ULONG ResultLength;
  136. BOOL bUseDefault = TRUE;
  137. // initialize UNICODE_STRING structures used in this function
  138. RtlInitUnicodeString (
  139. &PerflibSubKeyString,
  140. cszPerflibKey);
  141. RtlInitUnicodeString (
  142. &ValueNameString,
  143. (LPWSTR)szItem);
  144. //
  145. // Initialize the OBJECT_ATTRIBUTES structure and open the key.
  146. //
  147. InitializeObjectAttributes(
  148. &Obja,
  149. &PerflibSubKeyString,
  150. OBJ_CASE_INSENSITIVE,
  151. NULL,
  152. NULL
  153. );
  154. Status = NtOpenKey(
  155. &hPerflibKey,
  156. KEY_READ,
  157. &Obja
  158. );
  159. if (NT_SUCCESS( Status )) {
  160. // read value of desired entry
  161. ValueBufferLength = ResultLength = 1024;
  162. pValueInformation = ALLOCMEM(RtlProcessHeap(), 0, ResultLength);
  163. if (pValueInformation != NULL) {
  164. while ( (Status = NtQueryValueKey(hPerflibKey,
  165. &ValueNameString,
  166. KeyValuePartialInformation,
  167. pValueInformation,
  168. ValueBufferLength,
  169. &ResultLength))
  170. == STATUS_BUFFER_OVERFLOW ) {
  171. pValueInformation = REALLOCMEM(RtlProcessHeap(), 0,
  172. pValueInformation,
  173. ResultLength);
  174. if ( pValueInformation == NULL) {
  175. break;
  176. } else {
  177. ValueBufferLength = ResultLength;
  178. }
  179. }
  180. if (NT_SUCCESS(Status)) {
  181. // check to see if it's the desired type
  182. if (pValueInformation->Type == dwRegType) {
  183. // see if it will fit
  184. if (pValueInformation->DataLength <= dwMaxSize) {
  185. memcpy (pReturnBuffer, &pValueInformation->Data[0],
  186. pValueInformation->DataLength);
  187. bUseDefault = FALSE;
  188. lReturn = STATUS_SUCCESS;
  189. }
  190. }
  191. } else {
  192. // return the default value
  193. lReturn = Status;
  194. }
  195. // release temp buffer
  196. if (pValueInformation) {
  197. FREEMEM (RtlProcessHeap(), 0, pValueInformation);
  198. }
  199. } else {
  200. // unable to allocate memory for this operation so
  201. // just return the default value
  202. }
  203. // close the registry key
  204. NtClose(hPerflibKey);
  205. } else {
  206. // return default value
  207. }
  208. if (bUseDefault) {
  209. memcpy (pReturnBuffer, pDefault, dwDefaultSize);
  210. lReturn = STATUS_SUCCESS;
  211. }
  212. return lReturn;
  213. }
  214. #pragma warning ( disable : 4127) // while (TRUE) error
  215. BOOL
  216. MatchString (
  217. IN LPCWSTR lpValueArg,
  218. IN LPCWSTR lpNameArg
  219. )
  220. /*++
  221. MatchString
  222. return TRUE if lpName is in lpValue. Otherwise return FALSE
  223. Arguments
  224. IN lpValue
  225. string passed to PerfRegQuery Value for processing
  226. IN lpName
  227. string for one of the keyword names
  228. Return TRUE | FALSE
  229. --*/
  230. {
  231. BOOL bFound = TRUE; // assume found until contradicted
  232. LPWSTR lpValue = (LPWSTR)lpValueArg;
  233. LPWSTR lpName = (LPWSTR)lpNameArg;
  234. // check to the length of the shortest string
  235. while (1) {
  236. if (*lpValue != 0) {
  237. if (*lpName != 0) {
  238. if (*lpValue++ != *lpName++) {
  239. bFound = FALSE; // no match
  240. break; // bail out now
  241. }
  242. } else {
  243. // the value still has characters, but the name is out
  244. // so this is no match
  245. bFound = FALSE;
  246. break;
  247. }
  248. } else {
  249. if (*lpName != 0) {
  250. // then the value is out of characters, but the name
  251. // is out so no match
  252. bFound = FALSE;
  253. break;
  254. } else {
  255. // both strings are at the end so it must be a match
  256. }
  257. }
  258. }
  259. return (bFound);
  260. }
  261. #pragma warning ( default : 4127) // while (TRUE) error
  262. DWORD
  263. GetQueryType (
  264. IN LPWSTR lpValue
  265. )
  266. /*++
  267. GetQueryType
  268. returns the type of query described in the lpValue string so that
  269. the appropriate processing method may be used
  270. Arguments
  271. IN lpValue
  272. string passed to PerfRegQuery Value for processing
  273. Return Value
  274. QUERY_GLOBAL
  275. if lpValue == 0 (null pointer)
  276. lpValue == pointer to Null string
  277. lpValue == pointer to "Global" string
  278. QUERY_FOREIGN
  279. if lpValue == pointer to "Foriegn" string
  280. QUERY_COSTLY
  281. if lpValue == pointer to "Costly" string
  282. QUERY_COUNTER
  283. if lpValue == pointer to "Counter" string
  284. QUERY_HELP
  285. if lpValue == pointer to "Explain" string
  286. QUERY_ADDCOUNTER
  287. if lpValue == pointer to "Addcounter" string
  288. QUERY_ADDHELP
  289. if lpValue == pointer to "Addexplain" string
  290. otherwise:
  291. QUERY_ITEMS
  292. --*/
  293. {
  294. WCHAR LocalBuff[MAX_KEYWORD_LEN+1];
  295. int i;
  296. if ((lpValue == 0 || *lpValue == 0))
  297. return QUERY_GLOBAL;
  298. // convert the input string to Upper case before matching
  299. for (i=0; i < MAX_KEYWORD_LEN; i++) {
  300. if ((*lpValue == wcSpace) || (*lpValue == 0)) {
  301. break;
  302. }
  303. LocalBuff[i] = *lpValue ;
  304. if (*lpValue >= wc_a && *lpValue <= wc_z) {
  305. LocalBuff[i] = (WCHAR)(LocalBuff[i] - (WCHAR)wc_a + (WCHAR)wc_A);
  306. }
  307. lpValue++ ;
  308. }
  309. LocalBuff[i] = 0;
  310. // check for "Global" request
  311. if (MatchString (LocalBuff, cszGlobal))
  312. return QUERY_GLOBAL ;
  313. // check for "Foreign" request
  314. if (MatchString (LocalBuff, cszForeign))
  315. return QUERY_FOREIGN ;
  316. // check for "Costly" request
  317. if (MatchString (LocalBuff, cszCostly))
  318. return QUERY_COSTLY;
  319. // check for "Counter" request
  320. if (MatchString (LocalBuff, cszCounter))
  321. return QUERY_COUNTER;
  322. // check for "Help" request
  323. if (MatchString (LocalBuff, cszHelp))
  324. return QUERY_HELP;
  325. if (MatchString (LocalBuff, cszExplain))
  326. return QUERY_HELP;
  327. // check for "AddCounter" request
  328. if (MatchString (LocalBuff, cszAddCounter))
  329. return QUERY_ADDCOUNTER;
  330. // check for "AddHelp" request
  331. if (MatchString (LocalBuff, cszAddHelp))
  332. return QUERY_ADDHELP;
  333. // None of the above, then it must be an item list
  334. return QUERY_ITEMS;
  335. }
  336. #pragma warning ( disable : 4127) // while (TRUE) error
  337. DWORD
  338. GetNextNumberFromList (
  339. IN LPWSTR szStartChar,
  340. IN LPWSTR *szNextChar
  341. )
  342. /*++
  343. Reads a character string from the szStartChar to the next
  344. delimiting space character or the end of the string and returns
  345. the value of the decimal number found. If no valid number is found
  346. then 0 is returned. The pointer to the next character in the
  347. string is returned in the szNextChar parameter. If the character
  348. referenced by this pointer is 0, then the end of the string has
  349. been reached.
  350. --*/
  351. {
  352. DWORD dwThisNumber = 0;
  353. WCHAR *pwcThisChar = szStartChar;
  354. WCHAR wcDelimiter = wcSpace;
  355. BOOL bValidNumber = FALSE;
  356. if (szStartChar != 0) {
  357. while (TRUE) {
  358. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  359. case DIGIT:
  360. // if this is the first digit after a delimiter, then
  361. // set flags to start computing the new number
  362. bValidNumber = TRUE;
  363. dwThisNumber *= 10;
  364. dwThisNumber += (*pwcThisChar - wc_0);
  365. break;
  366. case DELIMITER:
  367. // a delimter is either the delimiter character or the
  368. // end of the string ('\0') if when the delimiter has been
  369. // reached a valid number was found, then return it
  370. //
  371. if (bValidNumber || (*pwcThisChar == 0)) {
  372. *szNextChar = pwcThisChar;
  373. return dwThisNumber;
  374. } else {
  375. // continue until a non-delimiter char or the
  376. // end of the file is found
  377. }
  378. break;
  379. case INVALID:
  380. // if an invalid character was encountered, ignore all
  381. // characters up to the next delimiter and then start fresh.
  382. // the invalid number is not compared.
  383. bValidNumber = FALSE;
  384. break;
  385. default:
  386. break;
  387. }
  388. pwcThisChar++;
  389. }
  390. } else {
  391. *szNextChar = szStartChar;
  392. return 0;
  393. }
  394. }
  395. #pragma warning ( default : 4127) // while (TRUE) error
  396. BOOL
  397. IsNumberInUnicodeList (
  398. IN DWORD dwNumber,
  399. IN LPWSTR lpwszUnicodeList
  400. )
  401. /*++
  402. IsNumberInUnicodeList
  403. Arguments:
  404. IN dwNumber
  405. DWORD number to find in list
  406. IN lpwszUnicodeList
  407. Null terminated, Space delimited list of decimal numbers
  408. Return Value:
  409. TRUE:
  410. dwNumber was found in the list of unicode number strings
  411. FALSE:
  412. dwNumber was not found in the list.
  413. --*/
  414. {
  415. DWORD dwThisNumber;
  416. WCHAR *pwcThisChar;
  417. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  418. pwcThisChar = lpwszUnicodeList;
  419. dwThisNumber = 0;
  420. while (*pwcThisChar != 0) {
  421. dwThisNumber = GetNextNumberFromList (
  422. pwcThisChar, &pwcThisChar);
  423. if (dwNumber == dwThisNumber) return TRUE;
  424. }
  425. // if here, then the number wasn't found
  426. return FALSE;
  427. } // IsNumberInUnicodeList
  428. LPWSTR
  429. ConvertProcName(LPSTR strProcName)
  430. {
  431. static WCHAR wstrProcName[MAX_PATH];
  432. ULONG lenProcName = (strProcName == NULL) ? (0) : (lstrlenA(strProcName));
  433. ULONG i;
  434. PUCHAR AnsiChar;
  435. if ((lenProcName == 0) || (lenProcName >= MAX_PATH)) {
  436. return (LPWSTR) cszSpace;
  437. }
  438. for (i = 0; i < lenProcName; i ++) {
  439. AnsiChar = (PUCHAR) & strProcName[i];
  440. wstrProcName[i] = (WCHAR) RtlAnsiCharToUnicodeChar(& AnsiChar);
  441. }
  442. wstrProcName[lenProcName] = L'\0';
  443. return wstrProcName;
  444. }