Delphi 设置Windows API的回调函数为类的方法

参考 SysUtils中TLanguages里面的技巧

{ This stores the languages that the system supports }

TLanguages = class

private

FSysLangs: array of TLangRec;

function LocalesCallback(LocaleID: PChar): Integer; stdcall;

function GetExt(Index: Integer): string;

function GetID(Index: Integer): string;

function GetLCID(Index: Integer): LCID;

function GetName(Index: Integer): string;

function GetNameFromLocaleID(ID: LCID): string;

function GetNameFromLCID(const ID: string): string;

function GetCount: integer;

public

constructor Create;

function IndexOf(ID: LCID): Integer;

property Count: Integer read GetCount;

property Name[Index: Integer]: string read GetName;

property NameFromLocaleID[ID: LCID]: string read GetNameFromLocaleID;

property NameFromLCID[const ID: string]: string read GetNameFromLCID;

property ID[Index: Integer]: string read GetID;

property LocaleID[Index: Integer]: LCID read GetLCID;

property Ext[Index: Integer]: string read GetExt;

end platform;

{ Called for each supported locale. }

function TLanguages.LocalesCallback(LocaleID: PChar): Integer; stdcall;

var

AID: LCID;

ShortLangName: string;

GetLocaleDataProc: function (ID: LCID; Flag: DWORD): string;

begin

if Win32Platform = VER_PLATFORM_WIN32_NT then

GetLocaleDataProc := @GetLocaleDataW

else

GetLocaleDataProc := @GetLocaleDataA;

AID := StrToInt('$' + Copy(LocaleID, 5, 4));

ShortLangName := GetLocaleDataProc(AID, LOCALE_SABBREVLANGNAME);

if ShortLangName <> '' then

begin

SetLength(FSysLangs, Length(FSysLangs) + 1);

with FSysLangs[High(FSysLangs)] do

begin

FName := GetLocaleDataProc(AID, LOCALE_SLANGUAGE);

FLCID := AID;

FExt := ShortLangName;

end;

end;

Result := 1;

end;

constructor TLanguages.Create;

type

TCallbackThunk = packed record

POPEDX: Byte;

MOVEAX: Byte;

SelfPtr: Pointer;

PUSHEAX: Byte;

PUSHEDX: Byte;

JMP: Byte;

JmpOffset: Integer;

end;

var

Callback: TCallbackThunk;

begin

inherited Create;

Callback.POPEDX := $5A;

Callback.MOVEAX := $B8;

Callback.SelfPtr := Self;

Callback.PUSHEAX := $50;

Callback.PUSHEDX := $52;

Callback.JMP := $E9;

Callback.JmpOffset := Integer(@TLanguages.LocalesCallback) - Integer(@Callback.JMP) - 5;

EnumSystemLocales(TFNLocaleEnumProc(@Callback), LCID_SUPPORTED);

end;

function TLanguages.GetCount: Integer;

begin

Result := High(FSysLangs) + 1;

end;

function TLanguages.GetExt(Index: Integer): string;

begin

Result := FSysLangs[Index].FExt;

end;

function TLanguages.GetID(Index: Integer): string;

begin

Result := HexDisplayPrefix + IntToHex(FSysLangs[Index].FLCID, 8);

end;

function TLanguages.GetLCID(Index: Integer): LCID;

begin

Result := FSysLangs[Index].FLCID;

end;

function TLanguages.GetName(Index: Integer): string;

begin

Result := FSysLangs[Index].FName;

end;

function TLanguages.GetNameFromLocaleID(ID: LCID): string;

var

Index: Integer;

begin

Index := IndexOf(ID);

if Index <> - 1 then Result := Name[Index];

if Result = '' then Result := sUnknown;

end;

function TLanguages.GetNameFromLCID(const ID: string): string;

begin

Result := NameFromLocaleID[StrToIntDef(ID, 0)];

end;

function TLanguages.IndexOf(ID: LCID): Integer;

begin

for Result := Low(FSysLangs) to High(FSysLangs) do

if FSysLangs[Result].FLCID = ID then Exit;

Result := -1;

end;

//==================================

将类的方法巧妙的变成windowsAPI的回调函数,

由于类的方法调用时隐含类指针,隐藏在调用时,这里通过一个TCallbackThunk实现在调用时直接跳过类指针来到真实的

方法地址。这种应用需要对类的方法使用过程以及汇编语言中函数调用过程熟悉才能做到。

原文地址:https://www.cnblogs.com/caibirdy1985/p/4232982.html