Pascal exe и С++ dll

Ответить
Аватара пользователя
Server

Pascal exe и С++ dll

Сообщение Server »

Прошу помочь знающих людей, бо сам уже оскомиму набил-таки...

Значит имеется программа написанная на Delphi 7. В ней вызывается dll, следующим образом:

--------------------------------------------------

var

PlugExec:function(I,R,S,B:pointer;ISize,RSize,SSize,BSize:integer):boolean;

IntMas:array[0..72] of ^integer;

RealMas:array[0..4] of ^real;

StrMas:array[0..29] of ^shortstring;

BoolMas:array[0..4] of ^boolean;

begin

@PlugExec:=nil;

NewHandle:=LoadLibrary('C++Plugin.dll'));

if NewHandle 0 then begin

@PlugExec:=GetProcAddress(NewHandle,'PluginExec');

PlugExec(@IntMas,@RealMas,@StrMas,@BoolMas,length(IntMas),length(RealMas),length(StrMas),length(Bool Mas));

end;

FreeLibrary(NewHandle);

--------------------------------------------------

Теперь код С++ dll-ки (.NET):

--------------------------------------------------

extern "C" bool PASCAL EXPORT PluginExec(void *I, void *R, void *S, void *B, int ISize, int RSize, int SSize, int BSize){

int *IntMas;

IntMas=new int[ISize];

IntMas=dynamic_cast(I);

if (IntMas[5]==4)

...

return true; }

--------------------------------------------------

В результате выскакивает следуюзая ошибка в строке с dynamic_cast:

error C2059: syntax error : 'constant'



1. В чем проблема? Объявить const void *I - та же проблема.

2. Если из Delphi в ISize сидит к примеру 40, то в С++ я виду 1200000 или что-то в этом роде.

3. Адрес ячейки памяти I указывает на 0х000005 чего-то так, то есть область ОС. Указатели без типа несовместимы?



Заранее благодарен, за любую предоставленную информацию.
Аватара пользователя
ivank

Re: Pascal exe и С++ dll

Сообщение ivank »

Server

Можно почитать документацию по dynamic_cast и понять, что а) он здесь не нужен б) синтаксис неправильный. Здесь хватит static_cast'а. Примерно так: IntMas = static_cast(i). Более того, поскольку фактически void* от int* ничем не отличается, а манглинг имён всё равно не применяется, то можно параметр I сразу сделать типа int*.



То что i=(void*)5 навевает на мысль, что конвенции вызова не совпадают и параметры лежат в обратном порядке (т.к. должно быть BSize=5). Что-то мне подсказывает, что PlugExec стоит объявить вот так:



Код:

Код: Выделить всё

PlugExec:function(I,R,S,B:pointer;ISize,RSize,SSize,BSize:integer):boolean; stdcall;

Либо убрать PASCAL из объявления функции в сишной реализации.
Аватара пользователя
Server

Re: Pascal exe и С++ dll

Сообщение Server »

ivank

Почему именно static надо применять? Массив я же создаю динамически.

Со static dll скомпилена. Массив динамически создается, но поскольку ISize равняется 1000000 и I указывает на системную область памяти - получаем Access Violation.



Экстрадиция Pascal из объявления функции - как мертвому припарки. Изменить exe код не представляется возможным. Там нет stdcall.
Аватара пользователя
ivank

Re: Pascal exe и С++ dll

Сообщение ivank »

Server

Курите документацию. Как вы выделяете память не влияет на то, какой *_cast применять. Это зависит сугубо от типов, которые подвергаются преобразованию. Для преобразования void* в int* достаточно static_cast. dynamic_cast нужен при преобразованиях от указателя на предок класса к указателю на наследника.




Цитата:



Экстрадиция Pascal из объявления функции - как мертвому припарки. Изменить exe код не представляется возможным. Там нет stdcall.



Слишком кратко, а поэтому непонятно.



Почему нельзя менять exe? Оптимально изменить именно его, чтобы использовалась конвенция stdcall, потому что про неё все (delphi и VC) всё прекрасно знают, так как она используется при вызове winapi. Это де-факто стандарт. Те, кто не используют эту конвенцию для вызова "инородных" функций - сами себе злобные буратины.



Я немножко погуглил и выяснил, что дельфи по умолчанию использует register конвенцию. То есть распихивает первые 3 параметры в регистры (eax, ecx, edx), остальные параметры кладутся на стек согласно паскалевской конвенции. Насколько мне известно VS ничего подобного не знает.



Поэтому, если exe менять нельзя для использования более адекватной конвенции, следует написать заглушку, которая будет принимать параметры согласно дельфёвым соглашениям (register), а вызывать функцию согласно согласно соглашениям, которые понимает VS (__cdecl, __stdcall, __pascal, или __fastcall). Если есть желание вставить такую заглушку непосредственно в dll, то придётся писать её на ассемблере.



Я, чтобы не мучиться, создал бы dll-заглушку на дельфи. В которой была бы одна функция PlugExec, которая принимает параметры в дельфёвой конвенции register, а вызывает сишный плагин уже с помощью stdcall. Соответственно в сишном плагине заменил бы соглашение для функции PlugExec с PASCAL на __stdcall.



upd

Повторюсь, резюмируя всё выше сказанное.



Либо используйте в exe и dll одно соглашение о вызовах, которое понимае и VS и delphi. К ним относятся: pascal/__pascal, cdecl/__cdecl, stdcall/__stdcall. Перед слышем дано название соглашеия в дельфе, после - в VS.



Либо (если exe менять нельзя) пишите заглушку, которая будет принимать парметры в дельфёвом соглашении register, а выдавать их в соглашении, понятном VS (сейчас у вас, судя по коду, сишная функция использует паскалевское соглашение).



Подробнее про различные соглашения о вызовах можно почитать в интернете. Погуглив на тему "delphi calling conventions".
Аватара пользователя
Server

Re: Pascal exe и С++ dll

Сообщение Server »

ivank

Спасибо, разобрался. Действительно нужно вызывать через соглашение stdcall. Получилось получить доступ ко всем параметрам главной программы, однако возник вопрос.

В программе на Delphi (этой же) используется тип shortstring. А какой для него аналог использовать в С++? char* не получается.
Аватара пользователя
ivank

Re: Pascal exe и С++ dll

Сообщение ivank »

http://www.google.ru/search?hl=ru&q=...+shortstring+c




Первый байт - длина строки, начиная со второго - сама строка. Без завершающего нуля.
Аватара пользователя
hasherfrog

Re: Pascal exe и С++ dll

Сообщение hasherfrog »

Для продвинутого курения :]

Относительно DLL хорошая статья:
http://www.progz.ru/articles.php?issue=9
Ответить

Вернуться в «Программирование и базы данных»