Delphi DLL в Visual C++
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
У меня такая проблема.
Есть длл на Делфи. Необходимо динамически подключить ее к проге на вижуале. Проблема в том, что я не могу передать правильно параметры. До длл на Делфи они доходят неправильно (я писал длл на С++ там все нормально). По видимому прблема в cflling conventions.
Пытался использовать stdcall и WINAPI результатов не дало.
Вот часть на делфи:
function ShowForm(c: LPCSTR; h: HWND; d: LPCSTR):HWND;
begin
Form1:=TForm1.Create(Application);
Form1.Edit1.Text:=c;
Form1.Edit2.Text:=inttostr(h);
form1.Edit3.Text:=d;
Form1.Show;
ShowForm:=Form1.WindowHandle;
ShowMessage(c+', '+d);
end;
Вот вызов на вижуале:
typedef HWND (* PTShowForm)(LPCSTR, HWND, LPCSTR);
PTShowForm TShow;
hDLL=LoadLibrary(dllname);
if (hDLL!=0)
{
TShow = (PTShowForm)GetProcAddress(hDLL,"ShowForm");
dllhwnd=TShow((LPCSTR)str1, GetSafeHwnd(), (LPCSTR)str2);
}
Вообще я пытаюсь вставить диалог на Делфи (длл) в прогу на вижуале. Получается довольно скверно. Постоянно приходиться обходить всякие пакости. Может кто-то подобное делал и может подсказать решение.
Есть длл на Делфи. Необходимо динамически подключить ее к проге на вижуале. Проблема в том, что я не могу передать правильно параметры. До длл на Делфи они доходят неправильно (я писал длл на С++ там все нормально). По видимому прблема в cflling conventions.
Пытался использовать stdcall и WINAPI результатов не дало.
Вот часть на делфи:
function ShowForm(c: LPCSTR; h: HWND; d: LPCSTR):HWND;
begin
Form1:=TForm1.Create(Application);
Form1.Edit1.Text:=c;
Form1.Edit2.Text:=inttostr(h);
form1.Edit3.Text:=d;
Form1.Show;
ShowForm:=Form1.WindowHandle;
ShowMessage(c+', '+d);
end;
Вот вызов на вижуале:
typedef HWND (* PTShowForm)(LPCSTR, HWND, LPCSTR);
PTShowForm TShow;
hDLL=LoadLibrary(dllname);
if (hDLL!=0)
{
TShow = (PTShowForm)GetProcAddress(hDLL,"ShowForm");
dllhwnd=TShow((LPCSTR)str1, GetSafeHwnd(), (LPCSTR)str2);
}
Вообще я пытаюсь вставить диалог на Делфи (длл) в прогу на вижуале. Получается довольно скверно. Постоянно приходиться обходить всякие пакости. Может кто-то подобное делал и может подсказать решение.
Borys, есть такое мнение, что параметры надо передавать не по значению, а по ссылке.
Даже самый дурацкий замысел можно воплотить мастерски
AiK, нет, это здесь не при чем.
Borys, конкретно, в чем ошибка?
Borys, конкретно, в чем ошибка?
Eugie, да, ты наверное прав. Это в случае var переменной на одну звёздочку требуется больше 

