Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > ОС и железо
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.10.2012, 20:02
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
Печаль универсальная загрузка dll

Здравствуйте, уже полторы недели туплю, над "волшебной" функцией заданной мне преподом, эта "уникальная" функция должна уметь загружать библиотеки, и использовать их функции, основоваясь на входящих аргументах: имя длл, имя функции, внутренние аргументы, заданные строкой. т.е. примерно так

Код:
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  
Старый 22.10.2012, 20:11
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,505
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Веселый, однако, препод. В длл функции могут по разным соглашениям вызываться, да и кол-во аргументов ф-ии заведомо не известно может быть. Если надо чтоб идеально работало, надо писать алгоритм анализа, как устроена ф-ия в длл (самый простой вариант - искать информацию в map файле, если таковой имеется). если же простяцкое-босяцкое, то просто пушить в стек аргументы (если дллка stdcall).
Код:
asm
  push arg3
  push arg2
  push arg1
  call Func
end;
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
Этот пользователь сказал Спасибо M.A.D.M.A.N. за это полезное сообщение:
reqyz (22.10.2012)
  #3  
Старый 22.10.2012, 20:23
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

можно подробнее пример, да функции stdcall, как этот асм использовать я с асемом просто дело не имел никогда(

с прописанием внутренних аргументов вся и загвоздка

представь, есть форма, на ней куча едитов, в первый выбираешь имя длл во второй имя функции в ней, в третьем выбираешь типы параметров и значения, наример

integer 8
string 'thtyhty'
byte true

нажимаешь кнопочку и это всё срабатывает, аргументы пусть пользователь вводит правильно, но программно то как это сформировать... ппц((

Последний раз редактировалось reqyz, 22.10.2012 в 20:27.
Ответить с цитированием
  #4  
Старый 22.10.2012, 20:56
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,505
Версия Delphi: XE10
Репутация: выкл
По умолчанию

А препод с каким званием? Доцент/профессор?
Чем-то смахивает на "подметать плацдарм ломом".
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
  #5  
Старый 22.10.2012, 21:09
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
представь, есть форма, на ней куча едитов, в первый выбираешь имя длл во второй имя функции в ней, в третьем выбираешь типы параметров и значения, наример
Код:
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);
Как-то так в случае, если параметры можно превратить в массив двордов Params (абсолютное большинство случаев). Если нельзя (суммарное кол-во байт не делится на 4) - то придется подобным образом с вордами (к счастью до байтов скатываться не придется - push для байта не существует, так что суммарный размер параметров всегда делится на 2 как минимум).
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 22.10.2012 в 21:14.
Ответить с цитированием
  #6  
Старый 22.10.2012, 21:15
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

спасибо, потестю)
а что делать если среди параметров есть строка?
Ответить с цитированием
  #7  
Старый 25.10.2012, 00:24
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 576
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от reqyz
эта "уникальная" функция должна уметь загружать библиотеки, и использовать их функции, основоваясь на входящих аргументах: имя длл, имя функции, внутренние аргументы, заданные строкой. т.е. примерно так
Кстати, гм. Эта функциональность очень похожа на rundll32 и прочие inf и advapi32.

Тогда нужно уметь работать всего лишь с двумя типами значений -- строкой и числом (DWORD). LONGBOOL -- тоже DWORD. В синтаксисе inf-файлов строки обычно заключаются в кавычки, а числа передаются просто так. Можно еще 16-ричные числа обрабатывать, которые заданы как 0x########, но это уже на любителя.
Ответить с цитированием
  #8  
Старый 25.10.2012, 02:03
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Цитата:
Сообщение от Freeman
Кстати, гм. Эта функциональность очень похожа на rundll32 и прочие inf и advapi32.

Тогда нужно уметь работать всего лишь с двумя типами значений -- строкой и числом (DWORD). LONGBOOL -- тоже DWORD. В синтаксисе inf-файлов строки обычно заключаются в кавычки, а числа передаются просто так. Можно еще 16-ричные числа обрабатывать, которые заданы как 0x########, но это уже на любителя.
можно подробнее) или пример)

реализовал функцию, всё кроме конст работает) вары возвращает)

всё работает прекрассно)
вот сама функция:

Код:
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  
Старый 25.10.2012, 11:13
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

для общего развития неплохо бы прочитать
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  
Старый 25.10.2012, 11:23
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

в догонку
Возвращаемое значение
boolean, char, byte, shortint - возвращаются в регистре AL
word и smallint - возвращаются в регистре AX
В Win-API накой способ не используется. Как правило возвращается целиком регистр EAX.
LongInt,DWORD, а так же всякие Pointer`ы- возвращаются в регистре EAX.
Int64 - возвращаются в регистрах EAX:EDX.
Record - вызывающая программа должна подготовить место для record`а, и передать его адрес в качестве неявного параметра, расположеного после всех явных параметров. Вызываемая процедура работает с этим параметром как с параметром с out-модификатором.
Ответить с цитированием
  #11  
Старый 25.10.2012, 11:34
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

А по теме.
тебе нужно разбить твою супер функцию на две или три части.
Первая - получения адреса функции из 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;
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 20:44.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter