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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #31  
Старый 24.10.2012, 18:15
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

с этим ясно) не понятно почему у меня ругалось, но всё же ясно, что можно и так передавать.. а почему ругается то тогда?

как в код асм добавить чтоб по разному для вар и оут?)
"обнаглевший я хочет готовый пример" я сам не додумаюсь, надеюсь вас не затруднит, пожалуйста)
Ответить с цитированием
  #32  
Старый 24.10.2012, 18:16
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

В асме ничего менять не придется. Нужно только добавить в делфовской части. А что - я уже описал.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #33  
Старый 24.10.2012, 18:51
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Код:
function SHFileOperation(const lpFileOp: _SHFILEOPSTRUCTA): Integer; stdcall; external shell32 name 'SHFileOperationA';//так работает

function SHFileOperation(lpFileOp: _SHFILEOPSTRUCTA): Integer; stdcall; external shell32 name 'SHFileOperationA';//так не работает

это как то обойти можно? конст значительно влияет, без него вылетает ошибка рунтайм еррор 216..


наверно я идиот и ничего не понимаю(
Код:
    while param <> '' do
    begin
      //тут я получаю тип передачи (вар оут конст)
      p := Pos(' ', param);
      if p = 0 then RaiseErrorFmt('Ожидался символ " " в строке "%s"', [param]);
      p0 := Copy(param, 1, p - 1);
      Delete(param, 1, p);

      p := Pos(':', param);
      if p = 0 then RaiseErrorFmt('Ожидался символ ":" в строке "%s"', [param]);
      p1 := LowerCase(Copy(param, 1, p - 1));
      Delete(param, 1, p);

      p := Pos(';', param);
      if p = 0 then RaiseErrorFmt('Ожидался символ ";" в строке "%s"', [param]);
      p2 := Copy(param, 1, p - 1);
      Delete(param, 1, p);

      if Length(Params) = PrmCount then
      begin
        SetLength(Params, PrmCount + 10);
        SetLength(_par, PrmCount + 10);
      end;

      //тут я использую индексы и запоминаю этот тип
      if(p0 = 'var')then
        _par[PrmCount]:=1
      else
      if(p0 = 'const')then
        _par[PrmCount]:=2
      else
      if(p0 = 'out')then
        _par[PrmCount]:=3
      else
      if(p0 = '')then
        _par[PrmCount]:=0
      else
        RaiseErrorFmt('Неподдерживаемый тип "%s"', [p0]);

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

Надо читать описание функции на нормальных источниках.
Цитата:
Сообщение от MSDN
int SHFileOperation(
_Inout_ LPSHFILEOPSTRUCT lpFileOp
);

A pointer to an SHFILEOPSTRUCT structure
Видимо делфа оптимизирует и передает указатель на структуру для const'а в этом конкретном случае. Так что это скорее случайность. А запихивать в стек саму структуру, когда нужен указатель - конечно будет рантайм еррор.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
Этот пользователь сказал Спасибо Bargest за это полезное сообщение:
reqyz (24.10.2012)
  #35  
Старый 24.10.2012, 19:32
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 576
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Bargest
Видимо делфа оптимизирует и передает указатель на структуру для const'а в этом конкретном случае.
Как раз const и говорить о том, что можно не копировать данные в стек, а смело передавать указатель на сами данные, потому как в процедуре они изменяться не будут.
Ответить с цитированием
  #36  
Старый 24.10.2012, 19:34
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Надо читать описание функции на нормальных источниках.

Видимо делфа оптимизирует и передает указатель на структуру для const'а в этом конкретном случае. Так что это скорее случайность. А запихивать в стек саму структуру, когда нужен указатель - конечно будет рантайм еррор.


ну ладно, тут тогда разберусь) а вторая часть вопоса, где мне _par учитывать?

Последний раз редактировалось reqyz, 24.10.2012 в 19:38.
Ответить с цитированием
  #37  
Старый 24.10.2012, 19:35
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Цитата:
Сообщение от Freeman
Как раз const и говорить о том, что можно не копировать данные в стек, а смело передавать указатель на сами данные, потому как в процедуре они изменяться не будут.
что же тогда делать то?
Ответить с цитированием
  #38  
Старый 24.10.2012, 19:39
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
Сообщение от reqyz
что же тогда делать то?
Что делать? Нормально описать параметры функции, в соответствии с официальными документами. В конкретно этом случае определить тип "указатель на эту структуру".

А где pVar учитывать - надо было внимательнее читать. В pVar нужно сохранять не только номер типа, но и адрес переменной этого типа, которая выделяется динамически. В массив Params класть тоже адрес VAR-овской переменной. А после вызова фунцкии проходить по массиву и выводить параметры в зависимости от типа.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #39  
Старый 24.10.2012, 19:57
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Что делать? Нормально описать параметры функции, в соответствии с официальными документами. В конкретно этом случае определить тип "указатель на эту структуру".

А где pVar учитывать - надо было внимательнее читать. В pVar нужно сохранять не только номер типа, но и адрес переменной этого типа, которая выделяется динамически. В массив Params класть тоже адрес VAR-овской переменной. А после вызова фунцкии проходить по массиву и выводить параметры в зависимости от типа.

