![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#31
|
|||
|
|||
|
с этим ясно) не понятно почему у меня ругалось, но всё же ясно, что можно и так передавать.. а почему ругается то тогда?
как в код асм добавить чтоб по разному для вар и оут?) "обнаглевший я хочет готовый пример" я сам не додумаюсь, надеюсь вас не затруднит, пожалуйста) |
|
#32
|
||||
|
||||
|
В асме ничего менять не придется. Нужно только добавить в делфовской части. А что - я уже описал.
|
|
#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
|
||||
|
||||
|
Надо читать описание функции на нормальных источниках.
Цитата:
|
| Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
reqyz (24.10.2012)
| ||
|
#35
|
||||
|
||||
|
Цитата:
|
|
#36
|
|||
|
|||
|
Цитата:
ну ладно, тут тогда разберусь) а вторая часть вопоса, где мне _par учитывать? Последний раз редактировалось reqyz, 24.10.2012 в 19:38. |
|
#37
|
|||
|
|||
|
Цитата:
|
|
#38
|
||||
|
||||
|
Цитата:
А где pVar учитывать - надо было внимательнее читать. В pVar нужно сохранять не только номер типа, но и адрес переменной этого типа, которая выделяется динамически. В массив Params класть тоже адрес VAR-овской переменной. А после вызова фунцкии проходить по массиву и выводить параметры в зависимости от типа. |
|
#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); |
|
#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-модификатором. |