Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2011.11.13;
Скачать: [xml.tar.bz2];

Вниз

Подключение плагина на 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 вся ветка

Форум: "WinAPI";
Текущий архив: 2011.11.13;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.003 c
15-1310730513
Rendy_Stager
2011-07-15 15:48
2011.11.13
Помощь по Клиент-серверному приложению


15-1310539493
SQLEXPRESS
2011-07-13 10:44
2011.11.13
Ctrl+shift+с во время описания класса. Некорректно


15-1310648771
SQLEXPRESS
2011-07-14 17:06
2011.11.13
Вот такой прикол нашел.. MSSQL


3-1266236064
Раиса
2010-02-15 15:14
2011.11.13
MySQL и несколько insert-ов


15-1311009842
istok
2011-07-18 21:24
2011.11.13
что может приводить к проблемам с клавой..?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский