![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Здравствуйте, уже полторы недели туплю, над "волшебной" функцией заданной мне преподом, эта "уникальная" функция должна уметь загружать библиотеки, и использовать их функции, основоваясь на входящих аргументах: имя длл, имя функции, внутренние аргументы, заданные строкой. т.е. примерно так
Код:
Function SetFunction(dll,adress:string;a:array of b;l:integer):b;
var
Func:function(a:array of b):HINST;stdcall;
_dll:integer;
begin
_dll:=LoadLibrary(PChar(dll));
if(_dll<>0)then
begin
@Func:=getProcAddress(_dll,PChar(adress));
if(addr(Func)<>nil)then
begin
Func(a);
//setlength(result,l);
end;
end;
end;это то что я наклепал, я никак не могу решить праблу внутренних параметров(((( глаза уже мутные и мозг плавится, кто подскажет... помогите, всё что плохо обьяснил спросите, отвечу как смогуууу |
|
#2
|
||||
|
||||
|
Веселый, однако, препод. В длл функции могут по разным соглашениям вызываться, да и кол-во аргументов ф-ии заведомо не известно может быть. Если надо чтоб идеально работало, надо писать алгоритм анализа, как устроена ф-ия в длл (самый простой вариант - искать информацию в map файле, если таковой имеется). если же простяцкое-босяцкое, то просто пушить в стек аргументы (если дллка stdcall).
Код:
asm push arg3 push arg2 push arg1 call Func end; |
| Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение: | ||
reqyz (22.10.2012)
| ||
|
#3
|
|||
|
|||
|
можно подробнее пример, да функции stdcall, как этот асм использовать я с асемом просто дело не имел никогда(
с прописанием внутренних аргументов вся и загвоздка представь, есть форма, на ней куча едитов, в первый выбираешь имя длл во второй имя функции в ней, в третьем выбираешь типы параметров и значения, наример integer 8 string 'thtyhty' byte true нажимаешь кнопочку и это всё срабатывает, аргументы пусть пользователь вводит правильно, но программно то как это сформировать... ппц(( Последний раз редактировалось reqyz, 22.10.2012 в 20:27. |
|
#4
|
||||
|
||||
|
А препод с каким званием? Доцент/профессор?
Чем-то смахивает на "подметать плацдарм ломом". |
|
#5
|
||||
|
||||
|
Цитата:
Код:
var hModule: DWORD;
proc: pointer;
a: DWORD;
Params: array of DWORD;
...
hModule := LoadLibrary(Edit1.Text);
proc := GetProcAddress(hModule, Edit2.Text);
if (proc <> 0) then
begin
asm
mov esi, Params
mov ecx, count
lea esp, [esp - ecx * 4]
mov edi, esp
cld
rep movsd
mov eax, proc
call eax
end;
end
else
MessageBoxA(0, 'Печальная история...', 'Ошибка', 0);Последний раз редактировалось Bargest, 22.10.2012 в 21:14. |
|
#6
|
|||
|
|||
|
спасибо, потестю)
а что делать если среди параметров есть строка? |
|
#7
|
||||
|
||||
|
Цитата:
Тогда нужно уметь работать всего лишь с двумя типами значений -- строкой и числом (DWORD). LONGBOOL -- тоже DWORD. В синтаксисе inf-файлов строки обычно заключаются в кавычки, а числа передаются просто так. Можно еще 16-ричные числа обрабатывать, которые заданы как 0x########, но это уже на любителя. |
|
#8
|
|||
|
|||
|
Цитата:
реализовал функцию, всё кроме конст работает) вары возвращает) всё работает прекрассно) вот сама функция: Код:
function SetFunction(dll, adress, param: String;out res2:string;l:integer): LongWord;
type
TPoint=record
x:Int64;
y:byte;
end;
Tp=record
s:string;
c:Char;
end;
var
hdll: HMODULE;
proc: Pointer;
Params: array of LongWord;
_par:array of TPoint;//0 1 2 3
Strings: array of String;
PrmCount, StrCount, p,i: Integer;
pp:array[0..2]of Tp;
//param =var integer:const 8;boolean:1;out pchar:reqyz; integer:8; ...//например
begin
hdll := LoadLibrary(Pointer(dll));
if hdll = 0 then
exit;
try
proc := GetProcAddress(hdll, Pointer(adress));
if not Assigned(proc) then
exit;
PrmCount := 0;
StrCount := 0;
setlength(_par,l);
setlength(Params,l);
pp[0].c:=' ';
pp[1].c:=':';
pp[2].c:=';';
while param <> '' do
begin
for i:=0 to 2 do
begin
p := Pos(pp[i].c, param);
pp[i].s := Copy(param, 1, p - 1);
Delete(param, 1, p);
end;
if(pp[1].s = 'boolean')or(pp[1].s = 'integer')then
Params[PrmCount] := StrToInt(pp[2].s)
else
if pp[1].s = 'pchar' then
begin // Здесь строки нигде не сохранялись, поэтому указатели на них теряли актуальность
if Length(Strings) = StrCount then
SetLength(Strings, StrCount + 10);
Strings[StrCount] := pp[2].s;
Params[PrmCount] := longWORD(Strings[StrCount]);
Inc(StrCount);
end;
if(pp[0].s = 'var')then
begin
_par[PrmCount].y:=1;
_par[PrmCount].x:=Params[PrmCount];
Params[PrmCount]:=integer(@_par[PrmCount].x);
end
else
if(pp[0].s = 'const')then
_par[PrmCount].y:=2
else
if(pp[0].s = 'out')then
begin
_par[PrmCount].y:=3;
_par[PrmCount].x:=Params[PrmCount];
Params[PrmCount]:=integer(@_par[PrmCount].x);
end
else
if(pp[0].s = '')then
_par[PrmCount].y:=0;
Inc(PrmCount);
end;
asm
PUSH ESI
PUSH EDI
MOV ESI, Params
MOV ECX, PrmCount
NEG ECX
LEA ESP, [ESP + ECX * 4] // Здесь была ошибочная инструкция lea esp, [esp - ecx * 4]
NEG ECX
MOV EDI, ESP
CLD
REP MOVSD
MOV EAX, proc
CALL EAX
MOV Result, EAX // Сохраняем результат работы вызванной функции
POP EDI
POP ESI
end;
res2:='';
for p:=0 to length(_par)-1 do
if(_par[p].y=1)or(_par[p].y=3)
then
res2:=res2+inttostr(p)+':'+inttostr(_par[p].x)+';';
finally
FreeLibrary(hdll);
end;
end;но есть странные особенности при использовании констант Код:
//например так функция работает:
Function func(const a,b:longword):LongWord;stdcall
begin
if(a<>b)then
end;//часть в длл-ке
procedure TForm1.Button1Click(Sender: TObject);
begin
SetFunction('project2.dll','func','const integer:5;const integer:4;',s,2);
end;//использование
//так функция тоже работает:
type
req=record
a,b:longword;
end;
Function func(z:req):LongWord;stdcall
begin
if(z.a<>z.b)then
end;//часть в длл-ке
procedure TForm1.Button1Click(Sender: TObject);
begin
SetFunction('project2.dll','func',' integer:5; integer:4;',s,2);
end;//использование
//а так функция не работает:
type
req=record
a,b:longword;
end;
Function func(const z:req):LongWord;stdcall
begin
if(z.a<>z.b)then
end;//часть в длл-ке
procedure TForm1.Button1Click(Sender: TObject);
begin
SetFunction('project2.dll','func','const integer:5;const integer:4;',s,2);
end;//использованиея не понимаю почему( кто нибудь знает? я предполагаю, что в последнем случае функция ожидает указатель, я прав? да, как оказалось, я прав, в случае, когда константой является несколько одновременно параметров, то нужно передавать один указатель на них Последний раз редактировалось reqyz, 25.10.2012 в 09:49. |
|
#9
|
|||
|
|||
|
для общего развития неплохо бы прочитать
http://www.transl-gunsmoker.ru/2008/12/1.html http://www.transl-gunsmoker.ru/2008/12/2.html http://www.transl-gunsmoker.ru/2008/12/3.html http://www.transl-gunsmoker.ru/2008/12/4-ia64.html http://www.transl-gunsmoker.ru/2008/12/5-amd64.html Особенно третью и пятую части. По передаче параметров тут так. - говорю за x86 - stdcall Без модификаторов const,var или out boolean, char, целочисленные вплоть до (LongInt/DWORD), а так же всякие Pointer`ы- каждая величина кладётся в стек и занимает в стеке 4 байта. Int64 кладётся в стек и занимает в стеке 8 байт. String - представляет собой указатель на первый символ строки и занимает в стеке 4 байта. Перед вызовом процедуры производится увеличение количества ссылок на строку. Record, состоящий из вышеперечисленного кладётся в стек весь целиком. С модификатором const boolean, char, целочисленные вплоть до (LongInt/DWORD), а так же всякие Pointer`ы - каждая величина кладётся в стек и занимает в стеке 4 байта. Int64 - кладётся в стек и занимает в стеке 8 байт. String - представляет собой указатель на первый символ строки и занимает в стеке 4 байта. Увеличение счётчика не производится. Record`ы - в стек кладётся указатель на начало структуры. С модификатором var Для всех типов в стек кладётся адрес переменной. С модификатором out Для всех типов в стек кладётся адрес переменной. |
|
#10
|
|||
|
|||
|
в догонку
Возвращаемое значение boolean, char, byte, shortint - возвращаются в регистре AL word и smallint - возвращаются в регистре AX В Win-API накой способ не используется. Как правило возвращается целиком регистр EAX. LongInt,DWORD, а так же всякие Pointer`ы- возвращаются в регистре EAX. Int64 - возвращаются в регистрах EAX:EDX. Record - вызывающая программа должна подготовить место для record`а, и передать его адрес в качестве неявного параметра, расположеного после всех явных параметров. Вызываемая процедура работает с этим параметром как с параметром с out-модификатором. |
|
#11
|
|||
|
|||
|
А по теме.
тебе нужно разбить твою супер функцию на две или три части. Первая - получения адреса функции из DLL+всякие проверки. Вторая - разбор параметров и укладка их в массив. Безо всякого асма. И третья сам вызов - тут самая большая проблема, которая, если её выделить, может сильно упроститься. например до вот этого Код:
type
TFunction = function():DWord;stdcall;
function SuperCall(F:TFunction; const Params : Array of DWord):DWord;
var
I:Integer;
P:Pointer;
begin
for I:=0 to Length(Params)-1 do
begin
P:=@Params[i];
asm
mov EAX,P;
Push [EAX]; <<<<----======
end;
end;
Result:=F();
end; |