Даже самый дурацкий замысел можно воплотить мастерски
Ошибка в следующем:
Я в вижуале вызываю функцию:
TShow((LPCSTR)str1, GetSafeHwnd(), (LPCSTR)str2);
Открывается окно делфийского приложения. Оно получает параметры не так как нужно. Например в вижуале str1--"7006", HWND -- число и str2--"Не выбран".
В делфи-диалоге пулучается:
str1="Um'j"
HWND--число, но не то которое было.
str2="7006"(=str1)
Если использовать stdcall(Delphi) и WINAPI(C++) то параметры вроде передаются правильно(по крайней мере строки), но приложение падает.
Я в вижуале вызываю функцию:
TShow((LPCSTR)str1, GetSafeHwnd(), (LPCSTR)str2);
Открывается окно делфийского приложения. Оно получает параметры не так как нужно. Например в вижуале str1--"7006", HWND -- число и str2--"Не выбран".
В делфи-диалоге пулучается:
str1="Um'j"
HWND--число, но не то которое было.
str2="7006"(=str1)
Если использовать stdcall(Delphi) и WINAPI(C++) то параметры вроде передаются правильно(по крайней мере строки), но приложение падает.
Во-первых, при использовании в программе модулей, написанных на разных языках, calling convention в любом случае должны быть согласованы - здесь не может быть сомнений. Не обязательно это должен быть stdcall, можно cdecl, также допустимый в обоих языках (в даннном случае VC++ и Delphi). Но stdcall все же удобнее, т.к. в настоящее время является стандартом для API функций.
Во-вторых, в VC-части лучше использовать явно __stdcall вместо макроса WINAPI, значение которого может меняться в зависимости от платформы и версии компилятора.
Вот пример согласованного объявления ShowForm:
Если это не поможет, сообщи, когда происходит ошибка (с точностью до строки кода, под отладчиком) и ее текст.
PS. Еще пара советов: 1) вместо Form1.Show -> Form1.ShowModal, тогда не нужен будет ShowMessage для задержки формы; 2) вместо Form1.WindowHandle лучше Form1.Handle (последний гарантированно инициализирован).
Во-вторых, в VC-части лучше использовать явно __stdcall вместо макроса WINAPI, значение которого может меняться в зависимости от платформы и версии компилятора.
Вот пример согласованного объявления ShowForm:
Код: Выделить всё
[VC++]
typedef HWND (__stdcall * PTShowForm)(LPCSTR, HWND, LPCSTR);
[Delphi]
function ShowForm(c: LPCSTR; h: HWND; d: LPCSTR): HWND; stdcall;
...
exports ShowFrom;
PS. Еще пара советов: 1) вместо Form1.Show -> Form1.ShowModal, тогда не нужен будет ShowMessage для задержки формы; 2) вместо Form1.WindowHandle лучше Form1.Handle (последний гарантированно инициализирован).
Eugie, спасибо. Вроде помогло.
Осталась одна проблема:
как связать окна (окно Делфи должно быть дочернее по отношению к окну вижуал си++). Я передаю даскриптор окна С++. И тут начинаются прблемы. Мне необходимо, чтоб окно делфи было немодальным. Когда запускаю приложение, окно показывается, все как надо, но судя по всему оно не реагирует на некоторые сообщения. Например: при нажатии на "таб" фокус не перескакивает на следующий компонент. Если навести фокус на компонент, в который ничего нельзя ввести (например кнопка) и нажать клавишу, то приложение виснет.
Частично проблему решает такое изменение кода (ShowMessage не играет никакой роли, оно было для проверки):
function ShowForm(c: PChar; h: HWND; d: PChar):HWND;
begin
Application.Initialize; //добавлено
Application.Handle:=h; //добавлено
Form1:=TForm1.Create(Application);
Application.DialogHandle:=Form1.Handle; //добавлено
Form1.Edit1.Text:=c;
Form1.Edit2.Text:=inttostr(h);
Form1.Edit3.Text:=d;
Form1.Show;
ShowForm:=Form1.Handle;
end;
В этом случае приложение не виснет, но фокус всеравно не перескакивает.
Я также пытался использовать CreateParanted и CreateParantedControl. Тогда окно делфи вообще не появляется и выскакивает ошибка, короче все падает.
Осталась одна проблема:
как связать окна (окно Делфи должно быть дочернее по отношению к окну вижуал си++). Я передаю даскриптор окна С++. И тут начинаются прблемы. Мне необходимо, чтоб окно делфи было немодальным. Когда запускаю приложение, окно показывается, все как надо, но судя по всему оно не реагирует на некоторые сообщения. Например: при нажатии на "таб" фокус не перескакивает на следующий компонент. Если навести фокус на компонент, в который ничего нельзя ввести (например кнопка) и нажать клавишу, то приложение виснет.
Частично проблему решает такое изменение кода (ShowMessage не играет никакой роли, оно было для проверки):
function ShowForm(c: PChar; h: HWND; d: PChar):HWND;
begin
Application.Initialize; //добавлено
Application.Handle:=h; //добавлено
Form1:=TForm1.Create(Application);
Application.DialogHandle:=Form1.Handle; //добавлено
Form1.Edit1.Text:=c;
Form1.Edit2.Text:=inttostr(h);
Form1.Edit3.Text:=d;
Form1.Show;
ShowForm:=Form1.Handle;
end;
В этом случае приложение не виснет, но фокус всеравно не перескакивает.
Я также пытался использовать CreateParanted и CreateParantedControl. Тогда окно делфи вообще не появляется и выскакивает ошибка, короче все падает.
Добавь в цикл обработки сообщений вызов IsDialogMessage (должен всегда присутствовать при наличии в приложении немодальных диалоговых окон):
Код: Выделить всё
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwndForm, &msg))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
У меня приложение на MFC поетому я добавил код в PreTranslateMessage(MSG* pMsg), помоему - единственное подходящее место где можно получить MSG а не (UINT message, WPARAM wParam, LPARAM lParam). Но всеравно не работает.
Интересно то, что согласно Spy++ форма на делфи не имеет Parent Window(=null). Хотя Owner Window -- как и нужно, окно С++.
Потом, если в делфи вызвать ShowMessage(), то у окошка с сообщением и Parent и Owner - окно С++.
И еще если смотреть сообщения, которые идут на окно С++, когда что-то происходит с окном на делфи (нажатия на кдавиши, движение мышки), то мы видим только одно сообщение: WM_KICKIDLE.
На окно на делфи сообщения не поступают при нажатии на "tab" или "enter".
Интересно то, что согласно Spy++ форма на делфи не имеет Parent Window(=null). Хотя Owner Window -- как и нужно, окно С++.
Потом, если в делфи вызвать ShowMessage(), то у окошка с сообщением и Parent и Owner - окно С++.
И еще если смотреть сообщения, которые идут на окно С++, когда что-то происходит с окном на делфи (нажатия на кдавиши, движение мышки), то мы видим только одно сообщение: WM_KICKIDLE.
На окно на делфи сообщения не поступают при нажатии на "tab" или "enter".
К сожалению, это так. В чем причина - не знаю.У меня приложение на MFC поетому я добавил код в PreTranslateMessage(MSG* pMsg), помоему - единственное подходящее место где можно получить MSG а не (UINT message, WPARAM wParam, LPARAM lParam). Но всеравно не работает.
Родительское (parent) окно определено только для дочерних (child) окон, а Delphi-форма является окном верхнего уровня и может иметь только владельца (owner window).Интересно то, что согласно Spy++ форма на делфи не имеет Parent Window(=null). Хотя