Windows NT 4.0 source code leak
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.

811 lines
20 KiB

4 years ago
  1. /* + mmtimers.h
  2. *
  3. * Accurate timers using pentium cpu clock, QueryPerformanceCounter
  4. * or GetTickCount depending on what system the code is run on
  5. *
  6. * Copyright (C) 1995, Microsoft Corporation, all rights reserved
  7. *
  8. *-========================================================================*/
  9. #if !defined _INC_MMTIMERS_
  10. #define _INC_MMTIMERS_
  11. typedef struct {
  12. DWORD dwlo;
  13. DWORD dwhi;
  14. } PCTIMER, NEAR * PPCTIMER;
  15. struct _pctimer_global {
  16. DWORD dwRawHz;
  17. DWORD dwMicroAdjust;
  18. union {
  19. DWORD dwRawKhz;
  20. WORD wRawKhz;
  21. };
  22. union {
  23. DWORD dwRawMhz;
  24. WORD wRawMhz;
  25. };
  26. DWORD dwTimerKhz;
  27. PCTIMER base;
  28. DWORD (WINAPI * DifTicks )(PCTIMER *);
  29. DWORD (WINAPI * DifMicrosec )(PCTIMER *);
  30. DWORD (WINAPI * DifMillisec )(PCTIMER *);
  31. DWORD (WINAPI * DeltaTicks )(PCTIMER *);
  32. DWORD (WINAPI * DeltaMicrosec)(PCTIMER *);
  33. DWORD (WINAPI * DeltaMillisec)(PCTIMER *);
  34. UINT uTimerType;
  35. };
  36. extern struct _pctimer_global pc;
  37. extern VOID WINAPI InitPerformanceCounters ();
  38. #define pcBegin() pc.DeltaTicks(&pc.base)
  39. #define pcGetTime() pc.DifMillisec(&pc.base)
  40. #define pcGetTicks() pc.DifMicrosec(&pc.base)
  41. #define pcGetTickRate() (pc.dwTimerKhz * 1000)
  42. #define pcBeginTimer(ppt) (pc.DeltaMicrosec(ppt), 0)
  43. #define pcDeltaTicks(ppt) pc.DeltaMicrosec(ppt)
  44. #endif //_INC_MMTIMERS_
  45. // =============================================================================
  46. //
  47. // include this in only one module in a DLL or APP
  48. //
  49. #if (defined _INC_MMTIMERS_CODE_) && (_INC_MMTIMERS_CODE_ != FALSE)
  50. #undef _INC_MMTIMERS_CODE_
  51. #define _INC_MMTIMERS_CODE_ FALSE
  52. static DWORD WINAPI tgtDeltaTime (PCTIMER *pctimer)
  53. {
  54. DWORD dwTime = timeGetTime();
  55. DWORD dwDelta = dwTime - pctimer->dwlo;
  56. pctimer->dwlo = dwTime;
  57. return dwDelta;
  58. }
  59. static DWORD WINAPI tgtDiffTime (PCTIMER *pctimer)
  60. {
  61. return timeGetTime() - pctimer->dwlo;
  62. }
  63. struct _pctimer_global pc = {1000, 0, 1, 0, 1,
  64. 0, 0,
  65. (LPVOID)tgtDiffTime,
  66. (LPVOID)tgtDiffTime,
  67. (LPVOID)tgtDiffTime,
  68. (LPVOID)tgtDeltaTime,
  69. (LPVOID)tgtDeltaTime,
  70. (LPVOID)tgtDeltaTime,
  71. 0,
  72. };
  73. #if defined WIN32 || defined _WIN32
  74. #if !defined _X86_
  75. #define Scale(value,scalar) (DWORD)((value).QuadPart / (scalar))
  76. #else
  77. //
  78. // c9 wants to do LARGE_INTEGER division by calling a library
  79. // routine. We get a link error for projects that are not
  80. // already using the C-runtime, so to avoid that, we do the division
  81. // using x86 assembler
  82. //
  83. #pragma warning(disable:4704)
  84. #pragma warning(disable:4035)
  85. DWORD _inline Scale(
  86. LARGE_INTEGER value,
  87. DWORD scalar)
  88. {
  89. _asm {
  90. mov ecx, scalar
  91. mov eax, value.LowPart
  92. mov edx, value.HighPart
  93. jecxz bail
  94. cmp edx, ecx
  95. jb ok_to_divide
  96. push eax
  97. mov eax, edx
  98. xor edx, edx
  99. div ecx
  100. pop eax
  101. ok_to_divide:
  102. div ecx
  103. bail:
  104. }
  105. }
  106. #endif
  107. static VOID WINAPI qpcInitTimer (PCTIMER * pbase)
  108. {
  109. QueryPerformanceCounter ((LPVOID)pbase);
  110. }
  111. static DWORD WINAPI qpcDiffTicks (PCTIMER * pbase)
  112. {
  113. LARGE_INTEGER *plarge = (LPVOID)pbase;
  114. LARGE_INTEGER ticks;
  115. QueryPerformanceCounter (&ticks);
  116. ticks.QuadPart -= plarge->QuadPart;
  117. return ticks.LowPart;
  118. }
  119. static DWORD WINAPI qpcDiffMicrosec (PCTIMER * pbase)
  120. {
  121. LARGE_INTEGER *plarge = (LPVOID)pbase;
  122. LARGE_INTEGER ticks;
  123. QueryPerformanceCounter (&ticks);
  124. ticks.QuadPart -= plarge->QuadPart;
  125. ticks.LowPart = Scale(ticks, pc.dwRawMhz);
  126. if (pc.dwMicroAdjust)
  127. return MulDiv (ticks.LowPart, 1000000, pc.dwMicroAdjust);
  128. return ticks.LowPart;
  129. }
  130. static DWORD WINAPI qpcDiffMillisec (PCTIMER * pbase)
  131. {
  132. LARGE_INTEGER *plarge = (LPVOID)pbase;
  133. LARGE_INTEGER ticks;
  134. QueryPerformanceCounter (&ticks);
  135. ticks.QuadPart -= plarge->QuadPart;
  136. return Scale(ticks, pc.dwRawKhz);
  137. }
  138. static DWORD WINAPI qpcDeltaTicks (PCTIMER * pbase)
  139. {
  140. LARGE_INTEGER *plarge = (LPVOID)pbase;
  141. LARGE_INTEGER ticks = *plarge;
  142. QueryPerformanceCounter (plarge);
  143. ticks.QuadPart = plarge->QuadPart - ticks.QuadPart;
  144. return ticks.LowPart;
  145. }
  146. static DWORD WINAPI qpcDeltaMicrosec (PCTIMER * pbase)
  147. {
  148. LARGE_INTEGER *plarge = (LPVOID)pbase;
  149. LARGE_INTEGER ticks = *plarge;
  150. QueryPerformanceCounter (plarge);
  151. ticks.QuadPart = plarge->QuadPart - ticks.QuadPart;
  152. ticks.LowPart = Scale(ticks, pc.dwRawMhz);
  153. if (pc.dwMicroAdjust)
  154. return MulDiv (ticks.LowPart, 1000000, pc.dwMicroAdjust);
  155. return ticks.LowPart;
  156. }
  157. static DWORD WINAPI qpcDeltaMillisec (PCTIMER * pbase)
  158. {
  159. LARGE_INTEGER *plarge = (LPVOID)pbase;
  160. LARGE_INTEGER ticks = *plarge;
  161. QueryPerformanceCounter (plarge);
  162. ticks.QuadPart = plarge->QuadPart - ticks.QuadPart;
  163. return Scale(ticks, pc.dwRawKhz);
  164. }
  165. static DWORD WINAPI qpcTimerFreq ()
  166. {
  167. LARGE_INTEGER freq;
  168. if (QueryPerformanceFrequency (&freq))
  169. return freq.LowPart;
  170. return 0;
  171. }
  172. #ifdef _X86_
  173. #pragma warning(disable:4704)
  174. #pragma warning(disable:4035)
  175. static VOID WINAPI p5InitTimer (PCTIMER * pBase)
  176. {
  177. _asm {
  178. _emit 0x0f
  179. _emit 0x31
  180. mov ebx, pBase
  181. mov [ebx], eax
  182. mov [ebx+4], edx
  183. }
  184. }
  185. static DWORD WINAPI p5DiffTicks (PCTIMER * pBase)
  186. {
  187. _asm {
  188. _emit 0x0f
  189. _emit 0x31
  190. mov ebx, pBase
  191. sub eax, [ebx]
  192. sbb edx, [ebx+4]
  193. }
  194. }
  195. static DWORD WINAPI p5DiffMicrosec (PCTIMER * pBase)
  196. {
  197. _asm {
  198. _emit 0x0f
  199. _emit 0x31
  200. mov ebx, pBase
  201. sub eax, [ebx]
  202. sbb edx, [ebx+4]
  203. mov ecx, pc.dwRawMhz
  204. jecxz bail
  205. cmp edx, ecx
  206. jb ok_to_divide
  207. push eax
  208. mov eax, edx
  209. xor edx, edx
  210. div ecx
  211. pop eax
  212. ok_to_divide:
  213. div ecx
  214. bail:
  215. }
  216. }
  217. static DWORD WINAPI p5DiffMillisec (PCTIMER * pBase)
  218. {
  219. _asm {
  220. _emit 0x0f
  221. _emit 0x31
  222. mov ebx, pBase
  223. sub eax, [ebx]
  224. sbb edx, [ebx+4]
  225. mov ecx, pc.dwRawKhz
  226. jecxz bail
  227. cmp edx, ecx
  228. jb ok_to_divide
  229. push eax
  230. mov eax, edx
  231. xor edx, edx
  232. div ecx
  233. pop eax
  234. ok_to_divide:
  235. div ecx
  236. bail:
  237. }
  238. }
  239. static DWORD WINAPI p5DeltaTicks (PCTIMER * pBase)
  240. {
  241. _asm {
  242. _emit 0x0f
  243. _emit 0x31
  244. mov ebx, pBase
  245. mov ecx, eax
  246. sub eax, [ebx]
  247. mov [ebx], ecx
  248. mov ecx, edx
  249. sbb edx, [ebx+4]
  250. mov [ebx+4], ecx
  251. }
  252. }
  253. static DWORD WINAPI p5DeltaMicrosec (PCTIMER * pBase)
  254. {
  255. _asm {
  256. _emit 0x0f
  257. _emit 0x31
  258. mov ebx, pBase
  259. mov ecx, eax
  260. sub eax, [ebx]
  261. mov [ebx], ecx
  262. mov ecx, edx
  263. sbb edx, [ebx+4]
  264. mov [ebx+4], ecx
  265. mov ecx, pc.dwRawMhz
  266. jecxz bail
  267. cmp edx, ecx
  268. jb ok_to_divide
  269. push eax
  270. mov eax, edx
  271. xor edx, edx
  272. div ecx
  273. pop eax
  274. ok_to_divide:
  275. div ecx
  276. bail:
  277. }
  278. }
  279. static DWORD WINAPI p5DeltaMillisec (PCTIMER * pBase)
  280. {
  281. _asm {
  282. _emit 0x0f
  283. _emit 0x31
  284. mov ebx, pBase
  285. mov ecx, eax
  286. sub eax, [ebx]
  287. mov [ebx], ecx
  288. mov ecx, edx
  289. sbb edx, [ebx+4]
  290. mov [ebx+4], ecx
  291. mov ecx, pc.dwRawKhz
  292. jecxz bail
  293. cmp edx, ecx
  294. jb ok_to_divide
  295. push eax
  296. mov eax, edx
  297. xor edx, edx
  298. div ecx
  299. pop eax
  300. ok_to_divide:
  301. div ecx
  302. bail:
  303. }
  304. }
  305. static DWORD WINAPI p5TimerFreq ()
  306. {
  307. SYSTEM_INFO si;
  308. GetSystemInfo(&si);
  309. if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
  310. si.wProcessorLevel == 5
  311. )
  312. {
  313. PCTIMER timer;
  314. LARGE_INTEGER qpc1, qpc2;
  315. DWORD dwTime;
  316. DWORD dwTicks;
  317. OSVERSIONINFO osv;
  318. #define MS_INTERVAL 500
  319. // pentium timers dont work correctly on NT so
  320. // dont use them
  321. //
  322. {
  323. osv.dwOSVersionInfoSize = sizeof(osv);
  324. GetVersionEx (&osv);
  325. }
  326. // dont use pentium timers if they take more
  327. // than about 12 microsec to execute
  328. //
  329. p5InitTimer (&timer);
  330. if (p5DeltaTicks (&timer) > (60 * 12) &&
  331. p5DeltaTicks (&timer) > (60 * 12))
  332. {
  333. // pentium timers are too slow to try and use them.
  334. // just go with QueryPerformanceCounter instead
  335. //
  336. return 0;
  337. }
  338. // for some reason, if you use timeBeginPeriod
  339. // on NT. it decides that my 90mhz pentium is an 88mhz
  340. // pentium.
  341. //
  342. //if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  343. // timeBeginPeriod (1);
  344. p5InitTimer (&timer);
  345. QueryPerformanceCounter (&qpc1);
  346. Sleep(MS_INTERVAL);
  347. QueryPerformanceCounter (&qpc2);
  348. dwTicks = p5DiffTicks(&timer);
  349. //if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  350. // timeEndPeriod (1);
  351. dwTime = (DWORD)(qpc2.QuadPart - qpc1.QuadPart);
  352. QueryPerformanceFrequency (&qpc1);
  353. dwTime = MulDiv(dwTime, 1000, qpc1.LowPart);
  354. if (dwTime < MS_INTERVAL * 9 / 10)
  355. return 0;
  356. pc.dwRawMhz = (dwTicks + dwTime * 1000/2) /dwTime /1000;
  357. pc.dwRawKhz = pc.dwRawMhz * 1000;
  358. pc.dwRawHz = pc.dwRawKhz * 1000;
  359. pc.dwMicroAdjust = 0;
  360. pc.dwTimerKhz = 1000;
  361. return pc.dwRawHz;
  362. }
  363. return 0;
  364. }
  365. #endif
  366. VOID WINAPI InitPerformanceCounters (void)
  367. {
  368. DWORD dwFreq;
  369. #ifdef _X86_
  370. if (p5TimerFreq())
  371. {
  372. pc.DifTicks = p5DiffTicks;
  373. pc.DifMicrosec = p5DiffMicrosec;
  374. pc.DifMillisec = p5DiffMillisec;
  375. pc.DeltaTicks = p5DeltaTicks;
  376. pc.DeltaMicrosec = p5DeltaMicrosec;
  377. pc.DeltaMillisec = p5DeltaMillisec;
  378. pc.uTimerType = 5;
  379. return;
  380. }
  381. #endif
  382. if (dwFreq = qpcTimerFreq())
  383. {
  384. pc.dwRawKhz = dwFreq / 1000;
  385. pc.dwRawMhz = pc.dwRawKhz / 1000;
  386. pc.dwMicroAdjust = dwFreq / pc.dwRawMhz;
  387. if (pc.dwMicroAdjust == 1000000)
  388. pc.dwMicroAdjust = 0;
  389. pc.dwTimerKhz = 1000;
  390. pc.DifTicks = qpcDiffTicks;
  391. pc.DifMicrosec = qpcDiffMicrosec;
  392. pc.DifMillisec = qpcDiffMillisec;
  393. pc.DeltaTicks = qpcDeltaTicks;
  394. pc.DeltaMicrosec = qpcDeltaMicrosec;
  395. pc.DeltaMillisec = qpcDeltaMillisec;
  396. pc.uTimerType = 1;
  397. }
  398. }
  399. #else // win16
  400. #pragma warning(disable:4704)
  401. #pragma warning(disable:4035)
  402. static VOID WINAPI p5InitTimer (PCTIMER * pBase)
  403. {
  404. _asm {
  405. _emit 0x0f
  406. _emit 0x31
  407. _emit 0x66
  408. xor bx, bx
  409. mov bx, pBase
  410. _emit 0x66
  411. mov [bx], ax
  412. _emit 0x66
  413. mov [bx+4], dx
  414. }
  415. }
  416. static DWORD WINAPI p5DiffTicks (PCTIMER * pBase)
  417. {
  418. _asm {
  419. _emit 0x0f
  420. _emit 0x31
  421. _emit 0x66
  422. xor bx, bx
  423. mov bx, pBase
  424. _emit 0x66
  425. sub ax, [bx]
  426. _emit 0x66
  427. sbb dx, [bx+4]
  428. }
  429. }
  430. static DWORD WINAPI p5DiffMicrosec (PCTIMER * pBase)
  431. {
  432. _asm {
  433. _emit 0x0f
  434. _emit 0x31
  435. _emit 0x66
  436. xor bx, bx
  437. mov bx, pBase
  438. _emit 0x66
  439. sub ax, [bx]
  440. _emit 0x66
  441. sbb dx, [bx+4]
  442. //_emit 0x66
  443. mov cx, pc.wRawMhz
  444. _emit 0x66
  445. jcxz bail
  446. _emit 0x66
  447. cmp dx, cx
  448. jb ok_to_divide
  449. _emit 0x66
  450. push ax
  451. _emit 0x66
  452. mov ax, dx
  453. _emit 0x66
  454. xor dx, dx
  455. _emit 0x66
  456. div cx
  457. _emit 0x66
  458. pop ax
  459. ok_to_divide:
  460. _emit 0x66
  461. div cx
  462. bail:
  463. }
  464. }
  465. static DWORD WINAPI p5DiffMillisec (PCTIMER * pBase)
  466. {
  467. _asm {
  468. _emit 0x0f
  469. _emit 0x31
  470. _emit 0x66
  471. xor bx, bx
  472. mov bx, pBase
  473. _emit 0x66
  474. sub ax, [bx]
  475. _emit 0x66
  476. sbb dx, [bx+4]
  477. _emit 0x66
  478. mov cx, pc.wRawKhz
  479. _emit 0x66
  480. jcxz bail
  481. _emit 0x66
  482. cmp dx, cx
  483. jb ok_to_divide
  484. _emit 0x66
  485. push ax
  486. _emit 0x66
  487. mov ax, dx
  488. _emit 0x66
  489. xor dx, dx
  490. _emit 0x66
  491. div cx
  492. _emit 0x66
  493. pop ax
  494. ok_to_divide:
  495. _emit 0x66
  496. div cx
  497. bail:
  498. }
  499. }
  500. static DWORD WINAPI p5DeltaTicks (PCTIMER * pBase)
  501. {
  502. _asm {
  503. _emit 0x0f
  504. _emit 0x31
  505. _emit 0x66
  506. mov bx, pBase
  507. _emit 0x66
  508. mov cx, ax
  509. _emit 0x66
  510. sub ax, [bx]
  511. _emit 0x66
  512. mov [bx], cx
  513. _emit 0x66
  514. mov cx, dx
  515. _emit 0x66
  516. sbb dx, [bx+4]
  517. _emit 0x66
  518. mov [bx+4], cx
  519. }
  520. }
  521. static DWORD WINAPI p5DeltaMicrosec (PCTIMER * pBase)
  522. {
  523. _asm {
  524. _emit 0x0f
  525. _emit 0x31
  526. _emit 0x66
  527. mov bx, pBase
  528. _emit 0x66
  529. mov cx, ax
  530. _emit 0x66
  531. sub ax, [bx]
  532. _emit 0x66
  533. mov [bx], cx
  534. _emit 0x66
  535. mov cx, dx
  536. _emit 0x66
  537. sbb dx, [bx+4]
  538. _emit 0x66
  539. mov [bx+4], cx
  540. _emit 0x66
  541. mov cx, pc.wRawMhz
  542. _emit 0x66
  543. jcxz bail
  544. _emit 0x66
  545. cmp dx, cx
  546. jb ok_to_divide
  547. _emit 0x66
  548. push ax
  549. _emit 0x66
  550. mov ax, dx
  551. _emit 0x66
  552. xor dx, dx
  553. _emit 0x66
  554. div cx
  555. _emit 0x66
  556. pop ax
  557. ok_to_divide:
  558. _emit 0x66
  559. div cx
  560. bail:
  561. }
  562. }
  563. static DWORD WINAPI p5DeltaMillisec (PCTIMER * pBase)
  564. {
  565. _asm {
  566. _emit 0x0f
  567. _emit 0x31
  568. _emit 0x66
  569. mov bx, pBase
  570. _emit 0x66
  571. mov cx, ax
  572. _emit 0x66
  573. sub ax, [bx]
  574. _emit 0x66
  575. mov [bx], cx
  576. _emit 0x66
  577. mov cx, dx
  578. _emit 0x66
  579. sbb dx, [bx+4]
  580. _emit 0x66
  581. mov [bx+4], cx
  582. //_emit 0x66
  583. mov cx, pc.wRawKhz
  584. _emit 0x66
  585. jcxz bail
  586. _emit 0x66
  587. cmp dx, cx
  588. jb ok_to_divide
  589. _emit 0x66
  590. push ax
  591. _emit 0x66
  592. mov ax, dx
  593. _emit 0x66
  594. xor dx, dx
  595. _emit 0x66
  596. div cx
  597. _emit 0x66
  598. pop ax
  599. ok_to_divide:
  600. _emit 0x66
  601. div cx
  602. bail:
  603. }
  604. }
  605. // 16 bit code for detecting CPU type so we can decide
  606. // whether or not it is ok to use the pentium timing stuff
  607. //
  608. int WINAPI pcGetCpuID ()
  609. {
  610. _asm {
  611. _emit 0x66
  612. pushf ; save eflags
  613. // check for 486 by attempting to set the 0x40000 bit
  614. // in eflags. if we can set it, the processor is 486 or better
  615. //
  616. _emit 0x66
  617. pushf ; push eflags
  618. pop ax ; move eflags to dx:ax
  619. pop dx
  620. or dx, 4 ; set 0x40000 bit in eflags
  621. push dx ; put back onto stack
  622. push ax
  623. _emit 0x66
  624. popf ; pop modified flags back into eflags
  625. _emit 0x66
  626. pushf ; push eflags back onto stack
  627. pop ax ; move eflags in to dx:bx
  628. pop dx
  629. _emit 0x66
  630. popf ; restore origonal eflags
  631. mov bx, 3 ; assume 386
  632. test dx, 4 ; 486 will preserve 0x40000 bit on push/pop of eflags
  633. jz ret_procid
  634. inc bx ; this is a 486 or higher
  635. // if we get to here it is a 486 or greater
  636. // check for pentium or higher by attempting to toggle the
  637. // ID bit (0x200000) in eflags.
  638. // on a pentium, this bit will toggle, on 486 it will not
  639. //
  640. _emit 0x66
  641. pushf ; save eflags
  642. _emit 0x66
  643. pushf ; get eflags
  644. pop ax ; put eflags into dx:ax
  645. pop dx
  646. xor dx, 0x20 ; toggle 0x200000 bit in eflags
  647. push dx
  648. push ax ; push modified eflags from dx:ax
  649. _emit 0x66
  650. popf ; load changed eflags
  651. _emit 0x66
  652. pushf ; get eflags again
  653. pop ax ; discard eflags lo
  654. pop ax ; get eflags hi
  655. xor dx, ax ; did anything change?
  656. _emit 0x66 ; restore old eflags
  657. popf
  658. test dx, 0x20 ; did we change the 20 bit?
  659. jz ret_procid ; if not, bx already has 4, return that
  660. // if we get to here, it is a pentium or greater
  661. // use the pentium CPUID instruction to detect exact processor
  662. // type
  663. //
  664. _emit 0x0F ; cpuid instruction
  665. _emit 0xA2
  666. shr ax, 8 ; extract family field
  667. and ax, 0x0F
  668. mov bx, ax ; 5 is pentium, others are higher
  669. ret_procid:
  670. mov ax, bx
  671. }
  672. }
  673. static DWORD WINAPI p5TimerFreq ()
  674. {
  675. if (pcGetCpuID() >= 5)
  676. {
  677. DWORD dw;
  678. DWORD dwTicks;
  679. static PCTIMER timer;
  680. p5InitTimer (&timer);
  681. dw = timeGetTime() + 200;
  682. while (timeGetTime() < dw)
  683. ;
  684. dw = timeGetTime() - dw;
  685. dwTicks = p5DiffTicks(&timer);
  686. pc.dwRawMhz = (dwTicks + dw * 1000/2) /dw /1000;
  687. pc.dwRawKhz = pc.dwRawMhz * 1000;
  688. pc.dwRawHz = pc.dwRawKhz * 1000;
  689. pc.dwMicroAdjust = 0;
  690. pc.dwTimerKhz = 1000;
  691. return pc.dwRawHz;
  692. }
  693. return 0;
  694. }
  695. VOID WINAPI InitPerformanceCounters (void)
  696. {
  697. if (p5TimerFreq() != 0l)
  698. {
  699. pc.DifTicks = p5DiffTicks;
  700. pc.DifMicrosec = p5DiffMicrosec;
  701. pc.DifMillisec = p5DiffMillisec;
  702. pc.DeltaTicks = p5DeltaTicks;
  703. pc.DeltaMicrosec = p5DeltaMicrosec;
  704. pc.DeltaMillisec = p5DeltaMillisec;
  705. pc.uTimerType = 5;
  706. return;
  707. }
  708. }
  709. #endif // WIN32
  710. #endif // _INC_MMTIMERS_CODE_