Kas Ob. 121 Posted October 2 Hi, This version of GetTickCount works in both flavors (32Bit and 64Bit) on all 64Bit Windows versions, the result is identical to both APIs, also the 32Bit version of it will work on all 32bit Windows versions, the problem is i don't have access to to 32Bit Windows that is running for more than 49.7 days to test the 64Bit result version, And here comes the question for the help, if anyone have access to such OS, like Windows XP or Server 2003 that is running for that long time, it will be great help to test the result from the 64Bit result form this emulated API, and confirm it does return true value with value above the 32Bit. function GetTickCount64Emu: UInt64; const KUSER_BASE_ADDRESS = $7FFE0000; //KUSER_BASE_ADDRESS_KERNEL_MODE =$FFFFF78000000000; //in case it is needed begin Result := (PUInt64(KUSER_BASE_ADDRESS + $320)^ * PCardinal(KUSER_BASE_ADDRESS + $4)^) shr 24; end; Rename as you wish, and adjust as you see fit, like make the result Cardinal to replace GetTickCount or keep it as UInt64, it doesn't matter. and keep in mind it does exactly what GetTickCount and GetTickCount64 do, as this snippet i decompiled form the OS, also this address is fixed across Windows versions, and belongs to a readonly page protected, also in the past, well, far past Microsoft documentation for DDK, was suggesting using the same algorithm for games engines to ditch calling API for timing, to squeeze few extra cycles, so even if this approach is not documented now, it was and will stay accessible. The operation of multiplication and shifting is as it seems a simple division, but with fixed point, hence the bit shifting, per Microsoft documentation the Windows OS kernel is prohibited from using float point operation, and only fixed point are allowed, those has the point at 24th bit. If someone has insight about this, then please share, and if someone can confirm a result over 32bit on an old or new 32Bit system that was and is running for over 49.7 days, then it will be great to share the result. Share this post Link to post
Remy Lebeau 1392 Posted October 2 (edited) 2 hours ago, Kas Ob. said: also this address is fixed across Windows versions, and belongs to a readonly page protected, also in the past, well, far past Microsoft documentation for DDK, was suggesting using the same algorithm for games engines to ditch calling API for timing, to squeeze few extra cycles, so even if this approach is not documented now, it was and will stay accessible. You are accessing a 64bit tick counter that is located at fixed address (0x7FFE0000+800), but according to this discussion: https://groups.google.com/g/comp.lang.asm.x86/c/zA0WcO6_5AU, in XP SP1 and earlier at least, the tick counter was a 32bit integer located at address (0x7FFE0000) instead. According to the history outlined here: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm, Windows deprecated the 32bit counter and switched over to the 64bit counter in v5.2 (ie, XP Pro 64bit) onward. Edited October 2 by Remy Lebeau Share this post Link to post
Kas Ob. 121 Posted October 2 1 hour ago, Remy Lebeau said: You are accessing a 64bit tick counter that is located at fixed address (0x7FFE0000+800), but according to this discussion: https://groups.google.com/g/comp.lang.asm.x86/c/zA0WcO6_5AU, in XP SP1 and earlier at least, the tick counter was a 32bit integer located at address (0x7FFE0000) instead. Right, i should have mentioned that may be as i read that second source you linked. 1 hour ago, Remy Lebeau said: According to the history outlined here: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm, Windows deprecated the 32bit counter and switched over to the 64bit counter in v5.2 (ie, XP Pro 64bit) onward. According to this i have the it should (might) work for all starting from Windows XP SP2/SP3 and Server 2003 SP1, and that include 32Bit and 64Bit , as shown per declaration with 64bit size in that link, It is the same declared in DDK headers https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data also here explain the size of KSYSTEM_TIME https://osm.hpi.de/wrk/2007/08/getting-os-information-the-kuser_shared_data-structure/ And there a confession to make there is a condition i omitted in the code because i don't see it as big relevant, in 64bit there is a loop to establish that High2Time and High3Time are identical, this happen if updating one was happening at this very exact moment, i tried to slow my CPU by overloading up to 100%, and couldn't make this trigger, then tried to downclock and overclock CPU, as mine is Intel unlocked (model with "k"), yet even over more than an hour and in both cases could capture such case not even once, and i am not saying it is right to capture it, but i am saying statistically i satisfied, also even when they are not identical, meaning the result will be as much as it was like 100ns before, so no harm there, this can affect and important for kernel drivers, but can not be critical for any software in user mode. Share this post Link to post
Remy Lebeau 1392 Posted October 2 What is the goal here? GetTickCount64() is available in Vista (6.0) onward. The page you quoted says the 64bit tick counter existed in 5.1, but wasn't actually in use until 5.2. So 5.2->6.0 is a pretty small window if you are just looking to emulate GetTickCount64() on pre-Vista systems. 1 Share this post Link to post
aehimself 396 Posted October 2 Give me a couple of days: I'll let the admin know NOT to touch either this one or the host 🙂 1 Share this post Link to post
Kas Ob. 121 Posted October 3 12 hours ago, aehimself said: Give me a couple of days: I'll let the admin know NOT to touch either this one or the host 🙂 Great and perfect and Thank you ! Share this post Link to post
Kas Ob. 121 Posted October 3 12 hours ago, Remy Lebeau said: What is the goal here? GetTickCount64() is available in Vista (6.0) onward. The page you quoted says the 64bit tick counter existed in 5.1, but wasn't actually in use until 5.2. So 5.2->6.0 is a pretty small window if you are just looking to emulate GetTickCount64() on pre-Vista systems. I want to know and solve this, away from Windows Server 2003 and Windows XP rare existence, it is nice to have unified version to support them all, this single API stopped a punch of great and old software and split many repository. I don't see this as stupid or waste of time, if a time spent lead to a result in testing something, success or failure, for me this is well spent time. Share this post Link to post
aehimself 396 Posted October 26 @Kas Ob. The VM is now at 61 days of uptime. I'm having a bit of trouble compiling an EXE which actually executes on Windows 2003... I remember having to change something somewhere in the IDE / project options. If you know the solution let me know - it might be quicker than me attempting to research. Share this post Link to post
aehimself 396 Posted October 26 Found it! The code I used could not be more simple... program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function GetTickCount64Emu: UInt64; const KUSER_BASE_ADDRESS = $7FFE0000; //KUSER_BASE_ADDRESS_KERNEL_MODE =$FFFFF78000000000; //in case it is needed begin Result := (PUInt64(KUSER_BASE_ADDRESS + $320)^ * PCardinal(KUSER_BASE_ADDRESS + $4)^) shr 24; end; begin try WriteLn(GetTickCount64Emu); ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. And it resulted 5283539281 with 61 days, 3.5 hours of uptime on a 32-bit Windows Server 2003 R2: 1 Share this post Link to post
Kas Ob. 121 Posted October 27 15 hours ago, aehimself said: And it resulted 5283539281 with 61 days, 3.5 hours of uptime on a 32-bit Windows Server 2003 R2: Brilliant, thank you very very much ! This test is very hard to wait for and make, and you did it, really appreciated your sharing. Share this post Link to post
Kas Ob. 121 Posted October 27 To make it clearer, your result is 5283539281 in decimal which is 13AEC6951 in hex, meaning it did not wrapped (overflow) and performed exactly what GetTickCount64 should/have returned. Share this post Link to post