2009-07-07 8 views
6

Estoy usando Delphi para hacer un complemento XLL para Excel, que implica hacer muchas llamadas a la función Excel4v de xlcall32.dll. Sin embargo, como supongo que muy pocos expertos de Delphi han trabajado con esa API específica, espero que el problema también se haya observado en otras API.Llamando a la API Win32 específica de Delphi: ¿Por qué vuelan las excepciones sin un "asm pop ..."?

En C, específicamente en el archivo xlcall.h que viene con el Microsoft Excel 2007 XLL SDK, Excel4v se define como:

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

En Delphi que estoy usando:

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

LPXLOPER es un puntero a una estructura (en C) o registro (en Delphi).

He estado haciendo mi tarea al declarar funciones C en Delphi (this excellent article fue de gran ayuda), y creo que estoy declarando Excel4v correctamente. Sin embargo, las llamadas de código de Delphi en que la función de causa excepciones ("violación de acceso ..." es lo que sigo viendo) a menos que se siguen por la línea siguiente:

asm pop sink; end; 

Donde "sumidero" se define en alguna parte como un entero.

No tengo ni idea sobre el ensamblaje ... Así que no hay forma de que haya pensado en intentar arreglar las excepciones con "asm pop sink; end;". Pero "asm pop sink; end;" de hecho arregla las excepciones. La vi por primera vez en this useful article on making XLLs using Delphi. Aquí está la cita más relevante:..

"A partir de Delphi el gran obstáculo con complementos es el parámetro extra después de que la dirección de retorno en la pila Esto viene gratis con cada llamada a Excel I' Nunca he descubierto lo que tiene, pero siempre que lo arroje de distancia, su complemento funcionará bien. Agregue la línea asm pop variable, final; después de cada llamada donde la variable puede ser cualquier global, local o la variable de objeto que tiene al menos 4 bytes de longitud, el entero es , está bien. Para repetir, ESTO DEBE SER INCLUIDO después de cada llamada a Excel4v. De lo contrario usted está construyendo una bomba de tiempo. "

Básicamente Quiero entender lo que está sucediendo realmente, y por qué. ¿Cuál podría ser la causa de una función de Win32 para devolver un" parámetro extra después de la dirección del remitente en el apilar "y lo que significa realmente?

Podría haber otra manera de solucionar este problema, por ejemplo, con una opción de compilador diferente o una forma diferente de la que se declara la función?

y hay algo arriesgado en llamar" receptor de pop asm; final; "después de cada llamada a Excel4v ...? Parece funcionar bien, pero, como no entiendo lo que está pasando, se siente un poco peligroso ...

+0

Escribo un XLL en Delphi y me gustaría ponerme en contacto con usted. Por favor envíeme un correo electrónico a [email protected] – garethm

Respuesta

8

No creo que sea pascal vs stdcall: son convenciones de llamadas muy similares y no deberían dar como resultado una pila no coincidente al salir de la función.

De la referencia article,

Este hecho, sería una muy buena sintaxis , pero no es el mismo que el anterior definición de la matriz. Los parámetros de matriz de son parámetros de matriz abierta. Pueden parecerse a cualquier matriz, y aceptan cualquier matriz, pero obtienen un parámetro adicional (oculto), que contiene el índice más alto en la matriz (el valor alto ). Como esto solo ocurre en Delphi, y no en C o C++, tendría un problema real. (Consulte también mi artículo sobre matrices abiertas), ya que el número real de parámetros no coincidiría con .

Obtiene el parámetro "índice de matriz más alto" que se pasa a la función. Esto es un int y tiene que ser limpiado cuando la función sale para que no termines con una pila dañada y se cuelgue. El artículo indica cómo pasar matrices a las funciones C.

Algo así como:

type 
PLPXLOPER = ^LPXLOPER; 

y pasar PLPXLOPER como el último parámetro.

+0

Gracias Michael, eso me suena a la explicación :) Lo haré jugar un poco con eso un poco para estar seguro y comentar de nuevo cuando lo haga. –

+0

¡Fantástico! Por lo que puedo decir, está funcionando perfectamente. Defina la función como función Excel4v (xlfn: Integer; operRes: LPXLOPER; count: Integer; opers: PLPXLOPER): Integer; stdcall; externo 'xlcall32.dll'; y luego llamarlo, hacer una matriz Delphi de LPXLOPER, y llamar a Excel4v con @myArray [0] para PLPXLOPER. Funciona muy bien, con stdcall, y no hay necesidad de llamadas asm pop sospechosas :) –

0

Su convenio de llamada es incorrecto, específicamente el "stdcall".La declaración C se especifica como "pascal"

Stdcall pasa los parámetros en orden de derecha a izquierda, espera que la rutina se limpie y no usa registros. Pascal, OTOH pasa parámetros en de izquierda a derecha orden. Por lo tanto, las cosas no están sucediendo como espera la otra mitad del código en ambos casos.

Cambie su declaración de Delphi para que también sea "pascal" en lugar de "stdcall".

+0

Intenté especificarlo como pascal, pero no pude recibir llamadas para que funcione. Pero la función definitivamente funciona correctamente con stdcall, siempre que se siga con la línea "asm pop ...". El artículo en http://rvelthuis.de/articles/articles-convert.html menciona que Pascal tiene un significado contrario a la intuición, aunque no es tan específico. –

+0

Solían ser diferentes convenciones de llamadas. Hoy en día, "pascal" es una macro que significa "stdcall" en los encabezados C. –

+0

También he visto PASCAL # defined'd to __stdcall. . . pero no estoy seguro de lo que significa con respecto a Delphi. Mi pensamiento original tampoco coincidía con las convenciones de llamadas, pero para una función como esta, la pila no estaría desactivada solo por 4 bytes entre las convenciones de invocación de llamadas y guardado de llamadas. – Michael

Cuestiones relacionadas