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.

683 lines
18 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Main
  6. File: axperf.cpp
  7. Owner: LeiJin
  8. Abstract:
  9. This file implements the Extensible Objects for the ActiveX Server
  10. object type
  11. ===================================================================*/
  12. //--------------------------------------------------------------------
  13. // Include Files
  14. //
  15. //--------------------------------------------------------------------
  16. #include "denpre.h"
  17. #pragma hdrstop
  18. #include "windows.h"
  19. #include "winperf.h"
  20. #include "axpfdata.h"
  21. #include <perfdef.h> // from denali
  22. #include <perfutil.h>
  23. #define QUERY_GLOBAL 1
  24. #define QUERY_ITEMS 2
  25. #define QUERY_FOREIGN 3
  26. #define QUERY_COSTLY 4
  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 < (WCHAR)'0') ? INVALID : \
  37. (c > (WCHAR)'9') ? INVALID : \
  38. DIGIT)
  39. extern AXPD g_AxDataDefinition;
  40. DWORD g_dwOpenCount = 0;
  41. BOOL bInitOK = FALSE; // true = DLL Initialized OK
  42. // WinSE 5901
  43. CRITICAL_SECTION g_CS;
  44. WCHAR GLOBAL_STRING[] = L"Global";
  45. WCHAR FOREIGN_STRING[] = L"Foreign";
  46. WCHAR COSTLY_STRING[] = L"Costly";
  47. WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  48. /*
  49. * Output Debug String should occur in Debug only
  50. */
  51. #ifdef _DEBUG
  52. BOOL gfOutputDebugString = TRUE;
  53. #else
  54. BOOL gfOutputDebugString = FALSE;
  55. #endif
  56. #define DebugOutputDebugString(x) \
  57. {\
  58. if (gfOutputDebugString) \
  59. { \
  60. OutputDebugString(x); \
  61. } \
  62. }
  63. //-------------------------------------------------------------------
  64. // Function Prototypes
  65. //
  66. // these are used to insure that the data collection functions accessed
  67. // by Perf lib will have the correct calling format
  68. //-------------------------------------------------------------------
  69. DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames);
  70. DWORD APIENTRY CollectASPPerformanceData(LPWSTR lpValueName,
  71. LPVOID *lppData,
  72. LPDWORD lpcbTotalBytes,
  73. LPDWORD lpNumObjectTypes
  74. );
  75. DWORD APIENTRY CloseASPPerformanceData(void);
  76. DWORD APIENTRY RegisterAXS(void);
  77. DWORD APIENTRY UnRegisterAXS(void);
  78. DWORD GetQueryType (IN LPWSTR lpValue);
  79. BOOL IsNumberInUnicodeList ( IN DWORD dwNumber,
  80. IN LPWSTR lpwszUnicodeList);
  81. CPerfMainBlock g_Shared; // shared global memory block
  82. //--------------------------------------------------------------------
  83. //
  84. // OpenASPPerformanceData
  85. //
  86. // This routine will open and map the memory used by the ActiveX Server
  87. // to pass performance data in. This routine also initializes the data
  88. // structure used to pass data back to the registry.
  89. //
  90. // Arguments:
  91. //
  92. // Pointer to object ID to be opened.
  93. //
  94. // Return Value:
  95. //
  96. // None.
  97. //--------------------------------------------------------------------
  98. //extern "C" DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames)
  99. DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames)
  100. {
  101. int status;
  102. DWORD RetCode = ERROR_SUCCESS;
  103. PERF_COUNTER_DEFINITION *pCounterDef;
  104. DWORD size = sizeof(DWORD);
  105. DebugOutputDebugString("Open");
  106. // WinSE 5901
  107. EnterCriticalSection(&g_CS);
  108. LONG nOpenCount = InterlockedIncrement((LONG *)&g_dwOpenCount);
  109. if (nOpenCount > 1){
  110. goto ExitPathSuccess;
  111. };
  112. // Hold the counter to 1, even if we are no sure to have this
  113. // initialized correctly
  114. // open shared memory to pass performance values
  115. if (FAILED(g_Shared.Init())) {
  116. RetCode = ERROR_INVALID_HANDLE;
  117. goto ExitPath;
  118. }
  119. // get counter and help index base values from registry
  120. // Open key to registry entry
  121. // read first counter and first help values
  122. // update static data structures by adding base to offset
  123. // value in structure
  124. HKEY hKeyServerPerf;
  125. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  126. "SYSTEM\\CurrentControlSet\\Services\\ASP\\Performance",
  127. 0L,
  128. KEY_READ,
  129. &hKeyServerPerf);
  130. if (ERROR_SUCCESS != status) {
  131. RetCode = status;
  132. goto ExitPath;
  133. }
  134. DWORD type;
  135. DWORD dwFirstCounter;
  136. DWORD dwFirstHelp;
  137. status = RegQueryValueEx(hKeyServerPerf,
  138. "First Counter",
  139. 0L,
  140. &type,
  141. (LPBYTE)&dwFirstCounter,
  142. &size);
  143. if (ERROR_SUCCESS != status || size != sizeof(DWORD)) {
  144. RegCloseKey(hKeyServerPerf);
  145. RetCode = status;
  146. goto ExitPath;
  147. }
  148. status = RegQueryValueEx(hKeyServerPerf,
  149. "First Help",
  150. 0L,
  151. &type,
  152. (LPBYTE)&dwFirstHelp,
  153. &size);
  154. if (ERROR_SUCCESS != status || size != sizeof(DWORD)) {
  155. RegCloseKey(hKeyServerPerf);
  156. RetCode = status;
  157. goto ExitPath;
  158. }
  159. //
  160. // NOTE: the initialiation could also retrieve
  161. // LastCounter and LastHelp if they wanted
  162. // to do bounds checking on the new number
  163. //
  164. g_AxDataDefinition.AXSObjectType.ObjectNameTitleIndex += dwFirstCounter;
  165. g_AxDataDefinition.AXSObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  166. pCounterDef = (PERF_COUNTER_DEFINITION *)&(g_AxDataDefinition.Counters[0]);
  167. int i;
  168. for (i = 0; i < AX_NUM_PERFCOUNT; i++, pCounterDef++) {
  169. pCounterDef->CounterNameTitleIndex += dwFirstCounter;
  170. pCounterDef->CounterHelpTitleIndex += dwFirstHelp;
  171. }
  172. RegCloseKey(hKeyServerPerf); // close key to registry
  173. bInitOK = TRUE; // ok to use this function
  174. // we have already incremented g_dwOpenCount
  175. // before going through this path
  176. ExitPathSuccess:
  177. LeaveCriticalSection(&g_CS);
  178. return ERROR_SUCCESS;
  179. ExitPath:
  180. InterlockedDecrement((LONG *)&g_dwOpenCount);
  181. LeaveCriticalSection(&g_CS);
  182. return RetCode;
  183. }
  184. //--------------------------------------------------------------------
  185. // DWORD CollectASPPerformanceData
  186. //
  187. // Description:
  188. //
  189. // This routine will return the data for the AxctiveX Server counters.
  190. //
  191. // Arguments:
  192. //
  193. // IN LPWSTR lpValueName
  194. // pointer to a wide chacter string passed by registry
  195. //
  196. // IN OUT LPVOID *lppData
  197. // IN: pointer to the address of the buffer to receive the completed
  198. // PerfDataBlock and subordinate structures. This routine will
  199. // append its data to the buffer starting at the point referenced
  200. // by the *lppData
  201. // OUT:points to the first byte after the data structure added by
  202. // this routine. This routine updated the value at lppdata after
  203. // appending its data.
  204. //
  205. // IN OUT LPDWORD lpcbTotalBytes
  206. // IN: the address of the DWORD that tells the size in bytes of the
  207. // buffer referenced by the lppData argument
  208. // OUT:the number of bytes added by this routine is written to the
  209. // DWORD pointed to by this argument
  210. //
  211. // IN OUT LPDWORD NumObjectTypes
  212. // IN: the address of the DWORD that receives the number of the objects
  213. // added by this routine
  214. // OUT:the number of objects added by this routine is written to
  215. // the DWORD pointed to by this argument
  216. //
  217. //
  218. // Return Value:
  219. //
  220. // ERROR_MORE_DATA if buffer passed is too small to hold data
  221. //
  222. // ERROR_SUCCESS if success or any other error.
  223. //
  224. //--------------------------------------------------------------------
  225. DWORD APIENTRY CollectASPPerformanceData(IN LPWSTR lpValueName,
  226. IN OUT LPVOID *lppData,
  227. IN OUT LPDWORD lpcbTotalBytes,
  228. IN OUT LPDWORD lpNumObjectTypes)
  229. {
  230. // before doing anything else, see if Open went Ok.
  231. DebugOutputDebugString("collect");
  232. if(!bInitOK) {
  233. //unable to continue because open failed
  234. *lpcbTotalBytes = (DWORD) 0;
  235. *lpNumObjectTypes = (DWORD) 0;
  236. return ERROR_SUCCESS;
  237. }
  238. //
  239. // variables used for error logging
  240. DWORD dwQueryType;
  241. // see if this is a foreign(i.e. non-NT) computer data request
  242. dwQueryType = GetQueryType(lpValueName);
  243. if (QUERY_FOREIGN == dwQueryType) {
  244. // this routine does not service requests for data from
  245. // Non-NT computers
  246. *lpcbTotalBytes = (DWORD)0;
  247. *lpNumObjectTypes = (DWORD)0;
  248. return ERROR_SUCCESS;
  249. }
  250. if (QUERY_ITEMS == dwQueryType) {
  251. if (!(IsNumberInUnicodeList(g_AxDataDefinition.AXSObjectType.ObjectNameTitleIndex,
  252. lpValueName))) {
  253. // request received for data object not provided by this routine
  254. *lpcbTotalBytes = (DWORD)0;
  255. *lpNumObjectTypes = (DWORD)0;
  256. return ERROR_SUCCESS;
  257. }
  258. }
  259. if (QUERY_GLOBAL == dwQueryType) {
  260. /* Comment the following code out, looks like that it is for
  261. debugging only.
  262. int i;
  263. i++;
  264. */
  265. }
  266. AXPD *pAxDataDefinition = (AXPD *)*lppData;
  267. ULONG SpaceNeeded = QWORD_MULTIPLE((sizeof(AXPD) + SIZE_OF_AX_PERF_DATA));
  268. if ( *lpcbTotalBytes < SpaceNeeded) {
  269. *lpcbTotalBytes = (DWORD)0;
  270. *lpNumObjectTypes = (DWORD)0;
  271. return ERROR_MORE_DATA;
  272. }
  273. //
  274. //Copy the (constant, initialized) Object Type and counter defintions to the caller's
  275. //data buffer
  276. //
  277. memmove(pAxDataDefinition, &g_AxDataDefinition, sizeof(AXPD));
  278. //
  279. // Format and collect Active X server performance data from shared memory
  280. //
  281. PERF_COUNTER_BLOCK *pPerfCounterBlock = (PERF_COUNTER_BLOCK *)&pAxDataDefinition[1];
  282. pPerfCounterBlock->ByteLength = SIZE_OF_AX_PERF_DATA;
  283. PDWORD pdwCounter = (PDWORD)(&pPerfCounterBlock[1]);
  284. // Get statistics from shared memory
  285. if (FAILED(g_Shared.GetStats(pdwCounter))) {
  286. *lpcbTotalBytes = (DWORD)0;
  287. *lpNumObjectTypes = (DWORD)0;
  288. return ERROR_SUCCESS;
  289. }
  290. pdwCounter += AX_NUM_PERFCOUNT;
  291. // update arguments for return
  292. *lpNumObjectTypes = 1;
  293. *lpcbTotalBytes = QWORD_MULTIPLE((DIFF((PBYTE)pdwCounter - (PBYTE)pAxDataDefinition)));
  294. *lppData = (PBYTE)(*lppData) + *lpcbTotalBytes;
  295. return ERROR_SUCCESS;
  296. }
  297. //-------------------------------------------------------------------
  298. // DWORD CloseASPPerformanceData
  299. //
  300. // Description:
  301. //
  302. // This routine closes the open handles to ActiveX Server performance
  303. // counters.
  304. //
  305. // Arguments:
  306. //
  307. // None.
  308. //
  309. // Return Value:
  310. //
  311. // ERROR_SUCCESS
  312. //
  313. //--------------------------------------------------------------------
  314. DWORD APIENTRY CloseASPPerformanceData(void)
  315. {
  316. DebugOutputDebugString("Close");
  317. EnterCriticalSection(&g_CS);
  318. LONG nLeft = InterlockedDecrement((LONG *)&g_dwOpenCount);
  319. if (nLeft == 0) {
  320. g_Shared.UnInit();
  321. bInitOK = FALSE;
  322. };
  323. LeaveCriticalSection(&g_CS);
  324. return ERROR_SUCCESS;
  325. }
  326. static const TCHAR szPerformance[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\ASP\\Performance");
  327. static const TCHAR szAXS[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\ASP");
  328. static const TCHAR szLibrary[] = TEXT("Library");
  329. static const TCHAR szOpen[] = TEXT("Open");
  330. static const TCHAR szClose[] = TEXT("Close");
  331. static const TCHAR szCollect[] = TEXT("Collect");
  332. static const TCHAR szLibraryValue[] = TEXT("aspperf.dll");
  333. static const TCHAR szOpenValue[] = TEXT("OpenASPPerformanceData");
  334. static const TCHAR szCloseValue[] = TEXT("CloseASPPerformanceData");
  335. static const TCHAR szCollectValue[] = TEXT("CollectASPPerformanceData");
  336. //--------------------------------------------------------------------
  337. //
  338. //
  339. //--------------------------------------------------------------------
  340. DWORD APIENTRY RegisterAXS(void)
  341. {
  342. HKEY hkey;
  343. if ((RegCreateKey(HKEY_LOCAL_MACHINE, szPerformance, &hkey)) != ERROR_SUCCESS)
  344. return E_FAIL;
  345. if ((RegSetValueEx(hkey, szLibrary, 0, REG_SZ, (const unsigned char *)&szLibraryValue, lstrlen(szLibraryValue))) != ERROR_SUCCESS)
  346. goto LRegErr;
  347. if ((RegSetValueEx(hkey, szOpen, 0, REG_SZ, (const unsigned char *)&szOpenValue, lstrlen(szOpenValue))) != ERROR_SUCCESS)
  348. goto LRegErr;
  349. if ((RegSetValueEx(hkey, szClose, 0, REG_SZ, (const unsigned char *)&szCloseValue, lstrlen(szCloseValue))) != ERROR_SUCCESS)
  350. goto LRegErr;
  351. if ((RegSetValueEx(hkey, szCollect, 0, REG_SZ, (const unsigned char *)&szCollectValue, lstrlen(szCollectValue))) != ERROR_SUCCESS)
  352. goto LRegErr;
  353. RegCloseKey(hkey);
  354. return NOERROR;
  355. LRegErr:
  356. RegCloseKey(hkey);
  357. return E_FAIL;
  358. }
  359. //--------------------------------------------------------------------
  360. //
  361. //
  362. //--------------------------------------------------------------------
  363. DWORD APIENTRY UnRegisterAXS(void)
  364. {
  365. if ((RegDeleteKey(HKEY_LOCAL_MACHINE, szPerformance)) != ERROR_SUCCESS)
  366. return (E_FAIL);
  367. if ((RegDeleteKey(HKEY_LOCAL_MACHINE, szAXS)) != ERROR_SUCCESS)
  368. return (E_FAIL);
  369. else
  370. return NOERROR;
  371. }
  372. DWORD
  373. GetQueryType (
  374. IN LPWSTR lpValue
  375. )
  376. /*++
  377. GetQueryType
  378. returns the type of query described in the lpValue string so that
  379. the appropriate processing method may be used
  380. Arguments
  381. IN lpValue
  382. string passed to PerfRegQuery Value for processing
  383. Return Value
  384. QUERY_GLOBAL
  385. if lpValue == 0 (null pointer)
  386. lpValue == pointer to Null string
  387. lpValue == pointer to "Global" string
  388. QUERY_FOREIGN
  389. if lpValue == pointer to "Foriegn" string
  390. QUERY_COSTLY
  391. if lpValue == pointer to "Costly" string
  392. otherwise:
  393. QUERY_ITEMS
  394. --*/
  395. {
  396. WCHAR *pwcArgChar, *pwcTypeChar;
  397. BOOL bFound;
  398. if (lpValue == 0) {
  399. return QUERY_GLOBAL;
  400. } else if (*lpValue == 0) {
  401. return QUERY_GLOBAL;
  402. }
  403. // check for "Global" request
  404. pwcArgChar = lpValue;
  405. pwcTypeChar = GLOBAL_STRING;
  406. bFound = TRUE; // assume found until contradicted
  407. // check to the length of the shortest string
  408. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  409. if (*pwcArgChar++ != *pwcTypeChar++) {
  410. bFound = FALSE; // no match
  411. break; // bail out now
  412. }
  413. }
  414. if (bFound) return QUERY_GLOBAL;
  415. // check for "Foreign" request
  416. pwcArgChar = lpValue;
  417. pwcTypeChar = FOREIGN_STRING;
  418. bFound = TRUE; // assume found until contradicted
  419. // check to the length of the shortest string
  420. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  421. if (*pwcArgChar++ != *pwcTypeChar++) {
  422. bFound = FALSE; // no match
  423. break; // bail out now
  424. }
  425. }
  426. if (bFound) return QUERY_FOREIGN;
  427. // check for "Costly" request
  428. pwcArgChar = lpValue;
  429. pwcTypeChar = COSTLY_STRING;
  430. bFound = TRUE; // assume found until contradicted
  431. // check to the length of the shortest string
  432. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  433. if (*pwcArgChar++ != *pwcTypeChar++) {
  434. bFound = FALSE; // no match
  435. break; // bail out now
  436. }
  437. }
  438. if (bFound) return QUERY_COSTLY;
  439. // if not Global and not Foreign and not Costly,
  440. // then it must be an item list
  441. return QUERY_ITEMS;
  442. }
  443. BOOL
  444. IsNumberInUnicodeList (
  445. IN DWORD dwNumber,
  446. IN LPWSTR lpwszUnicodeList
  447. )
  448. /*++
  449. IsNumberInUnicodeList
  450. Arguments:
  451. IN dwNumber
  452. DWORD number to find in list
  453. IN lpwszUnicodeList
  454. Null terminated, Space delimited list of decimal numbers
  455. Return Value:
  456. TRUE:
  457. dwNumber was found in the list of unicode number strings
  458. FALSE:
  459. dwNumber was not found in the list.
  460. --*/
  461. {
  462. DWORD dwThisNumber;
  463. WCHAR *pwcThisChar;
  464. BOOL bValidNumber;
  465. BOOL bNewItem;
  466. //BOOL bReturnValue;
  467. WCHAR wcDelimiter; // could be an argument to be more flexible
  468. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  469. pwcThisChar = lpwszUnicodeList;
  470. dwThisNumber = 0;
  471. wcDelimiter = (WCHAR)' ';
  472. bValidNumber = FALSE;
  473. bNewItem = TRUE;
  474. while (TRUE) {
  475. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  476. case DIGIT:
  477. // if this is the first digit after a delimiter, then
  478. // set flags to start computing the new number
  479. if (bNewItem) {
  480. bNewItem = FALSE;
  481. bValidNumber = TRUE;
  482. }
  483. if (bValidNumber) {
  484. dwThisNumber *= 10;
  485. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  486. }
  487. break;
  488. case DELIMITER:
  489. // a delimter is either the delimiter character or the
  490. // end of the string ('\0') if when the delimiter has been
  491. // reached a valid number was found, then compare it to the
  492. // number from the argument list. if this is the end of the
  493. // string and no match was found, then return.
  494. //
  495. if (bValidNumber) {
  496. if (dwThisNumber == dwNumber) return TRUE;
  497. bValidNumber = FALSE;
  498. }
  499. if (*pwcThisChar == 0) {
  500. return FALSE;
  501. } else {
  502. bNewItem = TRUE;
  503. dwThisNumber = 0;
  504. }
  505. break;
  506. case INVALID:
  507. // if an invalid character was encountered, ignore all
  508. // characters up to the next delimiter and then start fresh.
  509. // the invalid number is not compared.
  510. bValidNumber = FALSE;
  511. break;
  512. default:
  513. break;
  514. }
  515. pwcThisChar++;
  516. }
  517. } // IsNumberInUnicodeList
  518. STDAPI DLLRegisterServer(void)
  519. {
  520. return RegisterAXS();
  521. }
  522. BOOL WINAPI DllMain(HINSTANCE hInstDLL, // handle to the DLL module
  523. DWORD dwReason, // reason for calling function
  524. LPVOID lpvReserved // reserved
  525. )
  526. {
  527. switch(dwReason){
  528. case DLL_PROCESS_ATTACH:
  529. DisableThreadLibraryCalls(hInstDLL);
  530. InitializeCriticalSection(&g_CS);
  531. return TRUE;
  532. case DLL_PROCESS_DETACH:
  533. DeleteCriticalSection(&g_CS);
  534. return TRUE;
  535. }
  536. return TRUE;
  537. }