Fórum Sobre ponteiros de métodos #275913
06/04/2005
0
Bruno Belchior
Curtir tópico
+ 0Posts
06/04/2005
Massuda
Gostei + 0
06/04/2005
Bruno Belchior
Gostei + 0
06/04/2005
Michael
Uma solução seria vc criar um parâmetro do tipo array do tipo Variant. Veja:
function MinhaFuncao(Matriz : array of Variant) : boolean;
(...)
O problema das Variants é que elas consomem mais recursos do que se uma variável tipada.
[]´s
Gostei + 0
06/04/2005
Bruno Belchior
Gostei + 0
06/04/2005
Beppe
procedure Oi(A, B: Integer); procedure Ola(A, B: String); ... P: Pointer; ... P := @Oi; ... P := @Ola;
O problema que se vc não souber exatamente a assinatura(parâmetros e seus tipos) da rotina, não poderá chamar via ponteiro.
Gostei + 0
07/04/2005
Yallebr
Ou seja o método que passarei como ponteiro esta em uma classe, porém será outra classe quem vai executá-lo...
Gostei + 0
07/04/2005
Beppe
Isto é simples, dado que um método é apenas uma rotina com um parâmetro implícito. Por exemplo, os dois métodos são exatamente iguais quanto à síntese:
procedure Button1Click(Self: TForm1; Sender: TObject); begin ShowClass(Self); ShowClass(Sender); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowClass(Self); ShowClass(Sender); end;
Mas para chamar um método vc precisa mais do que apenas um ponteiro, precisa também do objeto sobre o qual o método agirá. Para isso, use TMethod.
var M: TMethod; begin M.Code := @TForm1.Button1Click; M.Data := Form1; TNotifyEvent(M)(Sender); end;
Ou ainda
type T2P = procedure(Self: TForm1; Sender: TObject); var P: Pointer; begin P := @TForm1.Button1Click; T2P(P)(Form1, Sender); end;
As duas formas se equivalem, a diferença está no trato de Self(como método ou simples subrotina).
Gostei + 0
07/04/2005
Nildo
function SuaFuncao: Integer; stdcall; var _ESP: Pointer; Param1: Integer; Param2: Integer; begin asm mov _ESP, ESP end; Param1 := PInteger( Integer( _ESP ) + ( 12 * 4 ) )^; Param2 := PInteger( Integer( _ESP ) + ( 11 * 4 ) )^; ShowMessage( IntToStr( Param1 ) ); ShowMessage( IntToStr( Param2 ) ); end;
E para testar, chame-a da seguinte maneira:
procedure TForm1.Button1Click(Sender: TObject); begin asm push eax push 1 push 2 call SuaFuncao pop eax pop eax pop eax end; end;
Partindo deste princípio você pode criar um parametro que seria a contagem dos parametros, daí você faz um FOR e sai lendo os itens da Stack. É complicado isso, nem é muito legal usar, mas foi só para mostrar que é possível :wink:
Gostei + 0
07/04/2005
Beppe
Gostei + 0
07/04/2005
Massuda
Se for para programar dessa forma, estaríamos retrocedendo para os tempos onde todas as variáveis tinham que ser globais e subrotinas não podiam receber parametros (algo como retornar aos anos 60?).
Gostei + 0
07/04/2005
Nildo
Por isso eu disse que nem vale a pena. Então, eu também achei que seria 3*4, mas quando eu testei deu erro, dai eu debugei pela CPU e ví que na Stack, o Delphi acrescentou uns 8 itens.. Dai pra funcionar (é sempre especifico de função para função) eu peguei o 11º e 12º item da Stack. Pode testar e você vai ver que funciona.
mas eu estranhei o Delphi ter PUSHado um monte de coisa numa função simples... mas fazer o que né! rs
Gostei + 0
07/04/2005
Beppe
Gostei + 0
07/04/2005
Nildo
É realmente um pesadelo, principalmente quando você tem que aplicar um patch na Stack por conta de um erro estranho na compilação. Mas enfim, depois que você começa a estudar a estrutura do processador você tira isso de letra
Isso sim eu chamo de [b:022f8d5df1]Programar[/b:022f8d5df1]! Eu gosto disso porque acabo aprendendo a base da coisa.. Como ela funciona internamente.. O que o processador faz quando executa nossos códigos, etc..
Gostei + 0
07/04/2005
Beppe
Nem precisa testar...estou vendo agora o IntToStr, que cria strings. Se não fossem por eles, neste caso, os offsets seriam os óbvios.
Gostei + 0
07/04/2005
Thiago Vidal
O motivo de o Delphi PUSHar tantos itens no stack, é pq o Delphi passa os parâmetros padrão ´register´ via registradores; para passar via stack, vc deve declarar o método como ´stdcall´. Como por Exemplo:
na Dll:
type PSQLConnection = ^TSQLConnection; function Abrir(cnn: PSQLConnection): LongBool; stdcall; begin with TForm1.Create(Application) do try SQLDataSet1.Connection := cnn; Result := (ShowModal = mrOk); finally Free; end; end;
no Executável:
procedure TForm1.Button1Click(Sender: TObject); type PSQLConnection = ^TSQLConnection; var DLLHandle: THandle; cnn: PSQLConnection; Metodo: Pointer; Resultado: LongBool; begin DLLHandle := LoadLibrary(´minhadll.dll´); if (DLLHandle <> 0) then try cnn := @SQLConnection1; Metodo := GetProcAddress(DLLHandle, ´Abrir´); asm push cnn call Metodo mov [Resultado], eax end; if (Resultado) then ShowMessage(´Sucesso!´); finally FreeLibrary(DLLHandle); end; end;
Realmente não é a forma mais recomendada de se fazer as coisas, mas funciona, e para um sistema como o meu, em que um executável enxuto carrega diversas DLLs, é importante manter apenas 1 conexão com o banco ativa... desde que se faça um rigoroso controle, para evitar que as DLLs tentem acessar a conexão simultaneamente.
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)