2010-07-01 14 views
9

In Delphi, come individuare l'indirizzo di un metodo COM? posso hardcode gli offsetCompensazioni metodo COM in Delphi

//0 is the offset of the QueryInterface method 
p := TPonterArray(pointer(SomeInterface)^)[0]; 

ma io preferirei usare nomi simbolici. Il folllowing ovviamente non funziona:

var M : TMethod; 
... 
M := TMethod(SomeInterface.QueryInterface); 

Grazie!

+3

Delphi porta via un sacco di tutti i dettagli cruenti COM, penso che si vuole fare un po 'troppo da soli. Cosa stai cercando di ottenere? Crea il tuo server COM o ne usi uno esistente? –

+0

Vuoi lo spostamento numerico del metodo nell'interfaccia (ad esempio IUnknown.QueryInterface è 0), l'indirizzo del metodo nella classe che implementa tale metodo di interfaccia (ad esempio, @ TInterfacedObject.QueryInterface) o l'indirizzo del metodo codice stub generato per collegare una chiamata all'interfaccia al metodo dell'oggetto corrispondente? Quest'ultimo è memorizzato nella tabella di interfaccia della classe. –

+0

@The_Fox: Nessuno dei due: intercetto le chiamate a un oggetto COM esterno utilizzando Win32Hook.pas. @Rob Kennedy: non esiste una classe TInterfacedObject - ho solo un'interfaccia implementata da una DLL esterna. –

risposta

3

Non credo che Delphi lo sostenga. L'hardcoding degli offset è probabilmente l'unica cosa che funzionerà, dal momento che il compilatore non conta i metodi di interfaccia come simboli il cui valore può essere assegnato a un puntatore di funzione, come possono fare i metodi oggetto o le funzioni standalone.

Perché stai cercando di farlo, a proposito?

+1

Sto intercettando le chiamate a un oggetto COM esterno utilizzando Win32Hook.pas - solo una funzionalità di registrazione per il mio OutlookSpy (http://www.dimastr.com/outspy/) –

+1

BTW, il compilatore Delphi ovviamente conosce gli offset del metodo, io sono solo cercando di trovare un modo per fare lo stesso invece di utilizzare offset hardcoded. –

+0

Sì, il compilatore lo sa, ma per quanto posso dire, non c'è modo di farlo direttamente. –

6

È possibile utilizzare la direttiva assemblatore vmtoffset per ottenere l'offset di byte di un metodo di interfaccia relativo all'inizio della tabella dei metodi dell'interfaccia. Date un'occhiata a l'attuazione di _IntfCast in System.pas, ad esempio:

call dword ptr [eax] + vmtoffset IInterface.QueryInterface 
... 
call dword ptr [eax] + vmtoffset IInterface._Release 

La prima espressione aggiunge 0; il secondo, 8.

Tuttavia, non è possibile parametrizzare tali espressioni. Sono costanti in fase di compilazione, quindi non è possibile scegliere quale metodo si desidera in fase di esecuzione. È necessario avere tutti i possibili nomi dei metodi rappresentati in anticipo.

Tutto quello che in realtà deve agganciare è QueryInterface. Una volta ottenuto ciò, è possibile restituire qualsiasi oggetto proxy desiderato che possa intercettare le chiamate a tutti gli altri metodi.

+0

Sembra promettente ... Ci proverò più tardi oggi e pubblicherò i risultati. Grazie! –

2

Il codice è errato perché un riferimento all'interfaccia non è un puntatore a una tabella dei metodi di interfaccia ma un puntatore al puntatore a una tabella del metodo di interfaccia. È così che le interfacce Delphi sono implementate a livello binario. È difficile dire di più e segnalare l'errore nel codice perché non è stato fornito un esempio di codice che può essere compilato. Utilizzare il seguente codice per la conversione di riferimento interfaccia per puntatore metodo correttamente, l'idea è stata presa da Barry Kelly's demonstration of creating a method pointer from a method reference:

procedure IntRefToMethPtr(const IntRef; var MethPtr; MethNo: Integer); 
type 
    TVtable = array[0..999] of Pointer; 
    PVtable = ^TVtable; 
    PPVtable = ^PVtable; 
begin 
    // QI=0, AddRef=1, Release=2, etc 
    TMethod(MethPtr).Code := PPVtable(IntRef)^^[MethNo]; 
    TMethod(MethPtr).Data := Pointer(IntRef); 
end; 

Se si preferisce nomi simbolici per MethNo si sono meglio di dichiarare da soli come costanti di offset

+0

No, una variabile di interfaccia in Delphi è un puntatore a una tabella v. –

+0

No, Dmitry, Serg ha ragione. Una variabile di interfaccia non può essere solo un puntatore a un vtable. Tutte le istanze della classe condividono un singolo vtable, proprio come le classi non-interface. Considera C++, in cui non vi è alcuna differenza tra interfacce e classi ordinarie. Un puntatore a oggetti non è solo un puntatore vtable, quindi nessuno dei due è un puntatore a interfaccia. –

+0

@Rob Kennedy: grazie, la domanda mi ha costretto a scrivere un post sul blog sulle interfacce Delphi: http://sergworks.wordpress.com/2010/07/06/delphi-interfaces-on-binary-level/ – kludg

1

Due direttive aggiuntive consentono al codice assembly di accedere ai metodi virtuali dinamici e : VMTOFFSET e DMTINDEX.

VMTOFFSET recupera l'offset in byte della tabella voce metodo puntatore virtuale dell'argomento metodo virtuale dall'inizio della tabella metodo virtuale (VMT). Questa direttiva richiede un nome di classe completo con un nome di metodo come parametro (ad esempio, TExample.VirtualMethod) o un nome di interfaccia e un metodo di interfaccia .

DMTINDEX recupera l'indice della tabella del metodo dinamico del metodo dinamico passato .Questa direttiva richiede anche un nome classe completo specificato con un nome di metodo come parametro, ad esempio, TExample.DynamicMethod. Per richiamare il metodo dinamico, chiamare il sistema . @ CallDynaInst con il registro (E) SI contenente il valore ottenuto da DMTINDEX.

docwiki.embarcadero.com

Ecco il codice per ottenere il puntatore del metodo necessario

function GetMethodPointer(const IntRef: IInterface): Pointer; assembler; 
asm 
    mov eax, [IntRef] 
    add eax, vmtoffset ISomeInterface.MemberMethod 
    mov eax, [eax] 
end;