Mi sembra che le tre risposte finora abbiano completamente ignorato il punto della domanda. Quello, o io ho. Stai chiedendo perché Win32 Delphi non ha qualcosa come la magica funzione Supports
di cui parla l'articolo di Hallvard, vero? Vale a dire, una funzione che, dato il nome di una DLL e le informazioni sul tipo di un'interfaccia, restituisce un oggetto che implementa tale interfaccia utilizzando le funzioni indipendenti esportate dalla DLL.
Hydra sembra voler chiamare il codice .Net da un programma Win32, non l'importazione di funzioni da una DLL. TJvPluginManager
richiede che le DLL dei plug-in esportino una funzione di autoregistrazione speciale che il gestore chiamerà quando carica la DLL e la funzione deve restituire un'istanza della classe TJvPlugin
, quindi la DLL del plug-in deve essere scritta in Delphi o C++ Builder. La funzione Supports
, d'altra parte, funziona con qualsiasi DLL scritta in qualsiasi lingua. Potresti usarlo su kernel32, se lo volessi.
Non so perché Win32 Delphi non ha una cosa del genere. Forse CodeGear non ha visto molta richiesta perché Delphi e Turbo Pascal se ne erano già andati così a lungo senza.
È sicuramente possibile scrivere una funzione che funzioni in questo modo, e non mi aspetto che sarebbe più difficile scrivere di quanto la versione .Net debba essere stata, a meno che le librerie .Net di Microsoft già forniscano la maggior parte dei pezzi e Delphi li avvolge semplicemente in una funzione conveniente da chiamare che assomiglia alle diverse altre versioni sovraccaricate di che Delphi ha avuto per anni.
Ci sarebbero alcuni passaggi per l'implementazione di quella funzione in Win32. (Sto fornendo solo uno schizzo di ciò che è necessario perché in questo momento non ho una copia di Delphi in esecuzione. Chiedi gentilmente, e forse troverò maggiori dettagli.) In primo luogo, dovresti assicurarti che quel tipo informazioni per un'interfaccia contenevano, come minimo, i nomi non decorati dei suoi metodi. Quindi, Supports
dovrebbe generare una funzione stub per ogni metodo nell'interfaccia (oltre a _AddRef, _Release e QueryInterface). Lo stub sarebbe qualcosa di simile, assumendo la convenzione di chiamata stdcall
:
asm
// Pop the return address,
// discard the "this" pointer,
// and restore the return address
pop eax
pop ecx
push eax
jmp AddressOfFunction
end;
Come Supports
generato ogni stub, sarebbe riempire l'indirizzo reale funzione, ottenuto dalla chiamata GetProcAddress
con il nome del metodo corrispondente interfaccia. La convenzione di chiamata stdcall
è facile da avvolgere in questo modo; cdecl
è un po 'macchinoso; register
è un dolore al collo.
Una volta che tutti gli stub sono stati generati, avrebbe dovuto generare un "oggetto" che assomiglia all'implementazione dell'interfaccia fornita. Non deve essere una classe reale. Al momento della compilazione, Supports
non conosce il layout dell'interfaccia che verrà chiesto di implementare, quindi avere una classe non sarebbe molto utile.
Il passaggio finale è fornire implementazioni di _AddRef
, _Release
e QueryInterface
. _AddRef
sarebbe irrilevante; _Release
è dove si chiamerebbe FreeLibrary
quando il conteggio dei riferimenti ha raggiunto lo zero; QueryInterface
non farebbe molto, ad eccezione del fatto che supporta IUnknown
e l'interfaccia fornita a Supports
.
Delphi era solito venire con un programma di esempio che dimostrava l'implementazione di un'interfaccia senza alcuna classe. Tutto è stato fatto con i record e i puntatori di funzione (che in fin dei conti è un'interfaccia, dopotutto). Delphi è arrivato anche con il codice corrispondente per farlo con le classi, in parte per mostrare quanto più facile Delphi può fare le cose. Non riesco a trovare il nome del programma demo ora, ma sono sicuro che sia ancora in giro da qualche parte.
L'ho affrontato brevemente nella mia risposta. Questa è la roba da "brutto scherzo in giro con i puntatori" in cui non volevo entrare. Oh, e come bonus laterale, comporta anche brutti muck in giro in assemblea. Ho dimenticato quella parte! : P –
In realtà, non il montaggio. Codice macchina. L'assemblea che ho scritto sopra è solo a scopo illustrativo. Dovresti inserire il codice macchina direttamente perché genereresti il codice in fase di esecuzione e non è disponibile un assemblatore di runtime. –
+1, risposta ponderata e con una bella spiegazione dei dettagli tecnici. Grazie per aver trovato il tempo per scriverlo. – mghie