Chamar API específica Win32 do Delphi - Por que Exceções voar sem um “pop asm ...”?

StackOverflow https://stackoverflow.com/questions/1093206

Pergunta

Estou usando o Delphi para fazer um XLL add-in para Excel, que envolve fazer um monte de chamadas para o função de xlcall32.dll Excel4v . No entanto, como eu estou supondo que muito poucos especialistas Delphi aqui têm trabalhado com essa API específica, eu estou esperando que o problema poderia ter sido observada em outras APIs também.

Em C, especificamente no arquivo xlcall.h que vem com o Microsoft Excel 2007 XLL SDK , Excel4v é definido como:

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

Em Delphi Eu estou usando:

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

LPXLOPER é um ponteiro para uma estrutura (em C) ou ficha (em Delphi).

Eu tenho feito o meu trabalho de casa sobre declarando funções C em Delphi ( este excelente artigo foi uma grande ajuda) e eu acho que estou declarando Excel4v corretamente. No entanto, chamadas de código Delphi em que a função de causa exceções ( "violação de acesso ..." é o que eu continuo vendo) menos são seguidos pela seguinte linha:

asm pop sink; end;

Onde "pia" é definido em algum lugar como um inteiro.

Eu não tenho nenhuma pista sobre a montagem ... Então não há nenhuma maneira que eu teria pensado para tentar resolver as exceções com "pop pia asm; end;". Mas "; end; asm pia pop" de fato, corrigir as exceções. Vi pela primeira vez que seja usado em este artigo útil em fazer XLLs usando Delphi . Aqui está a cotação mais relevante:

"De Delphi o grande obstáculo com add-ins é o parâmetro extra após o endereço de retorno na pilha. Este é fornecido gratuitamente com cada chamada para Excel. Eu nunca descobri o que detém, mas contanto que você jogá-lo distância, o add-in irá funcionar bem. Adicionar a variável pop asm linha, acabar; depois de cada chamada, onde variável pode ser qualquer global, local ou variável de objeto que é, pelo menos, quatro bytes longo inteiro seja bem. Para REPEAT isso deve ser incluído após cada chamada Excel4v. De outra forma você está construindo uma bomba-relógio. "

Basicamente Quero entender o que está realmente acontecendo, e por . O que poderia estar causando uma função Win32 para retornar um "parâmetro extra após o endereço de retorno na pilha", e o que isso realmente significa?

Pode haver outra maneira de corrigir isso, por exemplo, com uma opção de compilador diferente ou uma maneira diferente de declarar a função?

E existe alguma coisa arriscada sobre a chamada "pia asm pop; end;" após cada chamada para Excel4v ...? Parece funcionar bem, mas, como eu não entendo o que está acontecendo, ele se sente um pouco perigoso ...

Foi útil?

Solução

Eu não acredito que é pascal vs stdcall -. Eles são convenções de chamada muito semelhantes e não deve resultar em uma pilha incompatíveis na saída função

A partir do referenciada artigo ,

Este seria realmente um muito bom sintaxe, mas não é o mesmo que o definição de matriz acima. Matriz de parâmetros são parâmetros de matriz aberta. Podem olhar como qualquer matriz, e eles não aceitar qualquer array, mas eles obter uma adicional parâmetro (oculto), que detém o mais elevado índice na matriz (a Valor alto). Uma vez que este é somente assim em Delphi, e não em C ou C ++, você tem um problema real. (Veja também a minha artigo sobre matrizes abertas), uma vez que o número real de parâmetros não faria jogo.

Você está recebendo o extra "mais alto índice de array" parâmetro que está sendo passado para a função. Este é um int e tem de ser limpo quando a função sai de modo que você não acabar com uma pilha corrompido e acidente. O artigo indica como passar matrizes para funções C.

Algo como:

type
 PLPXLOPER  = ^LPXLOPER;

E passar PLPXLOPER como o último parâmetro.

Outras dicas

A maioria das funções do Windows usam __stdcall para suas convenções chamando .

A sua convenção de chamada é errado, especificamente o "stdcall". A declaração C é especificado como "pascal"

Stdcall passa parâmetros no direito de ordem da esquerda, espera que a rotina de limpar, e não usa registros. Pascal, OTOH passa parâmetros em esquerda para a direita ordem. Portanto, as coisas não estão acontecendo da maneira que a outra metade dos espera de código em ambos os casos.

Mude sua declaração Delphi também ser "pascal" em vez de "stdcall".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top