я ничего не понял, поэтому сделал как понял(

Код:
function SetFunction(dll, adress, param: String;out res2:string): LongWord;
type
  TPoint=record
    x:longword;
    y:Pointer;
  end;
var
  hdll: HMODULE;
  LastError: LongWord;
  proc: Pointer;
  Params: array of TPoint;
  _par:array of TPoint;//0 1 2 3
  Strings: array of String;
  PrmCount, StrCount, p: Integer;
  p0, p1, p2: String;
  //param =var integer:const 8;boolean:1;out pchar:reqyz; integer:8; ...//например
begin
  hdll := LoadLibrary(Pointer(dll));
  if hdll = 0 then
  begin
    LastError := GetLastError;
    {RaiseErrorFmt('При загрузке библиотеки "%s" возникла ошибка №%d: "%s"',
      [dll, LastError, SysErrorMessage(LastError)]);}
    exit;
  end;

  try
    proc := GetProcAddress(hdll, Pointer(adress));
    if not Assigned(proc) then
    begin
      //RaiseErrorFmt('В библиотеке "%s" отсутствует процедура "%s"', [dll, adress]);
      exit;
    end;
    PrmCount := 0;
    StrCount := 0;

    while param <> '' do
    begin
      p := Pos(' ', param);
      if p = 0 then
      begin
        //RaiseErrorFmt('Ожидался символ " " в строке "%s"', [param]);
        exit;
      end;
      p0 := Copy(param, 1, p - 1);
      Delete(param, 1, p);

      p := Pos(':', param);
      if p = 0 then
      begin
        //RaiseErrorFmt('Ожидался символ ":" в строке "%s"', [param]);
        exit;
      end;
      p1 := Copy(param, 1, p - 1);
      Delete(param, 1, p);

      p := Pos(';', param);
      if p = 0 then
      begin
        //RaiseErrorFmt('Ожидался символ ";" в строке "%s"', [param]);
        exit;
      end;
      p2 := Copy(param, 1, p - 1);
      Delete(param, 1, p);

      if Length(Params) = PrmCount then
      begin
        SetLength(Params, PrmCount + 10);
        SetLength(_par, PrmCount + 10);
      end;

      if p1 = 'integer' then
        Params[PrmCount].x := StrToInt(p2)
      else
      if p1 = 'boolean' then
        Params[PrmCount].x := StrToInt(p2)
      else
      if p1 = 'pchar' then
      begin // Здесь строки нигде не сохранялись, поэтому указатели на них теряли актуальность
        if Length(Strings) = StrCount then
          SetLength(Strings, StrCount + 10);
        Strings[StrCount] := p2;
        Params[PrmCount].x := longWORD(Strings[StrCount]);
        Inc(StrCount);
      end else
      begin
        //RaiseErrorFmt('Неподдерживаемый тип "%s"', [p1]);

      end;

      _par[PrmCount].y:=addr(Params[PrmCount]);

      if(p0 = 'var')then
        _par[PrmCount].x:=1
      else
      if(p0 = 'const')then
        _par[PrmCount].x:=2
      else
      if(p0 = 'out')then
        _par[PrmCount].x:=3
      else
      if(p0 = '')then
        _par[PrmCount].x:=0
      else
      begin
        //RaiseErrorFmt('Неподдерживаемый тип "%s"', [p0]);
      end;
      param[PrmCount].y:=addr(_par[PrmCount].x);

      Inc(PrmCount);
    end;
//mov        ax,word ptr value
    asm
      PUSH ESI
      PUSH EDI
      MOV  ESI, Params[PrmCount].x//тут теперь не компилит
      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].x=1)or(_par[p].y=3)
        then
          res2:=res2+inttostr(p)+':'+inttostr(Params[p].x)+';';
  finally
    FreeLibrary(hdll);
  end;
end;

где использовать новые параметры я не знаю, и что нужно менять в асеме тоже не знаю, но сейчас там глюк, а уже не понимаю чего делаю
Ответить с цитированием
  #40  
Старый 24.10.2012, 20:36
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Params не трогай. Его оставь как есть.
Просто для VAR переменных если обычно Params[i] := value, то теперь
Код:
var value: pointer;
...
value := GetMem(n); // тут размер типа
Integer(value^) := VAL; // VAL - передаваемое число, integer для примера
pVar[i].addr := value;
pVar[i].type :=  0; // для примера опять же, пусть 0 означает integer 
inc(i);
Params[count] = DWORD(value);
inc(count);
Примерно. А если переменная не VAR, то все как прежде.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #41  
Старый 24.10.2012, 20:45
reqyz reqyz вне форума
Начинающий
 
Регистрация: 13.02.2010
Сообщения: 104
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Params не трогай. Его оставь как есть.
Просто для VAR переменных если обычно Params[i] := value, то теперь
Код:
var value: pointer;
...
value := GetMem(n); // тут размер типа
Integer(value^) := VAL; // VAL - передаваемое число, integer для примера
pVar[i].addr := value;
pVar[i].type :=  0; // для примера опять же, пусть 0 означает integer 
inc(i);
Params[count] = DWORD(value);
inc(count);
Примерно. А если переменная не VAR, то все как прежде.
с этим ясно) а на счёт конст, я нарыл, когда такой тип вара, то посылается не значение а его копия, и с ним уже работает функция, а так как у нас посылается само значение, то функция начинает его использовать и получается ошибка, но думаю это обойти никак невозможно( и на том спасибо) завтра напишу конечную функцию с варами и аутами) спокойной ночи)
Ответить с цитированием
  #42  
Старый 25.10.2012, 00:24
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 576
Версия Delphi: 6
Репутация: выкл
По умолчанию

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

Тогда нужно уметь работать всего лишь с двумя типами значений -- строкой и числом (DWORD). LONGBOOL -- тоже DWORD. В синтаксисе inf-файлов строки обычно заключаются в кавычки, а числа передаются просто так. Можно еще 16-ричные числа обрабатывать, которые заданы как 0x########, но это уже на любителя.
Ответить с цитированием
  #43  
Старый 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.
Ответить с цитированием
  #44  
Старый 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
Для всех типов в стек кладётся адрес переменной.
Ответить с цитированием
  #45  
Старый 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-модификатором.
Ответить с цитированием
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

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

ВКонтакте   Facebook   Twitter