![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#31
|
|||
|
|||
![]() с этим ясно) не понятно почему у меня ругалось, но всё же ясно, что можно и так передавать.. а почему ругается то тогда?
как в код асм добавить чтоб по разному для вар и оут?) "обнаглевший я хочет готовый пример" я сам не додумаюсь, надеюсь вас не затруднит, пожалуйста) |
#32
|
||||
|
||||
![]() В асме ничего менять не придется. Нужно только добавить в делфовской части. А что - я уже описал.
jmp $ ; Happy End! The Cake Is A Lie. |
#33
|
|||
|
|||
![]() Код:
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
|
||||
|
||||
![]() Надо читать описание функции на нормальных источниках.
Цитата:
jmp $ ; Happy End! The Cake Is A Lie. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
reqyz (24.10.2012)
|
#35
|
||||
|
||||
![]() Цитата:
|
#36
|
|||
|
|||
![]() Цитата:
ну ладно, тут тогда разберусь) а вторая часть вопоса, где мне _par учитывать? Последний раз редактировалось reqyz, 24.10.2012 в 19:38. |
#37
|
|||
|
|||
![]() Цитата:
|
#38
|
||||
|
||||
![]() Цитата:
А где pVar учитывать - надо было внимательнее читать. В pVar нужно сохранять не только номер типа, но и адрес переменной этого типа, которая выделяется динамически. В массив Params класть тоже адрес VAR-овской переменной. А после вызова фунцкии проходить по массиву и выводить параметры в зависимости от типа. jmp $ ; Happy End! The Cake Is A Lie. |
#39
|
|||
|
|||
![]() Цитата:
я ничего не понял, поэтому сделал как понял( Код:
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
|
||||
|
||||
![]() 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); jmp $ ; Happy End! The Cake Is A Lie. |
#41
|
|||
|
|||
![]() Цитата:
|
#42
|
||||
|
||||
![]() Цитата:
Тогда нужно уметь работать всего лишь с двумя типами значений -- строкой и числом (DWORD). LONGBOOL -- тоже DWORD. В синтаксисе inf-файлов строки обычно заключаются в кавычки, а числа передаются просто так. Можно еще 16-ричные числа обрабатывать, которые заданы как 0x########, но это уже на любителя. |
#43
|
|||
|
|||
![]() Цитата:
реализовал функцию, всё кроме конст работает) вары возвращает) всё работает прекрассно) вот сама функция: Код:
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
|
|||
|
|||
![]() для общего развития неплохо бы прочитать
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
|
|||
|
|||
![]() в догонку
Возвращаемое значение boolean, char, byte, shortint - возвращаются в регистре AL word и smallint - возвращаются в регистре AX В Win-API накой способ не используется. Как правило возвращается целиком регистр EAX. LongInt,DWORD, а так же всякие Pointer`ы- возвращаются в регистре EAX. Int64 - возвращаются в регистрах EAX:EDX. Record - вызывающая программа должна подготовить место для record`а, и передать его адрес в качестве неявного параметра, расположеного после всех явных параметров. Вызываемая процедура работает с этим параметром как с параметром с out-модификатором. |