Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.11.13;
Скачать: CL | DM;

Вниз

Подключение плагина на C++ к программе на Delphi   Найти похожие ветки 

 
Bordo   (2009-09-01 13:52) [0]

Здравствуйте, коллеги!

Неделю мучаюсь над странным поведением SendMessage() из WinAPI -- растолкуйте кто знает.

Условия задачи:
* есть чужая программа на Delphi7, исходников нет;
* к программе можно подключать простые плагины в виде DLL с экспортируемой точкой входа вида ShowModForm(appWnd: HWND);
* подключаемый модуль может общаться с программой посредством SendMessage;
* тестовый пример на Delphi работает, а на WTL -- нет.

Код модуля на Delphi:

unit TestFormUnit;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TTestForm = class(TForm)
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 TestForm: TTestForm;

procedure ShowModForm(appWnd: HWND);

implementation

{$R *.dfm}

procedure ShowModuleForm(appWnd: HWND);
var
 rslt : Integer;
 msgCode : Integer;
begin
 with TTestForm.Create(Application) do
 try
   msgCode := RegisterWindowMessage("WM_ACME_REGISTERMODWND");

   {WM_ACME_REGISTERMODWND -- одно из сообщений для взаимодействия с приложением,
   {Возвращаемое значение должно быть 1 или 2}
   rslt := SendMessage(appWnd, msgCode, Handle, 0);

   Caption := "DelphiTestModule - " + IntToStr(rslt);
   ShowModal
 finally
   Free
 end
end;

end.


Процедура [i]ShowModuleForm[/i] экспортируется так:

library ModDelphi;

uses
 ShareMem,
 SysUtils,
 Classes,
 TestFormUnit in "TestFormUnit.pas" {TestForm};

{$R *.res}

exports ShowModuleForm;

begin
end.


При открытии формы этого модуля в заголовке будет написано DelphiTestModule - 1.

Вот код на C++ c использованием WTL:

#include "stdafx.h"

#define MOD_WTL_API __declspec(dllexport)

#include <windows.h>

#include <atlbase.h>
#include <atlapp.h>

extern CAppModule _Module;
#include <atlwin.h>
#include <atlgdi.h>
#include <atlmisc.h>

CAppModule _Module;

using namespace std;

// Функция вызова плагина
extern "C" MOD_WTL_API BOOL ShowModForm(HWND parent);

// Точка входа в DLL
BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
     )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
 // Инициализируем модуль
 _Module.Init(0, hModule, 0);

 break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
 break;
case DLL_PROCESS_DETACH:
 _Module.Term();
 break;
}
   return TRUE;
}

// Главное окно плагина
class CMainWindow :
public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
{
BEGIN_MSG_MAP(CMainWindow)
 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()

LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
 PostQuitMessage(0);
 return 0;
}
};

MOD_WTL_API BOOL ShowModForm(HWND parent)
{
// Создаём главное окно модуля.
CMainWindow wnd;
wnd.Create(NULL, CWindow::rcDefault);

const UINT WM_ACME_REGISTERMODWND = ::RegisterWindowMessage(L"WM_ACME_REGISTERMODWND");
const LRESULT rslt = ::SendMessage(parent, WM_ACME_REGISTERMODWND, (WPARAM)((HWND)wnd), 0); ///< Возвращает всегда 0!

char buffer[80] = {0};
_itoa(rslt, buffer, 10);

CString title(L"WtlTestModule - ");
title += rslt;
::SetWindowText(wnd, title);

wnd.ShowWindow(SW_SHOW);
// Запускаем цикл сообщений
CMessageLoop loop;
loop.Run();

return TRUE;
}


При открытии формы этого модуля в заголовке будет написано WtlTestModule - 0. Т.е. объявленный в программе API для подключения модулей не работает.

Подозреваю, что тайна может заключаться в использовании TTestForm.Create(Application), но как его использовать в C++?


 
clickmaker ©   (2009-09-01 13:58) [1]

TTestForm.CreateParented(appWnd)


 
Rouse_ ©   (2009-09-01 14:20) [2]

(WPARAM)((HWND)wnd)
замени на
wnd::m_hWnd


 
Bordo   (2009-09-01 15:35) [3]

Rouse_, тогда уж на
reinterpret_cast<WPARAM>(wnd.m_hWnd)

но к вопросу это не относится.


 
Bordo   (2009-09-01 15:41) [4]


> clickmaker ©   (01.09.09 13:58) [1]
> TTestForm.CreateParented(appWnd)

Это на CBuilder? К сожалению, не могу его использовать -- работаю на Visual Studio 2005 и gcc 3.4.5 (mingw-vista special r3). Есть способ использовать VCL в этих компиляторах?


 
Bordo   (2009-09-01 15:44) [5]

Мне тут указали, что procedure ShowModForm(appWnd: HWND); вызывается как register (__fastcall в С++).

