Leaked source code of windows server 2003
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.

820 lines
23 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. #define _NO_TRACING_
  22. #include "dbgutil.h"
  23. //DECLARE_DEBUG_PRINTS_OBJECT();
  24. //DECLARE_DEBUG_VARIABLE();
  25. #include <asppdef.h> // from denali
  26. #include <perfutil.h>
  27. #define QUERY_GLOBAL 1
  28. #define QUERY_ITEMS 2
  29. #define QUERY_FOREIGN 3
  30. #define QUERY_COSTLY 4
  31. // test for delimiter, end of line and non-digit characters
  32. // used by IsNumberInUnicodeList routine
  33. //
  34. #define DIGIT 1
  35. #define DELIMITER 2
  36. #define INVALID 3
  37. #define EvalThisChar(c,d) ( \
  38. (c == d) ? DELIMITER : \
  39. (c == 0) ? DELIMITER : \
  40. (c < (WCHAR)'0') ? INVALID : \
  41. (c > (WCHAR)'9') ? INVALID : \
  42. DIGIT)
  43. extern AXPD g_AxDataDefinition;
  44. DWORD g_dwOpenCount = 0;
  45. BOOL bInitOK = FALSE; // true = DLL Initialized OK
  46. BOOL bSharedMemInitd = FALSE; // state of Shared init
  47. HANDLE g_hASPWASProcessWait = NULL; // handle to the W3SVC process
  48. // so we know when to release
  49. // the counters.
  50. // WinSE 5901
  51. CRITICAL_SECTION g_CS;
  52. WCHAR GLOBAL_STRING[] = L"Global";
  53. WCHAR FOREIGN_STRING[] = L"Foreign";
  54. WCHAR COSTLY_STRING[] = L"Costly";
  55. WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  56. /*
  57. * Output Debug String should occur in Debug only
  58. */
  59. #ifdef _DEBUG
  60. BOOL gfOutputDebugString = TRUE;
  61. #else
  62. BOOL gfOutputDebugString = FALSE;
  63. #endif
  64. #define DebugOutputDebugString(x) \
  65. {\
  66. if (gfOutputDebugString) \
  67. { \
  68. OutputDebugString(x); \
  69. } \
  70. }
  71. //-------------------------------------------------------------------
  72. // Function Prototypes
  73. //
  74. // these are used to insure that the data collection functions accessed
  75. // by Perf lib will have the correct calling format
  76. //-------------------------------------------------------------------
  77. DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames);
  78. DWORD APIENTRY CollectASPPerformanceData(LPWSTR lpValueName,
  79. LPVOID *lppData,
  80. LPDWORD lpcbTotalBytes,
  81. LPDWORD lpNumObjectTypes
  82. );
  83. DWORD APIENTRY CloseASPPerformanceData(void);
  84. DWORD APIENTRY RegisterAXS(void);
  85. DWORD APIENTRY UnRegisterAXS(void);
  86. DWORD GetQueryType (IN LPWSTR lpValue);
  87. BOOL IsNumberInUnicodeList ( IN DWORD dwNumber,
  88. IN LPWSTR lpwszUnicodeList);
  89. CPerfMainBlock g_Shared; // shared global memory block
  90. /***************************************************************************++
  91. Routine Description:
  92. Routine drops the shared memory if the managing process of the memory
  93. goes away.
  94. Arguments:
  95. LPVOID lpParameter - Unused
  96. BOOL bUnused - Unused
  97. Return Value:
  98. None
  99. --***************************************************************************/
  100. VOID CALLBACK ShutdownMemory(
  101. PVOID,
  102. BOOLEAN
  103. )
  104. {
  105. EnterCriticalSection ( &g_CS );
  106. //
  107. // Now clean up the shared memory object.
  108. //
  109. if ( bSharedMemInitd )
  110. {
  111. g_Shared.UnInit();
  112. bSharedMemInitd = FALSE;
  113. }
  114. LeaveCriticalSection ( &g_CS );
  115. }
  116. //--------------------------------------------------------------------
  117. //
  118. // OpenASPPerformanceData
  119. //
  120. // This routine will open and map the memory used by the ActiveX Server
  121. // to pass performance data in. This routine also initializes the data
  122. // structure used to pass data back to the registry.
  123. //
  124. // Arguments:
  125. //
  126. // Pointer to object ID to be opened.
  127. //
  128. // Return Value:
  129. //
  130. // None.
  131. //--------------------------------------------------------------------
  132. //extern "C" DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames)
  133. DWORD APIENTRY OpenASPPerformanceData(LPWSTR lpDeviceNames)
  134. {
  135. int status;
  136. DWORD RetCode = ERROR_SUCCESS;
  137. PERF_COUNTER_DEFINITION *pCounterDef;
  138. DWORD size = sizeof(DWORD);
  139. DebugOutputDebugString("Open");
  140. // WinSE 5901
  141. EnterCriticalSection(&g_CS);
  142. LONG nOpenCount = InterlockedIncrement((LONG *)&g_dwOpenCount);
  143. if (nOpenCount > 1){
  144. goto ExitPathSuccess;
  145. };
  146. // Hold the counter to 1, even if we are no sure to have this
  147. // initialized correctly
  148. // get counter and help index base values from registry
  149. // Open key to registry entry
  150. // read first counter and first help values
  151. // update static data structures by adding base to offset
  152. // value in structure
  153. HKEY hKeyServerPerf;
  154. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  155. "SYSTEM\\CurrentControlSet\\Services\\ASP\\Performance",
  156. 0L,
  157. KEY_READ,
  158. &hKeyServerPerf);
  159. if (ERROR_SUCCESS != status) {
  160. RetCode = status;
  161. goto ExitPath;
  162. }
  163. DWORD type;
  164. DWORD dwFirstCounter;
  165. DWORD dwFirstHelp;
  166. status = RegQueryValueEx(hKeyServerPerf,
  167. "First Counter",
  168. 0L,
  169. &type,
  170. (LPBYTE)&dwFirstCounter,
  171. &size);
  172. if (ERROR_SUCCESS != status || size != sizeof(DWORD)) {
  173. RegCloseKey(hKeyServerPerf);
  174. RetCode = status;
  175. goto ExitPath;
  176. }
  177. status = RegQueryValueEx(hKeyServerPerf,
  178. "First Help",
  179. 0L,
  180. &type,
  181. (LPBYTE)&dwFirstHelp,
  182. &size);
  183. if (ERROR_SUCCESS != status || size != sizeof(DWORD)) {
  184. RegCloseKey(hKeyServerPerf);
  185. RetCode = status;
  186. goto ExitPath;
  187. }
  188. //
  189. // NOTE: the initialiation could also retrieve
  190. // LastCounter and LastHelp if they wanted
  191. // to do bounds checking on the new number
  192. //
  193. g_AxDataDefinition.AXSObjectType.ObjectNameTitleIndex += dwFirstCounter;
  194. g_AxDataDefinition.AXSObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  195. pCounterDef = (PERF_COUNTER_DEFINITION *)&(g_AxDataDefinition.Counters[0]);
  196. int i;
  197. for (i = 0; i < AX_NUM_PERFCOUNT; i++, pCounterDef++) {
  198. pCounterDef->CounterNameTitleIndex += dwFirstCounter;
  199. pCounterDef->CounterHelpTitleIndex += dwFirstHelp;
  200. }
  201. RegCloseKey(hKeyServerPerf); // close key to registry
  202. bInitOK = TRUE; // ok to use this function
  203. // we have already incremented g_dwOpenCount
  204. // before going through this path
  205. ExitPathSuccess:
  206. LeaveCriticalSection(&g_CS);
  207. return ERROR_SUCCESS;
  208. ExitPath:
  209. InterlockedDecrement((LONG *)&g_dwOpenCount);
  210. LeaveCriticalSection(&g_CS);
  211. return RetCode;
  212. }
  213. //--------------------------------------------------------------------
  214. // DWORD CollectASPPerformanceData
  215. //
  216. // Description:
  217. //
  218. // This routine will return the data for the AxctiveX Server counters.
  219. //
  220. // Arguments:
  221. //
  222. // IN LPWSTR lpValueName
  223. // pointer to a wide chacter string passed by registry
  224. //
  225. // IN OUT LPVOID *lppData
  226. // IN: pointer to the address of the buffer to receive the completed
  227. // PerfDataBlock and subordinate structures. This routine will
  228. // append its data to the buffer starting at the point referenced
  229. // by the *lppData
  230. // OUT:points to the first byte after the data structure added by
  231. // this routine. This routine updated the value at lppdata after
  232. // appending its data.
  233. //
  234. // IN OUT LPDWORD lpcbTotalBytes
  235. // IN: the address of the DWORD that tells the size in bytes of the
  236. // buffer referenced by the lppData argument
  237. // OUT:the number of bytes added by this routine is written to the
  238. // DWORD pointed to by this argument
  239. //
  240. // IN OUT LPDWORD NumObjectTypes
  241. // IN: the address of the DWORD that receives the number of the objects
  242. // added by this routine
  243. // OUT:the number of objects added by this routine is written to
  244. // the DWORD pointed to by this argument
  245. //
  246. //
  247. // Return Value:
  248. //
  249. // ERROR_MORE_DATA if buffer passed is too small to hold data
  250. //
  251. // ERROR_SUCCESS if success or any other error.
  252. //
  253. //--------------------------------------------------------------------
  254. DWORD APIENTRY CollectASPPerformanceData(IN LPWSTR lpValueName,
  255. IN OUT LPVOID *lppData,
  256. IN OUT LPDWORD lpcbTotalBytes,
  257. IN OUT LPDWORD lpNumObjectTypes)
  258. {
  259. BOOL fHookingUp = FALSE;
  260. // before doing anything else, see if Open went Ok.
  261. DebugOutputDebugString("collect");
  262. if(!bInitOK) {
  263. //unable to continue because open failed
  264. *lpcbTotalBytes = (DWORD) 0;
  265. *lpNumObjectTypes = (DWORD) 0;
  266. return ERROR_SUCCESS;
  267. }
  268. //
  269. // variables used for error logging
  270. DWORD dwQueryType;
  271. // see if this is a foreign(i.e. non-NT) computer data request
  272. dwQueryType = GetQueryType(lpValueName);
  273. if (QUERY_FOREIGN == dwQueryType) {
  274. // this routine does not service requests for data from
  275. // Non-NT computers
  276. *lpcbTotalBytes = (DWORD)0;
  277. *lpNumObjectTypes = (DWORD)0;
  278. return ERROR_SUCCESS;
  279. }
  280. if (QUERY_ITEMS == dwQueryType) {
  281. if (!(IsNumberInUnicodeList(g_AxDataDefinition.AXSObjectType.ObjectNameTitleIndex,
  282. lpValueName))) {
  283. // request received for data object not provided by this routine
  284. *lpcbTotalBytes = (DWORD)0;
  285. *lpNumObjectTypes = (DWORD)0;
  286. return ERROR_SUCCESS;
  287. }
  288. }
  289. if (QUERY_GLOBAL == dwQueryType) {
  290. /* Comment the following code out, looks like that it is for
  291. debugging only.
  292. int i;
  293. i++;
  294. */
  295. }
  296. AXPD *pAxDataDefinition = (AXPD *)*lppData;
  297. ULONG SpaceNeeded = QWORD_MULTIPLE((sizeof(AXPD) + SIZE_OF_AX_PERF_DATA));
  298. if ( *lpcbTotalBytes < SpaceNeeded) {
  299. *lpcbTotalBytes = (DWORD)0;
  300. *lpNumObjectTypes = (DWORD)0;
  301. return ERROR_MORE_DATA;
  302. }
  303. //
  304. //Copy the (constant, initialized) Object Type and counter defintions to the caller's
  305. //data buffer
  306. //
  307. memmove(pAxDataDefinition, &g_AxDataDefinition, sizeof(AXPD));
  308. //
  309. // Format and collect Active X server performance data from shared memory
  310. //
  311. PERF_COUNTER_BLOCK *pPerfCounterBlock = (PERF_COUNTER_BLOCK *)&pAxDataDefinition[1];
  312. pPerfCounterBlock->ByteLength = SIZE_OF_AX_PERF_DATA;
  313. PDWORD pdwCounter = (PDWORD)(&pPerfCounterBlock[1]);
  314. //
  315. // Must be in a Critical Section when dealing
  316. // with the shared memory, so we don't attempt
  317. // to release it while we are using it.
  318. //
  319. EnterCriticalSection(&g_CS);
  320. // if the shared memory isn't init, try again here
  321. // Whether we are trying to hook up or not will depend
  322. // completely on whether we are all ready hooked up.
  323. fHookingUp = !bSharedMemInitd;
  324. if (bSharedMemInitd == FALSE) {
  325. bSharedMemInitd = !!SUCCEEDED(g_Shared.Init());
  326. }
  327. // If we initialized the shared memory then we need
  328. // to start monitoring the W3SVC to make sure we let
  329. // go of the memory if W3SVC goes down.
  330. if ( bSharedMemInitd && fHookingUp )
  331. {
  332. //
  333. // if we re-initialized then we need to setup the
  334. // wait on the process again. it is possible that
  335. // the previous wait has not been cleaned up (since
  336. // we can't clean it up in the callback function) so
  337. // if this is the case we need to clean it up first.
  338. //
  339. if ( g_hASPWASProcessWait != NULL )
  340. {
  341. if ( !UnregisterWait( g_hASPWASProcessWait ) )
  342. {
  343. // Nothing we could do here. We will
  344. // end up just leaking it.
  345. }
  346. g_hASPWASProcessWait = NULL;
  347. }
  348. HANDLE hWASHandle = g_Shared.GetWASProcessHandle();
  349. if ( hWASHandle == NULL )
  350. {
  351. g_Shared.UnInit();
  352. bSharedMemInitd = FALSE;
  353. }
  354. else
  355. {
  356. //
  357. // Register to wait on the managing process,
  358. // so we release any shared memory if the managing
  359. // process shutsdown or crashes.
  360. //
  361. if ( !RegisterWaitForSingleObject( &g_hASPWASProcessWait,
  362. hWASHandle,
  363. &ShutdownMemory,
  364. NULL,
  365. INFINITE,
  366. WT_EXECUTEONLYONCE |
  367. WT_EXECUTEINIOTHREAD ) )
  368. {
  369. // If we could not wait on the handle then
  370. // we have to release the shared memory now,
  371. // it's not safe to keep it around.
  372. g_Shared.UnInit();
  373. bSharedMemInitd = FALSE;
  374. }
  375. }
  376. }
  377. // Get statistics from shared memory if the shared memory is
  378. // inited. Else, return just the definitions.
  379. // If we didn't get the counters we want to just memset the structure
  380. // to show all the counters as zero.
  381. if ((bSharedMemInitd == FALSE) || FAILED(g_Shared.GetStats(pdwCounter)))
  382. {
  383. memset( pdwCounter, 0, SIZE_OF_AX_PERF_DATA );
  384. }
  385. // Done dealing with the shared memory,
  386. // so now we can go ahead and release it
  387. // if need be.
  388. LeaveCriticalSection(&g_CS);
  389. pdwCounter += AX_NUM_PERFCOUNT;
  390. // update arguments for return
  391. *lpNumObjectTypes = 1;
  392. *lpcbTotalBytes = QWORD_MULTIPLE((DIFF((PBYTE)pdwCounter - (PBYTE)pAxDataDefinition)));
  393. *lppData = (PBYTE)(*lppData) + *lpcbTotalBytes;
  394. return ERROR_SUCCESS;
  395. }
  396. //-------------------------------------------------------------------
  397. // DWORD CloseASPPerformanceData
  398. //
  399. // Description:
  400. //
  401. // This routine closes the open handles to ActiveX Server performance
  402. // counters.
  403. //
  404. // Arguments:
  405. //
  406. // None.
  407. //
  408. // Return Value:
  409. //
  410. // ERROR_SUCCESS
  411. //
  412. //--------------------------------------------------------------------
  413. DWORD APIENTRY CloseASPPerformanceData(void)
  414. {
  415. DebugOutputDebugString("Close");
  416. EnterCriticalSection(&g_CS);
  417. LONG nLeft = InterlockedDecrement((LONG *)&g_dwOpenCount);
  418. if (nLeft == 0) {
  419. g_Shared.UnInit();
  420. bInitOK = FALSE;
  421. };
  422. if ( g_hASPWASProcessWait != NULL )
  423. {
  424. if ( !UnregisterWait( g_hASPWASProcessWait ) )
  425. {
  426. // Nothing we could do here. We will
  427. // end up just leaking it.
  428. }
  429. g_hASPWASProcessWait = NULL;
  430. }
  431. LeaveCriticalSection(&g_CS);
  432. return ERROR_SUCCESS;
  433. }
  434. static const TCHAR szPerformance[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\ASP\\Performance");
  435. static const TCHAR szAXS[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\ASP");
  436. static const TCHAR szLibrary[] = TEXT("Library");
  437. static const TCHAR szOpen[] = TEXT("Open");
  438. static const TCHAR szClose[] = TEXT("Close");
  439. static const TCHAR szCollect[] = TEXT("Collect");
  440. static const TCHAR szLibraryValue[] = TEXT("aspperf.dll");
  441. static const TCHAR szOpenValue[] = TEXT("OpenASPPerformanceData");
  442. static const TCHAR szCloseValue[] = TEXT("CloseASPPerformanceData");
  443. static const TCHAR szCollectValue[] = TEXT("CollectASPPerformanceData");
  444. //--------------------------------------------------------------------
  445. //
  446. //
  447. //--------------------------------------------------------------------
  448. DWORD APIENTRY RegisterAXS(void)
  449. {
  450. HKEY hkey;
  451. if ((RegCreateKey(HKEY_LOCAL_MACHINE, szPerformance, &hkey)) != ERROR_SUCCESS)
  452. return E_FAIL;
  453. if ((RegSetValueEx(hkey, szLibrary, 0, REG_SZ, (const unsigned char *)&szLibraryValue, lstrlen(szLibraryValue))) != ERROR_SUCCESS)
  454. goto LRegErr;
  455. if ((RegSetValueEx(hkey, szOpen, 0, REG_SZ, (const unsigned char *)&szOpenValue, lstrlen(szOpenValue))) != ERROR_SUCCESS)
  456. goto LRegErr;
  457. if ((RegSetValueEx(hkey, szClose, 0, REG_SZ, (const unsigned char *)&szCloseValue, lstrlen(szCloseValue))) != ERROR_SUCCESS)
  458. goto LRegErr;
  459. if ((RegSetValueEx(hkey, szCollect, 0, REG_SZ, (const unsigned char *)&szCollectValue, lstrlen(szCollectValue))) != ERROR_SUCCESS)
  460. goto LRegErr;
  461. RegCloseKey(hkey);
  462. return NOERROR;
  463. LRegErr:
  464. RegCloseKey(hkey);
  465. return E_FAIL;
  466. }
  467. //--------------------------------------------------------------------
  468. //
  469. //
  470. //--------------------------------------------------------------------
  471. DWORD APIENTRY UnRegisterAXS(void)
  472. {
  473. if ((RegDeleteKey(HKEY_LOCAL_MACHINE, szPerformance)) != ERROR_SUCCESS)
  474. return (E_FAIL);
  475. if ((RegDeleteKey(HKEY_LOCAL_MACHINE, szAXS)) != ERROR_SUCCESS)
  476. return (E_FAIL);
  477. else
  478. return NOERROR;
  479. }
  480. DWORD
  481. GetQueryType (
  482. IN LPWSTR lpValue
  483. )
  484. /*++
  485. GetQueryType
  486. returns the type of query described in the lpValue string so that
  487. the appropriate processing method may be used
  488. Arguments
  489. IN lpValue
  490. string passed to PerfRegQuery Value for processing
  491. Return Value
  492. QUERY_GLOBAL
  493. if lpValue == 0 (null pointer)
  494. lpValue == pointer to Null string
  495. lpValue == pointer to "Global" string
  496. QUERY_FOREIGN
  497. if lpValue == pointer to "Foriegn" string
  498. QUERY_COSTLY
  499. if lpValue == pointer to "Costly" string
  500. otherwise:
  501. QUERY_ITEMS
  502. --*/
  503. {
  504. WCHAR *pwcArgChar, *pwcTypeChar;
  505. BOOL bFound;
  506. if (lpValue == 0) {
  507. return QUERY_GLOBAL;
  508. } else if (*lpValue == 0) {
  509. return QUERY_GLOBAL;
  510. }
  511. // check for "Global" request
  512. pwcArgChar = lpValue;
  513. pwcTypeChar = GLOBAL_STRING;
  514. bFound = TRUE; // assume found until contradicted
  515. // check to the length of the shortest string
  516. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  517. if (*pwcArgChar++ != *pwcTypeChar++) {
  518. bFound = FALSE; // no match
  519. break; // bail out now
  520. }
  521. }
  522. if (bFound) return QUERY_GLOBAL;
  523. // check for "Foreign" request
  524. pwcArgChar = lpValue;
  525. pwcTypeChar = FOREIGN_STRING;
  526. bFound = TRUE; // assume found until contradicted
  527. // check to the length of the shortest string
  528. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  529. if (*pwcArgChar++ != *pwcTypeChar++) {
  530. bFound = FALSE; // no match
  531. break; // bail out now
  532. }
  533. }
  534. if (bFound) return QUERY_FOREIGN;
  535. // check for "Costly" request
  536. pwcArgChar = lpValue;
  537. pwcTypeChar = COSTLY_STRING;
  538. bFound = TRUE; // assume found until contradicted
  539. // check to the length of the shortest string
  540. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  541. if (*pwcArgChar++ != *pwcTypeChar++) {
  542. bFound = FALSE; // no match
  543. break; // bail out now
  544. }
  545. }
  546. if (bFound) return QUERY_COSTLY;
  547. // if not Global and not Foreign and not Costly,
  548. // then it must be an item list
  549. return QUERY_ITEMS;
  550. }
  551. BOOL
  552. IsNumberInUnicodeList (
  553. IN DWORD dwNumber,
  554. IN LPWSTR lpwszUnicodeList
  555. )
  556. /*++
  557. IsNumberInUnicodeList
  558. Arguments:
  559. IN dwNumber
  560. DWORD number to find in list
  561. IN lpwszUnicodeList
  562. Null terminated, Space delimited list of decimal numbers
  563. Return Value:
  564. TRUE:
  565. dwNumber was found in the list of unicode number strings
  566. FALSE:
  567. dwNumber was not found in the list.
  568. --*/
  569. {
  570. DWORD dwThisNumber;
  571. WCHAR *pwcThisChar;
  572. BOOL bValidNumber;
  573. BOOL bNewItem;
  574. //BOOL bReturnValue;
  575. WCHAR wcDelimiter; // could be an argument to be more flexible
  576. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not founde
  577. pwcThisChar = lpwszUnicodeList;
  578. dwThisNumber = 0;
  579. wcDelimiter = (WCHAR)' ';
  580. bValidNumber = FALSE;
  581. bNewItem = TRUE;
  582. while (TRUE) {
  583. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  584. case DIGIT:
  585. // if this is the first digit after a delimiter, then
  586. // set flags to start computing the new number
  587. if (bNewItem) {
  588. bNewItem = FALSE;
  589. bValidNumber = TRUE;
  590. }
  591. if (bValidNumber) {
  592. dwThisNumber *= 10;
  593. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  594. }
  595. break;
  596. case DELIMITER:
  597. // a delimter is either the delimiter character or the
  598. // end of the string ('\0') if when the delimiter has been
  599. // reached a valid number was found, then compare it to the
  600. // number from the argument list. if this is the end of the
  601. // string and no match was found, then return.
  602. //
  603. if (bValidNumber) {
  604. if (dwThisNumber == dwNumber) return TRUE;
  605. bValidNumber = FALSE;
  606. }
  607. if (*pwcThisChar == 0) {
  608. return FALSE;
  609. } else {
  610. bNewItem = TRUE;
  611. dwThisNumber = 0;
  612. }
  613. break;
  614. case INVALID:
  615. // if an invalid character was encountered, ignore all
  616. // characters up to the next delimiter and then start fresh.
  617. // the invalid number is not compared.
  618. bValidNumber = FALSE;
  619. break;
  620. default:
  621. break;
  622. }
  623. pwcThisChar++;
  624. }
  625. } // IsNumberInUnicodeList
  626. STDAPI DLLRegisterServer(void)
  627. {
  628. return RegisterAXS();
  629. }
  630. BOOL WINAPI DllMain(HINSTANCE hInstDLL, // handle to the DLL module
  631. DWORD dwReason, // reason for calling function
  632. LPVOID lpvReserved // reserved
  633. )
  634. {
  635. switch(dwReason){
  636. case DLL_PROCESS_ATTACH:
  637. // CREATE_DEBUG_PRINT_OBJECT( "aspperf" );
  638. DisableThreadLibraryCalls(hInstDLL);
  639. InitializeCriticalSection(&g_CS);
  640. return TRUE;
  641. case DLL_PROCESS_DETACH:
  642. DeleteCriticalSection(&g_CS);
  643. return TRUE;
  644. }
  645. return TRUE;
  646. }