For some reason, trying to create a TLanguages object provided by the SysUtils header by using the singleton or by calling the constructor directly is causing trouble in the wild, where some users report this error (X varies):
Access violation at address X. Write of address X (at address X)
... when the following seemingly innocent line of code is executed:
TLanguages.Create;
To clarify, this is not related to context. I can put this line in any place I like (as the only line of code of an empty program for example), but the problem remains.
The weird part is that this class is part of Delphi's standard headers, which should not fail (right?).
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;
The constructor attempts to use a member function as the EnumSystemLocales callback, which seems to be causing the crashes, because copying the TLanguages.LocalesCallback function to global scope and passing that to EnumSystemLocales works perfectly fine.
The struct contains the following Intel x86 assembly, where each item is given by its opcode:
pop edx
mov eax Self
push eax
push edx
jmp JmpOffset
Can anyone explain how the trick works and tell me why it's not working as expected?