И правда, если объявить procedure ShowModForm(appWnd: HWND); stdcall;, то в заголовке Дельфийской формы тоже будет ноль. К сожалению, пока что не удалось подобрать нужный спецификатор вызова для C++ версии.


 
Rouse_ ©   (2009-09-01 16:25) [6]


> но к вопросу это не относится.

Это как это не относится? :) У тебя же код разные вещи делает :)

В дельфи аналоге (который работает) ты передаешь в SendMessage хэндл вновь созданной формы, а в сишном варианте передаешь указатель на CMainWindow который зачем-то еще и к хэндлу приводишь. вместо того чтобы передать тот-же хэндл, хранящийся в параметре m_hWnd. Разница есть?
Ну а stdcall применить к ShowModForm - это тебя хитро надоумили. Стек на 4 байта уплыл, понятно почему после этого и дельфийский аналог перестал работать.


 
Bordo   (2009-09-01 17:16) [7]


> Rouse_ ©   (01.09.09 16:25) [6]
> > но к вопросу это не относится.Это как это не относится?
>  :) У тебя же код разные вещи делает :)В дельфи аналоге
> (который работает) ты передаешь в SendMessage хэндл вновь
> созданной формы, а в сишном варианте передаешь указатель
> на CMainWindow который зачем-то еще и к хэндлу приводишь.
>  вместо того чтобы передать тот-же хэндл, хранящийся в параметре
> m_hWnd. Разница есть?


1. не указатель, а локальную переменную;
2. CWindow автоматически приводится к HWND через тот же m_hWnd.


>  Ну а stdcall применить к ShowModForm
> - это тебя хитро надоумили. Стек на 4 байта уплыл, понятно
> почему после этого и дельфийский аналог перестал работать.


Да всё дело оказалось в calling conventions. Именно по этому не работает код на С++: я как порядочный человек использовал stdcall для экспорта, а авторы хост-программы плевать хотели на стандарты и соглашения.

Теперь разбираю примерчик отсюда: http://www.codeguru.com/forum/showthread.php?t=466266


 
Сергей М. ©   (2009-09-01 17:26) [8]


> авторы хост-программы плевать хотели на стандарты и соглашения


Имеют полное право плевать.
А вот то что они якобы не указали в своем PluginSDK требуемые соглашения о вызовах - это довольно подозрительно.


 
Bordo   (2009-09-01 17:41) [9]


> Сергей М. ©   (01.09.09 17:26) [8]
>
> Имеют полное право плевать. А вот то что они якобы не указали
> в своем PluginSDK требуемые соглашения о вызовах - это довольно
> подозрительно.

Иметь-то имеют, но не надо тогда заявлять, что можно разрабатывать модули на чём угодно. И всё-таки мне кажется, что они были "не в курсе" каких-то там соглашений.


 
Leonid Troyanovsky ©   (2009-09-01 18:04) [10]


> Bordo   (01.09.09 13:52)  

> TTestForm.Create(Application), но как его использовать в
> C++?

Application - никак. Т.е. влиять на него можно только сабклассив его окно.
Кроме того, есть глобальные переменные Screen, PopupMenues и т.п.,
в каждой из которых притаились ржавые грабли.

Подозреваю даже неправомерность

> // Запускаем цикл сообщений

если, конечно, это не модальный диалог.

--
Regards, LVT.


 
Bordo   (2009-09-02 05:46) [11]

Итак, всё дело было в разъезжании стека из-за несоответствия calling conventions. Проблему удалось решить с помощью простой обёртки на Дельфи:

unit TestFormUnit;

interface

type
 HWND = type LongWord;
 {$EXTERNALSYM HWND}

procedure ShowModuleFormProxy(appWnd: HWND);

implementation

procedure ShowModForm(appWnd: HWND); stdcall; External "mod_wtl.dll";

procedure ShowModuleFormProxy(appWnd: HWND);
begin
 mod_wtl_show(appWnd);
end;

end.

Код на C++ остался без изменений.

Параллельно пытаюсь разобраться с вариантом, описанным в  http://www.codeguru.com/forum/showthread.php?t=466266 . Если кто-нибудь поделится рабочим вариантом для Visual C++ 2005, а ещё лучше для gcc 3.4.5 под mingw, буду очень признателен, потому что в ассемблере я совершенно не разбираюсь.

Если кто-нибудь знает, как правильно написать



Страницы: 1 вся ветка

Текущий архив: 2011.11.13;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.009 c
2-1311744151
Шел мимо решил зайти
2011-07-27 09:22
2011.11.13
работа с excel


15-1309890322
Petr V. Abramov
2011-07-05 22:25
2011.11.13
вышел сегодня на новую работу


15-1311107388
Юрий
2011-07-20 00:29
2011.11.13
С днем рождения ! 20 июля 2011 среда


2-1311603780
>|<
2011-07-25 18:23
2011.11.13
Quick Report: создание отчета из двух источников данных


2-1311063552
Ш-К
2011-07-19 12:19
2011.11.13
Толстые и тонкие клиенты