2009-07-07 4 views
6

Używam Delphi do tworzenia dodatku XLL dla programu Excel, co wiąże się z wykonywaniem wielu wywołań funkcji Excel4v pliku xlcall32.dll. Jednak, jak przypuszczam, niewielu ekspertów Delphi pracowało z tym konkretnym API, mam nadzieję, że problem ten można było zaobserwować również w innych interfejsach API.Wywołanie określonego API Win32 z Delphi - Dlaczego wyjątki leżą bez "asm pop ..."?

W C, a konkretnie w pliku xlcall.h że pochodzi z Microsoft Excel 2007 XLL SDK, Excel4v jest zdefiniowany jako:

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

W Delphi Używam:

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

LPXLOPER jest wskaźnikiem do struktury (w C) lub rekordu (w Delphi).

Odrabiam zadania domowe dotyczące deklarowania funkcji C w Delphi (this excellent article była bardzo pomocna) i myślę, że deklaruję poprawnie Excel4v. Wzywa jednak z kodu Delphi w tym wyjątków funkcja przyczyna („naruszenia zasad dostępu ...” to co ja widuję) chyba są następnie następującej linii:

asm pop sink; end; 

Gdzie „sink” definiuje się gdzieś jako liczba całkowita.

Nie mam pojęcia o montażu ... Więc nie ma sposobu, bym pomyślał, aby spróbować naprawienia wyjątków za pomocą "asm pop sink; end;". Ale "pop upton pop, end;" naprawia wyjątki. Po raz pierwszy zobaczyłem, że był używany w this useful article on making XLLs using Delphi. Oto najbardziej istotne cytat:..

„z Delphi wielkim zgorszeniem z dodatków jest dodatkowy parametr po adresem zwrotnym na stosie To jest za darmo przy każdym wywołaniu Excel I” Nigdy nie dowiedziałem się, co to jest posiada, ale tak długo, jak wyrzucisz go z dala, twój dodatek będzie działał poprawnie Dodaj linia asm pop zmienna, koniec, po każde połączenie, gdzie zmienna może być dowolna globalna, lokalna lub zmienna obiektu, która ma długość co najmniej 4 bajtów, jest liczbą całkowitą . Aby powtórzyć, TO MUSI BYĆ INCLUDED po każdym wywołaniu Excel4v. Inaczej jesteś skonstruowania bomby zegarowej „

Zasadniczo Chcę zrozumieć, co się właściwie dzieje i dlaczego. Co może być przyczyną funkcji Win32 do zwracania” dodatkowy parametr po adresie zwrotu z stosu „a co to właściwie znaczy?

Może istnieć inny sposób rozwiązać ten problem, na przykład z inną opcją kompilatora lub inny sposób deklarowania funkcji?

a czy jest coś ryzykowne o wywołanie” ASm pop sink; koniec, "po każdym wywołaniu Excel4v ...? Wydaje się, że działa dobrze, ale, jak nie rozumiem, co się dzieje, czuje się trochę niebezpieczne ...

+0

Piszę XLL w Delphi i chciałbym się z Tobą skontaktować. Napisz do mnie na adres [email protected] – garethm

Odpowiedz

8

Nie sądzę, że jest to pascal vs stdcall - są to bardzo podobne konwencje wywoływania i nie powinny skutkować niedopasowaniem stosu przy wyjściu funkcji.

Od odwołuje article,

To rzeczywiście bardzo miłe składnia, ale to nie jest taka sama jak powyższej definicji tablicy. Array- Parametry są parametrami otwartej tablicy. Mogą one wyglądać jak dowolne macierze, a one akceptują dowolną tablicę, ale otrzymują dodatkowy (ukryty) parametr , który zawiera najwyższy indeks w tablicy ( ) (wysoka wartość w postaci ). Ponieważ jest to tylko w przypadku Delphi , a nie w C lub C++, masz poważny problem z . (Zobacz także mój artykuł na temat otwartych tablic), ponieważ rzeczywista liczba parametrów nie pasowałaby do .

Otrzymujesz dodatkowy parametr "najwyższego wskaźnika tablicy" przekazywany do funkcji. To jest int i musi zostać wyczyszczone, gdy funkcja kończy działanie, aby nie skończyć z uszkodzonym stosem i awarią. W artykule pokazano, jak przekazywać tablice do funkcji języka C.

Coś jak:

type 
PLPXLOPER = ^LPXLOPER; 

I przekazać PLPXLOPER jako ostatni parametr.

+0

Dzięki Michael, to brzmi jak wyjaśnienie dla mnie :) Będę baw się z nim trochę, aby być pewnym i skomentuj ponownie, kiedy jestem. –

+0

Fantastyczne! O ile mogę powiedzieć, że działa idealnie. Określ funkcję jako funkcja Excel4v (xlfn: liczba całkowita; operRes: LPXLOPER; stdcall; zewnętrzny "xlcall32.dll"; następnie wywołaj ją, utwórz tablicę Delphi LPXLOPERA i wywołaj Excel4v z @myArray [0] dla PLPXLOPERA. Działa wspaniale, ze stdcallem i nie ma potrzeby podejrzanych wyglądających asmowych połączeń pop :) –

0

Twoja konwencja telefonowania jest nieprawidłowa, w szczególności "stdcall".Deklaracja C jest określona jako "pascal"

Stdcall przekazuje parametry w porządku od prawej do lewej, oczekuje, że procedura oczyści się i nie będzie używać rejestrów. Pascal, OTOH przekazuje parametry od od lewej do prawej:. Dlatego nie dzieje się tak, jak druga połowa kodu oczekuje w obu przypadkach.

Zmień deklarację Delphi na "pascal" zamiast "stdcall".

+0

Próbowałem określając go jako pascal, ale nie mogłem uzyskać żadnych połączeń do niego do pracy. Ale funkcja zdecydowanie działa poprawnie ze stdcall, pod warunkiem, że jest podążana za linią "asm pop ...". Artykuł na http://rvelthuis.de/articles/articles-convert.html wspomina o tym, że pascal ma sprzeczne z intuicją znaczenie, choć nie jest to aż tak specyficzne. –

+0

Były to różne konwencje telefonowania. W dzisiejszych czasach "pascal" to makro, które oznacza "stdcall" w nagłówkach C. –

+0

Widziałem również PASCAL # define'd do __stdcall. . . ale nie jestem pewien, co to znaczy w odniesieniu do delphi. Moja oryginalna myśl była również niedopasowaną konwencją wywoływania, ale dla takiej funkcji stos nie byłby wyłączony tylko 4 bajtami między konwencjami oszczędzania rozmówcy i oszczędzania. – Michael