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.

946 lines
23 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. perfTAPI.c
  5. Abstract:
  6. This file implements the Extensible Objects for the TAPI object type
  7. Revision History
  8. --*/
  9. //
  10. // Include Files
  11. //
  12. #include <windows.h>
  13. #include <string.h>
  14. #include <tapi.h>
  15. #include <tspi.h>
  16. #include "client.h"
  17. #include "clntprivate.h"
  18. #include "tapsrv.h"
  19. #include <ntprfctr.h>
  20. #include "perfctr.h"
  21. #include "tapiperf.h"
  22. //
  23. // References to constants which initialize the Object type definitions
  24. //
  25. HINSTANCE ghInst;
  26. HINSTANCE ghTapiInst = NULL;
  27. extern TAPI_DATA_DEFINITION TapiDataDefinition;
  28. DWORD dwOpenCount = 0; // count of "Open" threads
  29. BOOL bInitOK = FALSE; // true = DLL initialized OK
  30. HLINEAPP hLineApp;
  31. HPHONEAPP hPhoneApp;
  32. BOOL bTapiSrvRunning = FALSE;
  33. DWORD gdwLineDevs, gdwPhoneDevs;
  34. void CheckForTapiSrv();
  35. LONG WINAPI Tapi32Performance(PPERFBLOCK);
  36. //
  37. // Tapi data structures
  38. //
  39. HANDLE hTapiSharedMemory; // Handle of Tapi Shared Memory
  40. PPERF_COUNTER_BLOCK pCounterBlock;
  41. typedef LONG (* PERFPROC)(PERFBLOCK *);
  42. #define SZINTERNALPERF TEXT("internalPerformance")
  43. #define SZTAPI32 TEXT("tapi32.dll")
  44. #define SZTAPISRVKEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony")
  45. PERFPROC glpfnInternalPerformance;
  46. //
  47. // Function Prototypes
  48. //
  49. // these are used to insure that the data collection functions
  50. // accessed by Perflib will have the correct calling format.
  51. //
  52. PM_OPEN_PROC OpenTapiPerformanceData;
  53. PM_COLLECT_PROC CollectTapiPerformanceData;
  54. PM_CLOSE_PROC CloseTapiPerformanceData;
  55. //
  56. // Constant structure initializations
  57. // defined in datatapi.h
  58. //
  59. TAPI_DATA_DEFINITION TapiDataDefinition =
  60. {
  61. {
  62. sizeof(TAPI_DATA_DEFINITION) + SIZE_OF_TAPI_PERFORMANCE_DATA,
  63. sizeof(TAPI_DATA_DEFINITION),
  64. sizeof(PERF_OBJECT_TYPE),
  65. TAPIOBJ,
  66. 0,
  67. TAPIOBJ,
  68. 0,
  69. PERF_DETAIL_NOVICE,
  70. (sizeof(TAPI_DATA_DEFINITION)-sizeof(PERF_OBJECT_TYPE))/
  71. sizeof(PERF_COUNTER_DEFINITION),
  72. 0,
  73. -1,
  74. 0
  75. },
  76. {
  77. sizeof(PERF_COUNTER_DEFINITION),
  78. LINES,
  79. 0,
  80. LINES,
  81. 0,
  82. 0,
  83. PERF_DETAIL_NOVICE,
  84. PERF_COUNTER_RAWCOUNT,
  85. sizeof(DWORD),
  86. LINES_OFFSET
  87. },
  88. {
  89. sizeof(PERF_COUNTER_DEFINITION),
  90. PHONES,
  91. 0,
  92. PHONES,
  93. 0,
  94. 0,
  95. PERF_DETAIL_NOVICE,
  96. PERF_COUNTER_RAWCOUNT,
  97. sizeof(DWORD),
  98. PHONES_OFFSET
  99. },
  100. {
  101. sizeof(PERF_COUNTER_DEFINITION),
  102. LINESINUSE,
  103. 0,
  104. LINESINUSE,
  105. 0,
  106. 0,
  107. PERF_DETAIL_NOVICE,
  108. PERF_COUNTER_RAWCOUNT,
  109. sizeof(DWORD),
  110. LINESINUSE_OFFSET
  111. },
  112. {
  113. sizeof(PERF_COUNTER_DEFINITION),
  114. PHONESINUSE,
  115. 0,
  116. PHONESINUSE,
  117. 0,
  118. 0,
  119. PERF_DETAIL_NOVICE,
  120. PERF_COUNTER_RAWCOUNT,
  121. sizeof(DWORD),
  122. PHONESINUSE_OFFSET
  123. },
  124. {
  125. sizeof(PERF_COUNTER_DEFINITION),
  126. TOTALOUTGOINGCALLS,
  127. 0,
  128. TOTALOUTGOINGCALLS,
  129. 0,
  130. 0,
  131. PERF_DETAIL_NOVICE,
  132. PERF_COUNTER_COUNTER,
  133. sizeof(DWORD),
  134. TOTALOUTGOINGCALLS_OFFSET
  135. },
  136. {
  137. sizeof(PERF_COUNTER_DEFINITION),
  138. TOTALINCOMINGCALLS,
  139. 0,
  140. TOTALINCOMINGCALLS,
  141. 0,
  142. 0,
  143. PERF_DETAIL_NOVICE,
  144. PERF_COUNTER_COUNTER,
  145. sizeof(DWORD),
  146. TOTALINCOMINGCALLS_OFFSET
  147. },
  148. {
  149. sizeof(PERF_COUNTER_DEFINITION),
  150. CLIENTAPPS,
  151. 0,
  152. CLIENTAPPS,
  153. 0,
  154. 0,
  155. PERF_DETAIL_NOVICE,
  156. PERF_COUNTER_RAWCOUNT,
  157. sizeof(DWORD),
  158. CLIENTAPPS_OFFSET
  159. }
  160. ,
  161. {
  162. sizeof(PERF_COUNTER_DEFINITION),
  163. ACTIVEOUTGOINGCALLS,
  164. 0,
  165. ACTIVEOUTGOINGCALLS,
  166. 0,
  167. 0,
  168. PERF_DETAIL_NOVICE,
  169. PERF_COUNTER_RAWCOUNT,
  170. sizeof(DWORD),
  171. ACTIVEOUTGOINGCALLS_OFFSET
  172. },
  173. {
  174. sizeof(PERF_COUNTER_DEFINITION),
  175. ACTIVEINCOMINGCALLS,
  176. 0,
  177. ACTIVEINCOMINGCALLS,
  178. 0,
  179. 0,
  180. PERF_DETAIL_NOVICE,
  181. PERF_COUNTER_RAWCOUNT,
  182. sizeof(DWORD),
  183. ACTIVEINCOMINGCALLS_OFFSET
  184. }
  185. };
  186. DWORD APIENTRY
  187. OpenTapiPerformanceData(
  188. LPWSTR lpDeviceNames
  189. )
  190. /*++
  191. Routine Description:
  192. This routine will open and map the memory used by the TAPI driver to
  193. pass performance data in. This routine also initializes the data
  194. structures used to pass data back to the registry
  195. Arguments:
  196. Pointer to object ID of each device to be opened (TAPI)
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. LONG status;
  202. TCHAR szMappedObject[] = TEXT("TAPI_COUNTER_BLOCK");
  203. HKEY hKeyDriverPerf;
  204. DWORD size;
  205. DWORD type;
  206. DWORD dwFirstCounter;
  207. DWORD dwFirstHelp;
  208. HKEY hTapiKey;
  209. DWORD dwType;
  210. DWORD dwSize;
  211. //
  212. // Since SCREG is multi-threaded and will call this routine in
  213. // order to service remote performance queries, this library
  214. // must keep track of how many times it has been opened (i.e.
  215. // how many threads have accessed it). the registry routines will
  216. // limit access to the initialization routine to only one thread
  217. // at a time so synchronization (i.e. reentrancy) should not be
  218. // a problem
  219. //
  220. if (!dwOpenCount)
  221. {
  222. // get counter and help index base values
  223. // update static data structures by adding base to
  224. // offset value in structure.
  225. // these values are from <ntprfctr.h>
  226. dwFirstCounter = TAPI_FIRST_COUNTER_INDEX;
  227. dwFirstHelp = TAPI_FIRST_HELP_INDEX;
  228. TapiDataDefinition.TapiObjectType.ObjectNameTitleIndex += dwFirstCounter;
  229. TapiDataDefinition.TapiObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  230. TapiDataDefinition.Lines.CounterNameTitleIndex += dwFirstCounter;
  231. TapiDataDefinition.Lines.CounterHelpTitleIndex += dwFirstHelp;
  232. TapiDataDefinition.Phones.CounterNameTitleIndex += dwFirstCounter;
  233. TapiDataDefinition.Phones.CounterHelpTitleIndex += dwFirstHelp;
  234. TapiDataDefinition.LinesInUse.CounterNameTitleIndex += dwFirstCounter;
  235. TapiDataDefinition.LinesInUse.CounterHelpTitleIndex += dwFirstHelp;
  236. TapiDataDefinition.PhonesInUse.CounterNameTitleIndex += dwFirstCounter;
  237. TapiDataDefinition.PhonesInUse.CounterHelpTitleIndex += dwFirstHelp;
  238. TapiDataDefinition.TotalOutgoingCalls.CounterNameTitleIndex += dwFirstCounter;
  239. TapiDataDefinition.TotalOutgoingCalls.CounterHelpTitleIndex += dwFirstHelp;
  240. TapiDataDefinition.TotalIncomingCalls.CounterNameTitleIndex += dwFirstCounter;
  241. TapiDataDefinition.TotalIncomingCalls.CounterHelpTitleIndex += dwFirstHelp;
  242. TapiDataDefinition.ClientApps.CounterNameTitleIndex += dwFirstCounter;
  243. TapiDataDefinition.ClientApps.CounterHelpTitleIndex += dwFirstHelp;
  244. TapiDataDefinition.CurrentOutgoingCalls.CounterNameTitleIndex += dwFirstCounter;
  245. TapiDataDefinition.CurrentOutgoingCalls.CounterHelpTitleIndex += dwFirstHelp;
  246. TapiDataDefinition.CurrentIncomingCalls.CounterNameTitleIndex += dwFirstCounter;
  247. TapiDataDefinition.CurrentIncomingCalls.CounterHelpTitleIndex += dwFirstHelp;
  248. bInitOK = TRUE; // ok to use this function
  249. }
  250. dwOpenCount++; // increment OPEN counter
  251. // get number of devices from tapi
  252. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  253. SZTAPISRVKEY,
  254. 0,
  255. KEY_READ,
  256. &hTapiKey))
  257. {
  258. gdwLineDevs = 0;
  259. gdwPhoneDevs = 0;
  260. }
  261. else
  262. {
  263. dwSize = sizeof(DWORD);
  264. if (ERROR_SUCCESS != RegQueryValueEx(hTapiKey,
  265. TEXT("Perf1"),
  266. NULL,
  267. &dwType,
  268. (LPBYTE)&gdwLineDevs,
  269. &dwSize))
  270. {
  271. gdwLineDevs = 0;
  272. }
  273. else
  274. {
  275. gdwLineDevs -= 'PERF';
  276. }
  277. dwSize = sizeof(DWORD);
  278. if (ERROR_SUCCESS != RegQueryValueEx(hTapiKey,
  279. TEXT("Perf2"),
  280. NULL,
  281. &dwType,
  282. (LPBYTE)&gdwPhoneDevs,
  283. &dwSize))
  284. {
  285. gdwPhoneDevs = 0;
  286. }
  287. else
  288. {
  289. gdwPhoneDevs -= 'PERF';
  290. }
  291. RegCloseKey(hTapiKey);
  292. }
  293. status = ERROR_SUCCESS; // for successful exit
  294. return status;
  295. }
  296. DWORD APIENTRY
  297. CollectTapiPerformanceData(
  298. IN LPWSTR lpValueName,
  299. IN OUT LPVOID *lppData,
  300. IN OUT LPDWORD lpcbTotalBytes,
  301. IN OUT LPDWORD lpNumObjectTypes
  302. )
  303. /*++
  304. Routine Description:
  305. This routine will return the data for the TAPI counters.
  306. Arguments:
  307. IN LPWSTR lpValueName
  308. pointer to a wide character string passed by registry.
  309. IN OUT LPVOID *lppData
  310. IN: pointer to the address of the buffer to receive the completed
  311. PerfDataBlock and subordinate structures. This routine will
  312. append its data to the buffer starting at the point referenced
  313. by *lppData.
  314. OUT: points to the first byte after the data structure added by this
  315. routine. This routine updated the value at lppdata after appending
  316. its data.
  317. IN OUT LPDWORD lpcbTotalBytes
  318. IN: the address of the DWORD that tells the size in bytes of the
  319. buffer referenced by the lppData argument
  320. OUT: the number of bytes added by this routine is written to the
  321. DWORD pointed to by this argument
  322. IN OUT LPDWORD NumObjectTypes
  323. IN: the address of the DWORD to receive the number of objects added
  324. by this routine
  325. OUT: the number of objects added by this routine is written to the
  326. DWORD pointed to by this argument
  327. Return Value:
  328. ERROR_MORE_DATA if buffer passed is too small to hold data
  329. any error conditions encountered are reported to the event log if
  330. event logging is enabled.
  331. ERROR_SUCCESS if success or any other error. Errors, however are
  332. also reported to the event log.
  333. --*/
  334. {
  335. // Variables for reformatting the data
  336. ULONG SpaceNeeded;
  337. PDWORD pdwCounter;
  338. PERF_COUNTER_BLOCK *pPerfCounterBlock;
  339. TAPI_DATA_DEFINITION *pTapiDataDefinition;
  340. // Variables for collecting data about TAPI Resouces
  341. LPWSTR lpFromString;
  342. LPWSTR lpToString;
  343. INT iStringLength;
  344. // variables used for error logging
  345. DWORD dwDataReturn[2];
  346. DWORD dwQueryType;
  347. PPERFBLOCK pPerfBlock;
  348. static BOOL bFirst = TRUE;
  349. //
  350. // before doing anything else, see if Open went OK
  351. //
  352. if (!bInitOK)
  353. {
  354. // unable to continue because open failed.
  355. *lpcbTotalBytes = (DWORD) 0;
  356. *lpNumObjectTypes = (DWORD) 0;
  357. return ERROR_SUCCESS; // yes, this is a successful exit
  358. }
  359. // see if this is a foreign (i.e. non-NT) computer data request
  360. //
  361. dwQueryType = GetQueryType (lpValueName);
  362. if (dwQueryType == QUERY_FOREIGN)
  363. {
  364. // this routine does not service requests for data from
  365. // Non-NT computers
  366. *lpcbTotalBytes = (DWORD) 0;
  367. *lpNumObjectTypes = (DWORD) 0;
  368. return ERROR_SUCCESS;
  369. }
  370. if (dwQueryType == QUERY_ITEMS)
  371. {
  372. if ( !(IsNumberInUnicodeList (TapiDataDefinition.TapiObjectType.ObjectNameTitleIndex, lpValueName)))
  373. {
  374. // request received for data object not provided by this routine
  375. *lpcbTotalBytes = (DWORD) 0;
  376. *lpNumObjectTypes = (DWORD) 0;
  377. return ERROR_SUCCESS;
  378. }
  379. }
  380. pTapiDataDefinition = (TAPI_DATA_DEFINITION *) *lppData;
  381. SpaceNeeded = sizeof(TAPI_DATA_DEFINITION) +
  382. SIZE_OF_TAPI_PERFORMANCE_DATA;
  383. if ( *lpcbTotalBytes < SpaceNeeded )
  384. {
  385. *lpcbTotalBytes = (DWORD) 0;
  386. *lpNumObjectTypes = (DWORD) 0;
  387. return ERROR_MORE_DATA;
  388. }
  389. //
  390. // Copy the (constant, initialized) Object Type and counter definitions
  391. // to the caller's data buffer
  392. //
  393. if (!bTapiSrvRunning)
  394. {
  395. CheckForTapiSrv();
  396. }
  397. pPerfBlock = (PPERFBLOCK)GlobalAlloc(GPTR, sizeof(PERFBLOCK));
  398. if (NULL == pPerfBlock)
  399. {
  400. *lpcbTotalBytes = (DWORD) 0;
  401. *lpNumObjectTypes = (DWORD) 0;
  402. return ERROR_SUCCESS;
  403. }
  404. if (!bTapiSrvRunning)
  405. {
  406. // don't do anything, but succeed
  407. FillMemory(pPerfBlock,
  408. sizeof(PERFBLOCK),
  409. 0);
  410. pPerfBlock->dwLines = gdwLineDevs;
  411. pPerfBlock->dwPhones = gdwPhoneDevs;
  412. }
  413. else
  414. {
  415. pPerfBlock->dwSize = sizeof(PERFBLOCK);
  416. glpfnInternalPerformance (pPerfBlock);
  417. // don't count me as a client app!
  418. if (0 != pPerfBlock->dwClientApps)
  419. {
  420. pPerfBlock->dwClientApps--;
  421. }
  422. }
  423. memmove(pTapiDataDefinition,
  424. &TapiDataDefinition,
  425. sizeof(TAPI_DATA_DEFINITION));
  426. //
  427. // Format and collect TAPI data from shared memory
  428. //
  429. pPerfCounterBlock = (PERF_COUNTER_BLOCK *) &pTapiDataDefinition[1];
  430. pPerfCounterBlock->ByteLength = SIZE_OF_TAPI_PERFORMANCE_DATA;
  431. pdwCounter = (PDWORD) (&pPerfCounterBlock[1]);
  432. // make sure we don't have funky values
  433. if (((LONG)pPerfBlock->dwTotalOutgoingCalls) < 0)
  434. {
  435. pPerfBlock->dwTotalOutgoingCalls = 0;
  436. }
  437. if (((LONG)pPerfBlock->dwTotalIncomingCalls) < 0)
  438. {
  439. pPerfBlock->dwTotalIncomingCalls = 0;
  440. }
  441. if (((LONG)pPerfBlock->dwCurrentOutgoingCalls) < 0)
  442. {
  443. pPerfBlock->dwCurrentOutgoingCalls = 0;
  444. }
  445. if (((LONG)pPerfBlock->dwCurrentIncomingCalls) < 0)
  446. {
  447. pPerfBlock->dwCurrentIncomingCalls = 0;
  448. }
  449. *pdwCounter = pPerfBlock->dwLines;
  450. *++pdwCounter = pPerfBlock->dwPhones;
  451. *++pdwCounter = pPerfBlock->dwLinesInUse;
  452. *++pdwCounter = pPerfBlock->dwPhonesInUse;
  453. *++pdwCounter = pPerfBlock->dwTotalOutgoingCalls;
  454. *++pdwCounter = pPerfBlock->dwTotalIncomingCalls;
  455. *++pdwCounter = pPerfBlock->dwClientApps;
  456. *++pdwCounter = pPerfBlock->dwCurrentOutgoingCalls;
  457. *++pdwCounter = pPerfBlock->dwCurrentIncomingCalls;
  458. *lppData = (PVOID) ++pdwCounter;
  459. // update arguments for return
  460. *lpNumObjectTypes = 1;
  461. *lpcbTotalBytes = (DWORD)
  462. ((PBYTE) pdwCounter - (PBYTE) pTapiDataDefinition);
  463. GlobalFree(pPerfBlock);
  464. bFirst = FALSE;
  465. return ERROR_SUCCESS;
  466. }
  467. DWORD APIENTRY
  468. CloseTapiPerformanceData(
  469. )
  470. /*++
  471. Routine Description:
  472. This routine closes the open handles to TAPI device performance counters
  473. Arguments:
  474. None.
  475. Return Value:
  476. ERROR_SUCCESS
  477. --*/
  478. {
  479. return ERROR_SUCCESS;
  480. }
  481. void CALLBACK LineCallbackFunc(DWORD dw1,
  482. DWORD dw2,
  483. DWORD dw3,
  484. DWORD dw4,
  485. DWORD dw5,
  486. DWORD dw6)
  487. {
  488. }
  489. //////////////////////////////////////////////////////////////////////
  490. //
  491. // PERF UTILITY STUFF BELOW!
  492. //
  493. //////////////////////////////////////////////////////////////////////
  494. #define INITIAL_SIZE 1024L
  495. #define EXTEND_SIZE 1024L
  496. //
  497. // Global data definitions.
  498. //
  499. ULONG ulInfoBufferSize = 0;
  500. // initialized in Open... routines
  501. DWORD dwLogUsers = 0; // count of functions using event log
  502. WCHAR GLOBAL_STRING[] = L"Global";
  503. WCHAR FOREIGN_STRING[] = L"Foreign";
  504. WCHAR COSTLY_STRING[] = L"Costly";
  505. WCHAR NULL_STRING[] = L"\0"; // pointer to null string
  506. // test for delimiter, end of line and non-digit characters
  507. // used by IsNumberInUnicodeList routine
  508. //
  509. #define DIGIT 1
  510. #define DELIMITER 2
  511. #define INVALID 3
  512. #define EvalThisChar(c,d) ( \
  513. (c == d) ? DELIMITER : \
  514. (c == 0) ? DELIMITER : \
  515. (c < (WCHAR)'0') ? INVALID : \
  516. (c > (WCHAR)'9') ? INVALID : \
  517. DIGIT)
  518. DWORD
  519. GetQueryType (
  520. IN LPWSTR lpValue
  521. )
  522. /*++
  523. GetQueryType
  524. returns the type of query described in the lpValue string so that
  525. the appropriate processing method may be used
  526. Arguments
  527. IN lpValue
  528. string passed to PerfRegQuery Value for processing
  529. Return Value
  530. QUERY_GLOBAL
  531. if lpValue == 0 (null pointer)
  532. lpValue == pointer to Null string
  533. lpValue == pointer to "Global" string
  534. QUERY_FOREIGN
  535. if lpValue == pointer to "Foreign" string
  536. QUERY_COSTLY
  537. if lpValue == pointer to "Costly" string
  538. otherwise:
  539. QUERY_ITEMS
  540. --*/
  541. {
  542. WCHAR *pwcArgChar, *pwcTypeChar;
  543. BOOL bFound;
  544. if (lpValue == 0) {
  545. return QUERY_GLOBAL;
  546. } else if (*lpValue == 0) {
  547. return QUERY_GLOBAL;
  548. }
  549. // check for "Global" request
  550. pwcArgChar = lpValue;
  551. pwcTypeChar = GLOBAL_STRING;
  552. bFound = TRUE; // assume found until contradicted
  553. // check to the length of the shortest string
  554. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  555. if (*pwcArgChar++ != *pwcTypeChar++) {
  556. bFound = FALSE; // no match
  557. break; // bail out now
  558. }
  559. }
  560. if (bFound) return QUERY_GLOBAL;
  561. // check for "Foreign" request
  562. pwcArgChar = lpValue;
  563. pwcTypeChar = FOREIGN_STRING;
  564. bFound = TRUE; // assume found until contradicted
  565. // check to the length of the shortest string
  566. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  567. if (*pwcArgChar++ != *pwcTypeChar++) {
  568. bFound = FALSE; // no match
  569. break; // bail out now
  570. }
  571. }
  572. if (bFound) return QUERY_FOREIGN;
  573. // check for "Costly" request
  574. pwcArgChar = lpValue;
  575. pwcTypeChar = COSTLY_STRING;
  576. bFound = TRUE; // assume found until contradicted
  577. // check to the length of the shortest string
  578. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
  579. if (*pwcArgChar++ != *pwcTypeChar++) {
  580. bFound = FALSE; // no match
  581. break; // bail out now
  582. }
  583. }
  584. if (bFound) return QUERY_COSTLY;
  585. // if not Global and not Foreign and not Costly,
  586. // then it must be an item list
  587. return QUERY_ITEMS;
  588. }
  589. BOOL
  590. IsNumberInUnicodeList (
  591. IN DWORD dwNumber,
  592. IN LPWSTR lpwszUnicodeList
  593. )
  594. /*++
  595. IsNumberInUnicodeList
  596. Arguments:
  597. IN dwNumber
  598. DWORD number to find in list
  599. IN lpwszUnicodeList
  600. Null terminated, Space delimited list of decimal numbers
  601. Return Value:
  602. TRUE:
  603. dwNumber was found in the list of unicode number strings
  604. FALSE:
  605. dwNumber was not found in the list.
  606. --*/
  607. {
  608. DWORD dwThisNumber;
  609. WCHAR *pwcThisChar;
  610. BOOL bValidNumber;
  611. BOOL bNewItem;
  612. BOOL bReturnValue;
  613. WCHAR wcDelimiter; // could be an argument to be more flexible
  614. if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not found
  615. pwcThisChar = lpwszUnicodeList;
  616. dwThisNumber = 0;
  617. wcDelimiter = (WCHAR)' ';
  618. bValidNumber = FALSE;
  619. bNewItem = TRUE;
  620. while (TRUE) {
  621. switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
  622. case DIGIT:
  623. // if this is the first digit after a delimiter, then
  624. // set flags to start computing the new number
  625. if (bNewItem) {
  626. bNewItem = FALSE;
  627. bValidNumber = TRUE;
  628. }
  629. if (bValidNumber) {
  630. dwThisNumber *= 10;
  631. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  632. }
  633. break;
  634. case DELIMITER:
  635. // a delimiter is either the delimiter character or the
  636. // end of the string ('\0') if when the delimiter has been
  637. // reached a valid number was found, then compare it to the
  638. // number from the argument list. if this is the end of the
  639. // string and no match was found, then return.
  640. //
  641. if (bValidNumber) {
  642. if (dwThisNumber == dwNumber) return TRUE;
  643. bValidNumber = FALSE;
  644. }
  645. if (*pwcThisChar == 0) {
  646. return FALSE;
  647. } else {
  648. bNewItem = TRUE;
  649. dwThisNumber = 0;
  650. }
  651. break;
  652. case INVALID:
  653. // if an invalid character was encountered, ignore all
  654. // characters up to the next delimiter and then start fresh.
  655. // the invalid number is not compared.
  656. bValidNumber = FALSE;
  657. break;
  658. default:
  659. break;
  660. }
  661. pwcThisChar++;
  662. }
  663. } // IsNumberInUnicodeList
  664. BOOL
  665. WINAPI
  666. DllEntryPoint(
  667. HANDLE hDLL,
  668. DWORD dwReason,
  669. LPVOID lpReserved
  670. )
  671. {
  672. switch (dwReason)
  673. {
  674. case DLL_PROCESS_ATTACH:
  675. {
  676. ghInst = hDLL;
  677. break;
  678. }
  679. case DLL_PROCESS_DETACH:
  680. {
  681. break;
  682. }
  683. case DLL_THREAD_ATTACH:
  684. break;
  685. case DLL_THREAD_DETACH:
  686. {
  687. break;
  688. }
  689. } // switch
  690. return TRUE;
  691. }
  692. void CheckForTapiSrv()
  693. {
  694. SC_HANDLE sc, scTapiSrv;
  695. SERVICE_STATUS ServStat;
  696. sc = OpenSCManager (NULL, NULL, GENERIC_READ);
  697. if (NULL == sc)
  698. {
  699. return;
  700. }
  701. bTapiSrvRunning = FALSE;
  702. scTapiSrv = OpenService (sc, "TAPISRV", SERVICE_QUERY_STATUS);
  703. if (!QueryServiceStatus (scTapiSrv, &ServStat))
  704. {
  705. }
  706. if (ServStat.dwCurrentState != SERVICE_RUNNING)
  707. {
  708. }
  709. else
  710. {
  711. bTapiSrvRunning = TRUE;
  712. }
  713. if (bTapiSrvRunning)
  714. {
  715. if (!ghTapiInst)
  716. {
  717. ghTapiInst = LoadLibrary (SZTAPI32);
  718. glpfnInternalPerformance = (PERFPROC)GetProcAddress(
  719. ghTapiInst,
  720. SZINTERNALPERF
  721. );
  722. if (!glpfnInternalPerformance)
  723. {
  724. }
  725. }
  726. }
  727. CloseServiceHandle(scTapiSrv);
  728. CloseServiceHandle(sc);
  729. }