|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#16
|
||||
|
||||
Цитата:
Ошибка у тебя скорее всего вот здесь: Цитата:
|
#17
|
|||
|
|||
у меня в примере незакомментированном даже не используется возможность с чар, не в этом дело(
|
#18
|
||||
|
||||
Цитата:
Цитата:
Цитата:
Есть правда вариант, что в ассемблерном куске ошибка. Например навскидку из справки по Delphi по поводу директивы asm: Цитата:
|
#19
|
||||
|
||||
Цитата:
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#20
|
||||
|
||||
Цитата:
ТС: в крайнем случае в начале можно сделать push используемых регистров, а в конце - pop. Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 23.10.2012 в 21:23. |
#21
|
||||
|
||||
Хоть практическая польза от этой "волшебной" функции довольно сомнительна, но интерес меня всё же пересилил.
Ошибки были и в том месте что я указывал выше, и в ассемблерной вставке, и даже в вызывающей строке. Кроме того я привёл эту функцию к более приличному виду, в результате получилось так: Код:
procedure RaiseErrorFmt(const Msg: String; const Args: array of const); begin raise Exception.CreateFmt(Msg, Args); end; function SetFunction(dll, adress, param: String): DWORD; var hdll: HMODULE; LastError: DWORD; proc: Pointer; Params: array of DWORD; Strings: array of String; PrmCount, StrCount, p: Integer; p1, p2: String; //param = integer:8;boolean:true; ... begin hdll := LoadLibrary(Pointer(dll)); if hdll = 0 then begin LastError := GetLastError; RaiseErrorFmt('При загрузке библиотеки "%s" возникла ошибка №%d: "%s"', [dll, LastError, SysErrorMessage(LastError)]); end; try proc := GetProcAddress(hdll, Pointer(adress)); if not Assigned(proc) then RaiseErrorFmt('В библиотеке "%s" отсутствует процедура "%s"', [dll, adress]); PrmCount := 0; StrCount := 0; while param <> '' do begin 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 SetLength(Params, PrmCount + 10); if p1 = 'integer' then begin Params[PrmCount] := StrToInt(p2); end else if p1 = 'boolean' then begin Params[PrmCount] := StrToInt(p2); end else if p1 = 'pchar' then begin // Здесь строки нигде не сохранялись, поэтому указатели на них теряли актуальность if Length(Strings) = StrCount then SetLength(Strings, StrCount + 10); Strings[StrCount] := p2; Params[PrmCount] := DWORD(Strings[StrCount]); Inc(StrCount); end else begin RaiseErrorFmt('Неподдерживаемый тип "%s"', [p1]); end; 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; finally FreeLibrary(hdll); end; end; // Пример вызова (в исходном варианте здесь была ошибка): procedure TForm1.Button1Click(Sender: TObject); begin SetFunction('shell32.dll', 'ShellExecuteA', 'Integer:0;PChar:;PChar:calc.exe;PChar:;PChar:;Integer:0;'); end; |
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
reqyz (24.10.2012)
|
#22
|
|||
|
|||
потестю) уверен в 100% что всё правильно) примного благодарен)
|
#23
|
|||
|
|||
уважаемый poli-smen важный вопрос, уже не удобно о чём либо просить, но всё же, а возможно как либо указывать такие параметры переменных как вар конст и аут?)
|
#24
|
||||
|
||||
Цитата:
|
#25
|
|||
|
|||
Цитата:
я представляю как в этой функции получать результаты, но я не знаю совсем ассемблер и не знаю что писать там. как я представляю: Код:
function SetFunction(dll, adress, param: String;out res2:string): LongWord; var hdll: HMODULE; LastError: LongWord; proc: Pointer; Params: array of LongWord; _par:array of byte;//0 1 2 3 Strings: array of String; PrmCount, StrCount, p: Integer; p0, p1, p2: String; //param =var integer:const 8;boolean:1;out char:reqyz; integer:8; ...//например begin hdll := LoadLibrary(Pointer(dll)); if hdll = 0 then begin LastError := GetLastError; RaiseErrorFmt('При загрузке библиотеки "%s" возникла ошибка №%d: "%s"', [dll, LastError, SysErrorMessage(LastError)]); end; try proc := GetProcAddress(hdll, Pointer(adress)); if not Assigned(proc) then RaiseErrorFmt('В библиотеке "%s" отсутствует процедура "%s"', [dll, adress]); PrmCount := 0; StrCount := 0; 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]); if p1 = 'integer' then Params[PrmCount] := StrToInt(p2) else if p1 = 'boolean' then Params[PrmCount] := StrToInt(p2) else if p1 = 'pchar' then begin // Здесь строки нигде не сохранялись, поэтому указатели на них теряли актуальность if Length(Strings) = StrCount then SetLength(Strings, StrCount + 10); Strings[StrCount] := p2; Params[PrmCount] := DWORD(Strings[StrCount]); Inc(StrCount); end else begin RaiseErrorFmt('Неподдерживаемый тип "%s"', [p1]); end; 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]=1)or(_par[p]=3) then res2:=res2+inttostr(p)+':'+inttostr(Params[p])+';'; finally FreeLibrary(hdll); end; end; нарыл вот это Передача параметров по значению говорится о const? Процедуре передается собственно значение параметра. При этом фактически значение параметра копируется, и процедура использует его копию, так что модификация исходного параметра оказывается невозможной. Этот механизм применяется для передачи небольших параметров, таких как байты или слова. Например, если параметры передаются в регистрах: Код:
mov ax,word ptr value ; сделать копию значения call procedure ; вызвать процедуру Процедуре передается не значение переменной, а ее адрес, по которому процедура должна сама прочитать значение параметра. Этот механизм удобен для передачи больших массивов данных и для тех случаев, когда процедура должна модифицировать параметры, хотя он и медленнее из-за того, что процедура будет выполнять дополнительные действия для получения значений параметров. Код:
mov ax,offset value call procedure Этот механизм объединяет передачу по значению и по ссылке. Процедуре передают адрес переменной, а процедура делает локальную копию параметра, затем работает с ней, а в конце записывает локальную копию обратно по переданному адресу. Этот метод эффективнее обычной передачи параметров по ссылке в тех случаях, когда процедура должна обращаться к параметру достаточно большое число раз, например, если используется передача параметров в глобальной переменной: Код:
mov global_variable,offset value call procedure [...] procedure proc near mov dx,global_variable mov ax,word ptr [dx] (команды, работающие с АХ в цикле десятки тысяч раз) mov word ptr [dx],ax procedure endp из этой статьи но я не знаю как это применить, так как в ассеме полный нуб помогите плиз, чуток осталось Последний раз редактировалось reqyz, 24.10.2012 в 13:56. |
#26
|
||||
|
||||
Цитата:
Следовательно, можно сделать "префикс" типа VAR, который будет означать, что программа выделит память, скопирует туда значение и передаст в функцию адрес переменной. Соответственно если составить отдельно массив записей о таких параметрах (например в формате <адрес><тип>), то и вывести их потом не составит труда. А вот то, что lea не дает идти в минус я забыл. jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 24.10.2012 в 17:06. |
#27
|
|||
|
|||
можете подравить мой пример под вар?) и насчёт конст и оут неужели невозможно, та статья не правильная?)
|
#28
|
||||
|
||||
Конст - это фактически просто директива для компилятора, которая проверит твой код за тебя, чтобы ты случайно не мог изменить параметр. После компиляции const и обычный параметр не будут отличаться.
С аут та же история. Ну а подправить код - надо ему еще объявить префикс var. То есть он будет искать как сейчас до :, а потом будет смотреть, нету ли в типе пробела. Если есть пробел - то выдирает то, что до него и сравнивает с var. Если равно var - выделяет место для значения, сохраняет его адрес в массиве записей и в Params, затем сохраняет тип для дальнейшей обработки. Записи можно сделать вида <addr><typeID>, как я уже говорил. После вызова вывод всех параметров из этого массива. jmp $ ; Happy End! The Cake Is A Lie. |
#29
|
|||
|
|||
Цитата:
да в функции я это сделал, я не знаю как правильно в ассем это добавить и на счёт конст, если в функции, например Код:
function SHFileOperation(const lpFileOp: _SHFILEOPSTRUCTA): Integer; stdcall; external shell32 name 'SHFileOperationA'; Последний раз редактировалось reqyz, 24.10.2012 в 17:28. |
#30
|
||||
|
||||
Смотря как использовать.
Код:
function Func1(const p: PAnsiChar): Integer; stdcall; begin MessageBoxA(0,p,0,0); end; function Func2(p: PAnsiChar): Integer; stdcall; begin MessageBoxA(0,p,0,0); end; ; --------------------------------------------------------- Project1.dpr.13: begin 00418F0C 55 push ebp 00418F0D 8BEC mov ebp,esp 00418F0F 51 push ecx Project1.dpr.14: MessageBoxA(0,p,0,0); 00418F10 6A00 push $00 00418F12 6A00 push $00 00418F14 8B4508 mov eax,[ebp+$08] 00418F17 50 push eax 00418F18 6A00 push $00 00418F1A E875F8FEFF call MessageBoxA Project1.dpr.15: end; 00418F1F 8B45FC mov eax,[ebp-$04] 00418F22 59 pop ecx 00418F23 5D pop ebp 00418F24 C20400 ret $0004 ; -------------------------------------------------------- Project1.dpr.17: begin 00418F28 55 push ebp 00418F29 8BEC mov ebp,esp 00418F2B 51 push ecx Project1.dpr.18: MessageBoxA(0,p,0,0); 00418F2C 6A00 push $00 00418F2E 6A00 push $00 00418F30 8B4508 mov eax,[ebp+$08] 00418F33 50 push eax 00418F34 6A00 push $00 00418F36 E859F8FEFF call MessageBoxA Project1.dpr.19: end; 00418F3B 8B45FC mov eax,[ebp-$04] 00418F3E 59 pop ecx 00418F3F 5D pop ebp 00418F40 C20400 ret $0004 А вот пример номер два: Код:
function Func1(var p: AnsiString): Integer; stdcall; begin MessageBoxA(0,PAnsiChar(p),0,0); end; function Func2(p: AnsiString): Integer; stdcall; begin MessageBoxA(0,PAnsiChar(p),0,0); end; ; ---------------------------------------------------------- Project1.dpr.13: begin 00418F1C 55 push ebp 00418F1D 8BEC mov ebp,esp 00418F1F 51 push ecx Project1.dpr.14: MessageBoxA(0,PAnsiChar(p),0,0); 00418F20 6A00 push $00 00418F22 6A00 push $00 00418F24 8B4508 mov eax,[ebp+$08] // Берем параметр 00418F27 8B00 mov eax,[eax] // <------- Вот оно! 00418F29 E872CAFEFF call @LStrToPChar 00418F2E 50 push eax 00418F2F 6A00 push $00 00418F31 E86EF8FEFF call MessageBoxA Project1.dpr.15: end; 00418F36 8B45FC mov eax,[ebp-$04] 00418F39 59 pop ecx 00418F3A 5D pop ebp 00418F3B C20400 ret $0004 00418F3E 8BC0 mov eax,eax ; ---------------------------------------------------------- Project1.dpr.17: begin 00418F40 55 push ebp 00418F41 8BEC mov ebp,esp 00418F43 51 push ecx 00418F44 8B4508 mov eax,[ebp+$08] // берем параметр 00418F47 E890C6FEFF call @LStrAddRef // не обращаем внимания, это inc количества текущих ссылок на строку, делается для защиты многопоточности 00418F4C 33C0 xor eax,eax 00418F4E 55 push ebp 00418F4F 68848F4100 push $00418f84 00418F54 64FF30 push dword ptr fs:[eax] // Для хендла исключений 00418F57 648920 mov fs:[eax],esp Project1.dpr.18: MessageBoxA(0,PAnsiChar(p),0,0); 00418F5A 6A00 push $00 00418F5C 6A00 push $00 00418F5E 8B4508 mov eax,[ebp+$08] // снова берем параметр 00418F61 E83ACAFEFF call @LStrToPChar // перевод в PChar (фактически return eax) 00418F66 50 push eax 00418F67 6A00 push $00 00418F69 E836F8FEFF call MessageBoxA Project1.dpr.19: end; 00418F6E 33C0 xor eax,eax 00418F70 5A pop edx 00418F71 59 pop ecx 00418F72 59 pop ecx 00418F73 648910 mov fs:[eax],edx // Восстанавливаем все 00418F76 688B8F4100 push $00418f8b 00418F7B 8D4508 lea eax,[ebp+$08] 00418F7E E889C5FEFF call @LStrClr // снимаем ссылку на строку 00418F83 C3 ret 00418F84 E977BCFEFF jmp @HandleFinally 00418F89 EBF0 jmp $00418f7b 00418F8B 8B45FC mov eax,[ebp-$04] 00418F8E 59 pop ecx 00418F8F 5D pop ebp 00418F90 C20400 ret $0004 Видно, что первая делает mov eax, [eax]. Что означает взять значение по указателю. То есть ей передался указатель на строку s (скорее даже "указатель на указатель на строку"). jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 24.10.2012 в 17:57. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
reqyz (24.10.2012)
|