2009-07-07 8 views
6

Utilizzo Delphi per creare un componente aggiuntivo XLL per Excel, che comporta l'esecuzione di molte chiamate alla funzione Excel4v di xlcall32.dll. Tuttavia, dato che immagino che pochissimi esperti di Delphi abbiano lavorato con quell'API specifica, spero che il problema possa essere stato osservato anche in altre API.Chiamare specifiche API Win32 da Delphi - Perché le eccezioni volano senza "asm pop ..."?

In C, in particolare nel file xlcall.h che viene fornito con il Microsoft Excel 2007 XLL SDK, Excel4v è definito come:

int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]); 

In Delphi sto usando:

function Excel4v(xlfn: Integer; operRes: LPXLOPER; count: Integer; 
    opers: array of LPXLOPER): Integer; stdcall; external 'xlcall32.dll'; 

LPXLOPER è un puntatore in una struct (in C) o in un record (in Delphi).

Ho fatto i compiti per dichiarare le funzioni C in Delphi (this excellent article è stato di grande aiuto), e penso di dichiarare Excel4v correttamente. Tuttavia, le chiamate dal codice Delphi in quella funzione causa eccezioni ("violazione di accesso ..." è quello che continuo a vedere) a meno sono seguiti dalla seguente riga:

asm pop sink; end; 

Dove "Sink" è definito da qualche parte come un numero intero

Non ho la minima idea dell'assemblaggio ... Quindi non avrei mai pensato di provare a correggere le eccezioni con "asm pop sink; end;". Ma "asm pop sink, end;" risolve davvero le eccezioni. L'ho visto per la prima volta in this useful article on making XLLs using Delphi. Ecco la citazione più rilevanti:..

"Dal Delphi grande ostacolo con componenti aggiuntivi è il parametro più dopo l'indirizzo di ritorno sullo stack questo viene fornito gratuitamente con ogni chiamata a Excel I' Non ho mai scoperto cosa detiene lo , ma a patto che tu passi via il , il tuo componente aggiuntivo funzionerà bene Aggiungi la variabile asm pop linea, fine; dopo ogni chiamata dove la variabile può essere qualsiasi globale, locale o variabile oggetto che è almeno 4 byte l'intero numero intero è . Per ripetere- QUESTO DEVE ESSERE INCLUSO dopo ogni chiamata a Excel4v. Altrimenti si sta costruendo una bomba a orologeria. "

Fondamentalmente voglio capire cosa sta realmente accadendo, e perché. Quello che potrebbe essere la causa di una funzione Win32 per restituire un" parametro in più, dopo l'indirizzo di ritorno sulla stack "e cosa che in realtà significa?

Potrebbe esserci un altro modo per risolvere questo problema, ad esempio con una diversa opzione di compilatore o un diverso modo di dichiarare la funzione di?

e c'è qualcosa di rischioso a chiamare" asm pop sink; fine: "dopo ogni chiamata a Excel4v ...? Sembra funzionare bene, ma, poiché non capisco cosa sta succedendo, sembra un po 'pericoloso ...

+0

Sto scrivendo un XLL in Delphi e mi piacerebbe metterti in contatto con te. Inviami un'email a [email protected] – garethm

risposta

8

Non credo che sia Pascal vs stdcall - sono convenzioni di chiamata molto simili e non dovrebbero risultare in uno stack non corrispondente all'uscita dalla funzione.

Dalla riferimento article,

Questo sarebbe davvero un bel sintassi, ma non è lo stesso del sopra definizione di matrice. I parametri dell'array-of sono parametri di array aperti. Possono apparire come qualsiasi array e accettano qualsiasi array, ma ottengono un parametro aggiuntivo (nascosto) , che detiene l'indice più alto nella matrice (il valore alto ). Poiché questo è solo così in Delphi, e non in C o C++, avresti un problema reale con lo . (Vedere anche il mio articolo su array aperti), dal momento che il numero reale di parametri non corrisponderebbe a .

Stai ottenendo il parametro extra "indice di array più alto" passato alla funzione. Questo è un int e deve essere ripulito quando la funzione termina in modo da non finire con uno stack corrotto e crash. L'articolo indica come passare gli array alle funzioni C.

Qualcosa di simile:

type 
PLPXLOPER = ^LPXLOPER; 

e superare PLPXLOPER come ultimo parametro.

+0

Grazie Michael, sembra la spiegazione per me :) I'll giocare un po 'con esso per essere sicuro e commentare di nuovo quando sono. –

+0

Fantastico! Per quanto posso dire, funziona perfettamente. Definire la funzione come function Excel4v (xlfn: Integer; operRes: LPXLOPER; numero: Integer; opers: PLPXLOPER): Intero; stdcall; 'xlcall32.dll' esterno; quindi chiamarlo, creare un array Delphi di LPXLOPER e chiamare Excel4v con @myArray [0] per PLPXLOPER. Funziona alla grande, con stdcall e senza bisogno di chiamate pop asmatiche dall'aspetto sospetto :) –

0

La convenzione di chiamata è errata, in particolare "stdcall".La dichiarazione C è specificata come "pascal"

Stdcall passa i parametri nell'ordine da destra a sinistra, prevede la pulizia della routine e non utilizza registri. Pascal, OTOH passa i parametri nell'ordine da sinistra a destra. Pertanto, le cose non stanno accadendo nel modo in cui l'altra metà del codice si aspetta in entrambi i casi.

Modifica la tua dichiarazione Delphi per essere "pascal" invece di "stdcall".

+0

Ho provato a specificarlo come pascal, ma non sono riuscito a ricevere alcuna chiamata per farlo funzionare. Ma la funzione sicuramente funziona correttamente con stdcall, purché sia ​​seguita dalla riga "asm pop ...". L'articolo su http://rvelthuis.de/articles/articles-convert.html menziona Pascal con un significato controintuitivo sebbene non sia poi così specifico. –

+0

Prima erano convenzioni di chiamata diverse. Al giorno d'oggi, "pascal" è una macro che significa "stdcall" nelle intestazioni C. –

+0

Ho visto PASCAL # define'd anche su __stdcall. . . ma non sono sicuro di cosa significhi rispetto al delphi. Il mio pensiero originale non corrispondeva alla convenzione, ma per una funzione come questa lo stack non sarebbe stato disattivato solo di 4 byte tra le convenzioni call-save e callee-save. – Michael

Problemi correlati