Объявление внешних функций в зависимости от того, существуют ли они

Я хотел бы объявить внешнюю функцию из библиотеки kernel32.dll с именем GetTickCount64. Насколько я знаю, он определяется только в Висте и в более поздних версиях Windows. Это означает, что когда я определяю функцию следующим образом:

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

Я определенно не смогу запустить свое приложение в предыдущих версиях Windows из-за ошибки, возникающей при запуске приложения.

Есть ли обходной путь к этой проблеме? Допустим, я хотел бы не включать эту функцию, когда она не существует, а затем использовать какую-то замещающую функцию в моем коде. Как это сделать? Существуют ли какие-либо директивы компилятора, которые могут помочь? Я предполагаю, что определение должно быть окружено такой директивой, и мне также придется использовать некоторые директивы везде, где я использую функцию GetTickCount64, верно?

Ваша помощь будет оценена по достоинству. Заранее спасибо.

Мариуш.


person Mariusz Schimke    schedule 25.04.2009    source источник


Ответы (1)


Объявите указатель на функцию этого типа, а затем загрузите функцию во время выполнения с помощью LoadLibrary или GetModuleHandle и GetProcAddress. Вы можете найти несколько примеров этой техники в исходном коде Delphi; просмотрите TlHelp32.pas, который загружает библиотеку ToolHelp , который недоступен в более ранних версиях 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;
person Rob Kennedy    schedule 25.04.2009
comment
Спасибо за Ваш ответ. Я думаю, это то, что я искал. Но у меня есть вопрос. Я хотел бы изменить условие следующим образом: если не Assigned(_GetTickCount64), то @_GetTickCount64 := @GetTickCount; Это правильно? Как видите, я использовал функцию GetTickCount, объявленную по умолчанию в модуле Windows, в качестве замены, когда GetTickCount64 не определен. Я так понимаю, что любую функцию, возвращающую int64, я могу присвоить переменной _GetTickCount64, верно? Или это должна быть только внешняя функция? Я еще не знаю ключевое слово stdcall :-(. - person Mariusz Schimke; 25.04.2009
comment
Вы можете назначить DWord для Int64, но вы не можете назначить указатель на функцию, возвращающую DWord, на указатель на функцию, возвращающую Int64. Вы можете написать другую функцию, соответствующую сигнатуре GetTickCount64, и вызвать в ней GetTickCount. Назначьте указатель на эту функцию в _GetTickCount64, если вы обнаружите, что реальная функция отсутствует. - person Rob Kennedy; 25.04.2009