Форум: "Прочее";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
ВнизПередача указателя на метод как на non-object функцию. Найти похожие ветки
← →
Дмитрий С © (2010-04-07 14:40) [0]Передать указатель на метод в качестве аргумента функции, например, EnumWindows не выйдет, по понятным причинам: хотя бы потому что метод 8 байт, а указатель 4 :).
Я написал враппер для случаев, когда нужно передать метод экземпляра класса и не хочется городить функции, использовать lparam и еще 100 причин.
У меня была необходимость передавать указатель на cdecl-функцию, а не stdcall.
Выкладываю код на общий суд:
Форма Form2, на ней кнопка Button1.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TSomeFunctionType = function (A, B: Cardinal): Cardinal; cdecl;
TForm2 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FMul: Integer; { Тестовое значение этого объекта
для использования внутри SomeCdeclMethod }
FSomeCdeclMethodWrapper: Pointer; { Указатель на Wrapper для
метода SomeCdeclMethod,
его нужно передавать в качестве параметра
в Api функции
}
function SomeCdeclMethod(A, B: Cardinal): Cardinal; cdecl; { Тестовый метод }
private
{ Функции для создания и освобождения Wrapper-ов }
function GetWrapper(Method: Pointer): Pointer;
procedure FreeWrapper(WrapperPtr: Pointer);
public
{ Как бы Api функция }
procedure Test(NonObjectProc: TSomeFunctionType);
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
{
Используем враппер
}
Test( FSomeCdeclMethodWrapper );
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
FMul := 2;
{
Инициализируем враппер
}
FSomeCdeclMethodWrapper := GetWrapper(@TForm2.SomeCdeclMethod);
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
FreeWrapper(FSomeCdeclMethodWrapper);
end;
procedure TForm2.FreeWrapper(WrapperPtr: Pointer);
begin
VirtualFree(WrapperPtr, 0, MEM_RELEASE);
end;
function TForm2.GetWrapper(Method: Pointer): Pointer;
const
Prg: array[0..37] of byte = (
$58, {pop eax}
$68, {2} 0,0,0,0, {push <Self>}
$50, {push eax}
$B8, {8}0,0,0,0, {mov eax, <Mtd>}
$5A, {pop edx}
$BB, {14}0,0,0,0, {mov ebx, <PointToDummy>}
$89, $13, {mov [ebx], edx}
$FF, $D0, {call eax}
$83,$C4,$04, {add esp, 4}
$BB, {26}0,0,0,0, {mov ebx, <PointToDummy>}
$8B, $13, {mov edx, [ebx]}
$52, {push edx}
$C3, {ret}
{34}0,0,0,0); {Dummy}
var
B: PByteArray;
PtrToEnd: Pointer;
begin
Result := VirtualAlloc(nil, SizeOf(Prg), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Win32Check(Result <> nil);
CopyMemory(Result, @Prg, SizeOf(Prg));
B := Result;
CopyMemory(@B^[2], @Self, 4);
CopyMemory(@B^[8], @Method, 4);
PtrToEnd := @B^[34];
CopyMemory(@B^[14], @PtrToEnd, 4);
CopyMemory(@B^[26], @PtrToEnd, 4);
end;
function TForm2.SomeCdeclMethod(A, B: Cardinal): Cardinal;
begin
Result := (A + B) * FMul;
end;
procedure TForm2.Test(NonObjectProc: TSomeFunctionType);
begin
ShowMessage(
IntToStr(
NonObjectProc(1,2)
)
);
end;
end.
Интересует мнения, ваши замечания, более простые решения.
P.S. Еще конкретный, для возврата используется только регистр EAX?
← →
oxffff © (2010-04-07 14:54) [1]function Classes.MakeObjectInstance(AMethod: TWndMethod): Pointer;
← →
oxffff © (2010-04-07 15:05) [2]The following conventions are used for returning function result values.
Ordinal results are returned, when possible, in a CPU register. Bytes are returned in AL, words are returned in AX, and double-words are returned in EAX.
Real results are returned in the floating-point coprocessor"s top-of-stack register (ST(0)). For function results of type Currency, the value in ST(0) is scaled by 10000. For example, the Currency value 1.234 is returned in ST(0) as 12340.
For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.
Int64 is returned in EDX:EAX.
Pointer, class, class-reference, and procedure-pointer results are returned in EAX.
For static-array, record, and set results, if the value occupies one byte it is returned in AL; if the value occupies two bytes it is returned in AX; and if the value occupies four bytes it is returned in EAX. Otherwise, the result is returned in an additional var parameter that is passed to the function after the declared parameters.
← →
oxffff © (2010-04-07 15:08) [3]+ возможно тебе будет интересен модуль ObjAuto для исследований.
← →
Дмитрий С © (2010-04-07 15:18) [4]
> function Classes.MakeObjectInstance(AMethod: TWndMethod):
> Pointer;
По-моему это не совсем то, что нужно, хотя я точно так и не понял.
> oxffff © (07.04.10 15:05) [2]
А это полезно. Мой враппер испортит возвращаемое Int64 значение функции, если таковое будет. :)
> ObjAuto для исследований.
почитаю
← →
Leonid Troyanovsky © (2010-04-07 16:23) [5]
> Дмитрий С © (07.04.10 15:18) [4]
> > function Classes.MakeObjectInstance(AMethod: TWndMethod):
> По-моему это не совсем то, что нужно, хотя я точно так и
> не понял.
Это - то. Оно стоит изучения.
Но, в подобных вещах не следует, IMHO:
1. Разрабатывать универсальные методы на все случаи жизни.
2. Полагаться на то, что действующая политика всегда останется
к оным вещам равнодушной.
Сегодня запретили выполнять код из стека, а завтра не разрешат
менять в екзешнике атрибуты страниц.
И выживут самые морозоустойчивые :)
--
Regards, LVT.
← →
Игорь Шевченко © (2010-04-07 17:43) [6]Читаем разницу между TWndMethod и "любая callback-функция"
← →
oxffff © (2010-04-07 19:52) [7]
> Игорь Шевченко © (07.04.10 17:43) [6]
> Читаем разницу между TWndMethod и "любая callback-функция"
Где написано, что любая?
[2] - это пример реализации заголовка темы.
← →
Игорь Шевченко © (2010-04-07 20:52) [8]oxffff © (07.04.10 19:52) [7]
[2] это что где возвращается.
> Где написано, что любая?
в [0]
← →
oxffff © (2010-04-08 08:31) [9]
> Игорь Шевченко © (07.04.10 20:52) [8]
> oxffff © (07.04.10 19:52) [7]
>
> [2] это что где возвращается.
Да, моя оплошность. Но вы поняли.
← →
oxffff © (2010-04-08 08:39) [10]
> Игорь Шевченко © (07.04.10 20:52) [8]
> oxffff © (07.04.10 19:52) [7]
> > Где написано, что любая?
>
>
> в [0]
И?
В чем вы видите сложность обобщенного кода при реализации произвольной трансляции, учитывая [2],[3] и RTTI?
← →
Юрий Зотов © (2010-04-08 09:28) [11]> Интересует мнения, ваши замечания, более простые решения.
Непонятно, зачем нужно городить огород. Можно же передать адрес обычной callback-функции, а уже в ней никто не мешает вызвать любой метод любого объекта. Это и есть то самое "более простое решение" (и вполне безопасное, к тому же).
← →
oxffff © (2010-04-08 09:34) [12]
> Юрий Зотов © (08.04.10 09:28) [11]
> > Интересует мнения, ваши замечания, более простые решения.
>
>
> Непонятно, зачем нужно городить огород. Можно же передать
> адрес обычной callback-функции, а уже в ней никто не мешает
> вызвать любой метод любого объекта. Это и есть то самое
> "более простое решение" (и вполне безопасное, к тому же).
>
Именно это и происходит. Только сложность в том, что в таком случае придется реализовывать все функции во время компиляции программисту.
То есть для каждой пары - объект+сигнатура метода.
Поэтому и прибегают к динамическому инстанцированию, для удобства и расширяемости.
← →
Дмитрий С © (2010-04-08 10:38) [13]
> а завтра не разрешат
> менять в екзешнике атрибуты страниц.
Будем DLL генерить :) Прикольно получится - для каждого экземпляра класса своя dll :)
← →
Дмитрий С © (2010-04-19 17:33) [14]Код в шапке ошибочный, как выяснилось, вызывает потерю ebx, что недопустимо для вызова cdecl. Константу Prg нужно заменить на
Prg: array[0..37] of byte = (
$58, {pop eax}
$68, {2} 0,0,0,0, {push <Self>}
$50, {push eax}
$B8, {8}0,0,0,0, {mov eax, <Mtd>}
$5A, {pop edx} //
$B9, {14}0,0,0,0, {mov ecx, <PointToDummy>}
$89, $11, {mov [ecx], edx}
$FF, $D0, {call eax}
$83,$C4,$04, {add esp, 4}
$B9, {26}0,0,0,0, {mov ecx, <PointToDummy>}
$8B, $11, {mov edx, [ecx]}
$52, {push edx}
$C3, {ret}
{34}0,0,0,0); {Dummy}
P.S. Это для тех, кто тему по поиску вдруг найдет
← →
RC (2010-04-20 17:41) [15]To Дмитрий С ©
http://delphikingdom.com/asp/answer.asp?IDAnswer=58782
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.065 c