Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.144.35.148] |
|
Сообщ.
#1
,
|
|
|
Добрый день.
Помогите доперевести код на ASM x64. {$IFDEF WIN64} function CallFunc(const AObj: TObject; AMethod: Pointer; var AResult: Variant): Variant; asm .NOFRAME PUSH RSI PUSH RDI LEA RCX, [AObj] PUSH RCX MOV RDX, AResult CALL AMethod MOV Result, 1 POP RAX POP RCX POP RDX end; function CallFuncParam(const AObj: TObject; AMethod: Pointer; var AResult: Variant; const AParams: Pointer): Variant; asm .PARAMS 64 PUSH RSI PUSH RDI MOV RAX, RCX MOV RCX, RDX MOV RDX, AResult CALL AMethod MOV Result, 1 POP RAX POP RCX POP RDX end; {$ENDIF} function TmyClass.CallMethod(AObject: TObject; const AMethod: string; AParams: PVariant): Variant; var method_def: TmbMethod; method: pointer; pvar: pointer; param_count: integer; el_size: integer; rez: Variant; begin method_def := FindMethod(AMethod); if method_def = nil then raise Exception.CreateFmt('Method not found', [AMethod]); el_size := 0; pvar := AParams; if AParams = nil then param_count := 0 else if VarIsArray(AParams^) then with PVarData(AParams).VArray^ do begin param_count := Bounds[0].ElementCount; pvar := Data; el_size := ElementSize; end else param_count := 1; if method_def.ParamCnt <> param_count then raise Exception.CreateFmt('BadMethodParamCount', [AMethod, method_def.ParamCnt, param_count]); method := method_def.Addr; // заносим параметры в стек в обратном порядке (stdcall) {$IFDEF WIN32} pvar := PAnsiChar(pvar) + (param_count - 1) * el_size; while param_count > 0 do begin asm push pvar end; Dec(PAnsiChar(pvar), el_size); Dec(param_count); end; asm mov eax, [AObject] // передаем self push eax end; // Если метод возвращает результат (функция), заносим Result в стек if method_def.Result then asm push Result end; asm call method end; {$ELSE} if param_count = 0 then rez := CallFunc(AObject, method, Result) else begin rez := CallFuncParam(AObject, method, Result, AParams) end; {$ENDIF} end; из dll вызываю методы: Код: function RegEmployee(const AEmployee: Variant): Variant; stdcall; function GetStreets(const ASettlementID, AStreetType: Variant): Variant; stdcall; Для методов без параметров CallFunc отрабатывает, и все ок. Для методов с параметрами CallFuncParam отрабатывает, но параметры не могу заполнить. Помогите дописать CallFuncParam чтобы заполнялись параметры. Спасибо. |
Сообщ.
#2
,
|
|
|
D-monua, вы хотите сделать универсальную функцию, которая будет вызывать любой метод с любыми параметрами?
Почему нельзя обычным образом вызывать методы из DLL, а нужно именно через такую функцию? Почему у вас push'атся одни регистры, а pop'ятся другие? Вы знаете, что если параметров больше 4-х, их нужно будет заносить в стек? И что надо выравнивать стек и оставлять буфер 20h при вызове процедуры? Почитайте про соглашения о вызовах Win x64. Добавлено И вообще, вы уверены, что вам обязательно нужно работать с типами Variant? |
Сообщ.
#3
,
|
|
|
D-monua
Если очень нужна именно такая "универсальная" реализация, то можно использовать методы с открытым массивом Variant-параметров: AParams: array of const. Тогда не придется городить никакой огород на асме. Но, судя по примеру вызова из dll function RegEmployee(const AEmployee: Variant): Variant; stdcall; function GetStreets(const ASettlementID, AStreetType: Variant): Variant; stdcall; вообще не понятно, зачем нужен универсальный способ вызова через единый CallMethod? Почему бы для каждой из этих функций не написать свою реализацию с нормальным вызовом конкретного метода обычным образом без каких-либо выкрутасов с FindMethod и т.д. и т.п.? |