Search code examples
delphifunctionexternalgettickcount

Declaring external functions depending on whether they exist


I would like to declare an external function from the kernel32.dll library whose name is GetTickCount64. As far as I know, it is defined only in Vista and in later Windows versions. This means that when I define the function as follows:

function GetTickCount64: int64; external kernel32 name 'GetTickCount64';

I will certainly not be able to run my application on previous versions of Windows because of error generated on application startup.

Is there a workaround to that problem? Let's say I would like not to include that function when it does not exist and then use some substitute function in my code. How to do that? Are there any compiler directives that would help? I gues the definition would have to be surrounded by such directive and I would also have to use some directives wherever I use the GetTickCount64 founction, right?

Your help will be appreciated. Thanks in advance.

Mariusz.


Solution

  • Declare a function pointer of that type, and then load the function at run time with LoadLibrary or GetModuleHandle and GetProcAddress. You can find several examples of the technique in the Delphi source code; look at TlHelp32.pas, which loads the ToolHelp library, which isn't available on older versions of Windows NT.

    interface
    
    function GetTickCount64: Int64;
    
    implementation
    
    uses Windows, SysUtils;
    
    type
       // Don't forget stdcall for API functions.
      TGetTickCount64 = function: Int64; stdcall;
    
    var
      _GetTickCount64: TGetTickCount64;
    
    // Load the Vista function if available, and call it.
    // Raise EOSError if the function isn't available.
    function GetTickCount64: Int64;
    var
      kernel32: HModule;
    begin
      if not Assigned(_GetTickCount64) then begin
        // Kernel32 is always loaded already, so use GetModuleHandle
        // instead of LoadLibrary
        kernel32 := GetModuleHandle('kernel32');
        if kernel32 = 0 then
          RaiseLastOSError;
        @_GetTickCount := GetProcAddress(kernel32, 'GetTickCount64');
        if not Assigned(_GetTickCount64) then
          RaiseLastOSError;
      end;
      Result := _GetTickCount64;
    end;