Вызов определенного Win32 API из Delphi - Почему исключения вылетают без "asm pop ...”?

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

Вопрос

Я использую Delphi для создания надстройки XLL для Excel, которая включает в себя выполнение множества вызовов Excel4v функция xlcall32.dll.Однако, поскольку я предполагаю, что очень немногие специалисты по Delphi здесь работали с этим конкретным API, я надеюсь, что проблема могла наблюдаться и в других API.

В C, в частности, в файле xlcall.h, который поставляется вместе с Microsoft Excel 2007 XLL SDK, Excel4v определяется как:

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

В Delphi я использую:

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

LPXLOPER - это указатель на структуру (в C) или запись (в Delphi).

Я делал свою домашнюю работу по объявлению функций C в Delphi (эта превосходная статья было большим подспорьем), и я думаю, что я правильно объявляю Excel4v.Однако вызовы из кода Delphi в эту функцию вызывают исключения ("нарушение доступа ..." - это то, что я продолжаю видеть) если не за ними следует следующая строка:

asm pop sink; end;

Где "sink" где-то определяется как целое число.

Я понятия не имею о сборке...Так что мне бы ни за что не пришло в голову попробовать исправить исключения с помощью "asm pop sink;конец;".Но "asm pop тонет;end;" действительно исправляет исключения.Впервые я увидел, как его используют в эта полезная статья о создании XLLS с использованием Delphi.Вот наиболее актуальная цитата:

"Из Delphi большим камнем преткновения с надстройками является дополнительный параметр после адреса возврата в стеке.Это предоставляется бесплатно при каждом обращении в Excel.Я так и не узнал, что в нем содержится, но пока вы выбрасываете это , ваша надстройка будет работать нормально.Добавить строку asm pop переменной, end;после каждого вызова, где переменной может быть любая глобальная, локальная или объектная переменная длиной не менее 4 байт- целое число в порядке.Повторяю - ЭТО ДОЛЖНО БЫТЬ ВКЛЮЧЕНО после каждого вызова Excel4v.В противном случае вы создаете бомбу замедленного действия ".

В основном Я хочу понять, что на самом деле происходит и почему.Что может быть причиной того, что функция Win32 возвращает "дополнительный параметр после адреса возврата в стеке", и что это на самом деле означает?

Может ли быть другой способ исправить это, напримерс другой опцией компилятора или другим способом объявления функции?

И есть ли что - то рискованное в вызове "asm pop sink;end;" после каждого вызова Excel4v ...?Кажется, это работает нормально, но, поскольку я не понимаю, что происходит, это кажется немного опасным...

Это было полезно?

Решение

Я не верю, что это pascal против stdcall - они очень похожи в соглашениях о вызовах и не должны приводить к несоответствующему стеку при выходе из функции.

Из упомянутого Статья,

Это действительно был бы очень приятный синтаксис, но он не совпадает с приведенным выше определением массива.Array-of параметры - это параметры открытого массива.Они могут выглядеть как любой массив, и они принимаем любые массива, но они получают дополнительные (скрытые) параметр, который держит самый высокий индекс в массиве (в Высокое значение).Поскольку это так только в Delphi, а не в C или C ++, у вас бы возникла реальная проблема.(Смотрите также мою статью об открытых массивах), поскольку реальное количество параметров не будет совпадать.

Вы получаете дополнительный параметр "самый высокий индекс массива", передаваемый функции.Это значение int, и его необходимо очистить при завершении работы функции, чтобы вы не столкнулись с поврежденным стеком и аварийным завершением работы.В статье показано, как передавать массивы функциям языка Си.

Что -то вроде:

type
 PLPXLOPER  = ^LPXLOPER;

И передайте PLPXLOPER в качестве последнего параметра.

Другие советы

Большинство функций Windows используют __stdcall ( первый вызов) для их соглашения о вызовах.

Ваше соглашение о вызовах неверно, в частности, "stdcall".В объявлении C указано как "pascal".

Stdcall передает параметры справа налево, ожидает, что процедура выполнит очистку, и не использует регистры.Pascal, OTOH передает параметры в слева направо порядок.Следовательно, все происходит не так, как ожидает другая половина кода в любом случае.

Измените свое объявление Delphi также на "pascal" вместо "stdcall".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top