C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
и снова DLL, кнопка — реакция на нажатие
joynter
Отправлено: 08.09.2004, 12:23


Станционный диспетчер

Группа: Участник
Сообщений: 137



в либе создаю форму, на форму кладу кнопку далее

button->OnClick = button_click;

...

void button_click()
{
ShowMessage("...");
}

компилятор говорит "not an allowed type"

как правильно оформить в библиотеке реакцию на нажатие кнопки?
Guest
Отправлено: 08.09.2004, 12:48


Не зарегистрирован







использовать closure, TNotifyEvent или можно почитать здесь
Asher
Отправлено: 08.09.2004, 12:56


Мастер участка

Группа: Модератор
Сообщений: 550



void __factcall button_click(TObject* Sender) не пробовал?

А вообще если это у тебя DLL то могут быть большие проблемы с передачей указателя между адресными пространствами (это когда будешь компилить без dinamic RTL)
joynter
Отправлено: 08.09.2004, 13:50


Станционный диспетчер

Группа: Участник
Сообщений: 137



оказалось всё просто, как три рубля:

TMethod Method;
Method.Code= button_click;
button->OnClick = *(TNotifyEvent*)&Method;

void button_click()
{
ShowMessage("...");
}

Guest
Отправлено: 08.09.2004, 14:17


Не зарегистрирован







Что то с памятью твоей станет ...
joynter
Отправлено: 08.09.2004, 14:40


Станционный диспетчер

Группа: Участник
Сообщений: 137



2Guest:
ты какую имеешь в виду?
Konstantine
Отправлено: 08.09.2004, 14:40


Мастер участка

Группа: Модератор
Сообщений: 545



QUOTE (joynter @ 08/09/2004, 14:52)
оказалось всё просто, как три рубля...

Лучше послушай Asher-а он дело говорит:
Функцию объяви как
CODE
void __factcall button_click(TObject* Sender)
и всё станет на свои места. А преобразование типа тем более ф-ции к добру не приведёт!!!
joynter
Отправлено: 08.09.2004, 14:58


Станционный диспетчер

Группа: Участник
Сообщений: 137



люди добрые, объясните, почему
CODE
void __fastcall button_click(TObject* Sender)

лучше, чем
CODE
void button_click()

где тут сермяжная правда?
Asher
Отправлено: 08.09.2004, 15:06


Мастер участка

Группа: Модератор
Сообщений: 550



Для того, чтобы так поступить
QUOTE
TMethod Method;
Method.Code= button_click;
button->OnClick = *(TNotifyEvent*)&Method;

вам TMethod вовсе не нужен. biggrin.gif
Если посмотреть в справку, то видим, что
QUOTE
struct TMethod
{
void *Code;
void *Data;
};

после чего разименованный указатель приводится к требуемому типу.
QUOTE
typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);

в вашем случае просто нехватало __fastcall и TObject* Sender в качестве параметров.
В принципе не понял где здесь DLL, но не суть важно.
при __fastcall первые три параметра передаются через регистры. (не все, но тоже не важно) и подпрограмма в праве ожидать их там. а без __fastcall все передает через стек. Это хорошо, что в вашем конкретном случае входных параметров нет. Инече можно было бы огрести по полной.
Asher
Отправлено: 08.09.2004, 15:10


Мастер участка

Группа: Модератор
Сообщений: 550



QUOTE
люди добрые, объясните, почему
void __fastcall button_click(TObject* Sender)
лучше, чем  
void button_click()
где тут сермяжная правда?


просто OnClick типа TNotifyEvent
QUOTE

__property Classes::TNotifyEvent OnClick = {read=FOnClick, write=FOnClick, stored=
IsOnClickStored};
joynter
Отправлено: 08.09.2004, 16:07


Станционный диспетчер

Группа: Участник
Сообщений: 137



спасибо за подробный ответ
Nick
Отправлено: 09.09.2004, 08:33


Машинист паровоза

Группа: Участник
Сообщений: 247



"Что то с памятью твоей станет..."

Прошу прощения
не знал об 3 параметрах

при __fastcall первые три параметра передаются через регистры. (не все, но тоже не важно) и подпрограмма в праве ожидать их там. а без __fastcall все передает через стек. Это хорошо, что в вашем конкретном случае входных параметров нет. Инече можно было бы огрести по полной.

я имел ввиду чудеса со стеком
joynter
Отправлено: 09.09.2004, 09:11


Станционный диспетчер

Группа: Участник
Сообщений: 137



извините за назойливость, но у меня происходит еще одна непонятная мне штука, а именно:
при закрытии формы, вызванной из библиотеки, закрыватся и главная форма (хотя в процессах она по-прежнему есть).
не могли бы господа программисты объяснить мне суть этого явления?

вот библиотека
CODE
//---------------------------------------------------------------------------

#include <vcl.h>
#include <windows.h>
#include <Forms.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------

#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
       return 1;
}
//---------------------------------------------------------------------------
extern "C" void __declspec(dllexport) CreateForm(TApplication*);

//---------------------------------------------------------------------------
void __fastcall button_click(TObject* Sender)
{
ShowMessage("кнопка нажата");
}
//***********************
void CreateForm(TApplication* any_application)
{
Application = any_application;
TForm *form = new TForm(Application);
form->Caption = "форма из библиотеки";
form->Height = 200;
form->Width = 300;
form->Position=poDefaultPosOnly;

TButton *button = new TButton(form);
button->Parent = form;
button->Height = 25;
button->Width = 76;
button->Top = form->Height — button->Height — 35;
button->Left = (form->Width — button->Width)/2;
button->Caption = "кнопка";

void *buffer;
buffer = button_click;
button->OnClick = *(TNotifyEvent*)&buffer;

form->ShowModal();
delete form;
}




вот вызывающая ее форма
CODE
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
typedef void __declspec(dllimport) DLL_Addr(TApplication*);
HMODULE hDLL=LoadLibrary("DLL_Project.dll");
if(hDLL)
{
DLL_Addr *CreateForm = (DLL_Addr*)GetProcAddress(hDLL, "_CreateForm");
if(CreateForm)
 CreateForm(Application);
else
 ShowMessage("функция CreateForm не найдена в DLL_Project.dll");
FreeLibrary(hDLL);
}
else ShowMessage("не могу загрузить DLL_Project.dll");
}

//---------------------------------------------------------------------------
pagan
Отправлено: 09.09.2004, 09:51


Ученик-кочегар

Группа: Участник
Сообщений: 22



Сначала перепишите свой код :
CODE
static TApplication *AppDLL;
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
   case DLL_PROCESS_DETACH: Application = AppDLL;
                            Application->Handle = NULL;
   return 1;
}
//---------------------------------------------------------------------------
void CreateForm(void *AppMain)
{
 if (! AppDLL)
 {
   Application->Handle = ((TApplication *)AppMain)->Handle;
   AppDLL = Application;
   Application = (TApplication *)AppMain;
 }
 //  ...


Объяснения чуть позже ...

Отредактировано pagan — 09/09/2004, 10:54
joynter
Отправлено: 09.09.2004, 11:01


Станционный диспетчер

Группа: Участник
Сообщений: 137



подозреваю, что
CODE

switch (reason)
{
case DLL_PROCESS_DETACH: Application = AppDLL;
                           Application->Handle = NULL;}


но после этих изменений ShowMessage("функция CreateForm не найдена в DLL_Project.dll");
pagan
Отправлено: 09.09.2004, 11:41


Ученик-кочегар

Группа: Участник
Сообщений: 22



Объяснения (как и обещал) : Во-первых я бы не рекомендовал вам передавать указатели на объекты VCL в явном виде, по причине того, что DLL с VCL мягко говоря не очень ладят. Лучше передавать их как безтиповые (void), а потом преобразовывать.
Важно понять, что у приложения свой тип GUI приложения (т.е. экземпляр TApplication), а у DLL свой (в отличие от пакетов packages, ну это уже другая история) ! Поэтому их необходимо, как бы сказать "дружить".
Далее — при передачи экземпляра TApplication — приложения в библиотеку нам нужно направить его на TApplication — этой библиотеки. Предварительно сохранив значение типа GUI нашей DLL в какую-нть переменную.
При выходе из DLL (FreeLibrary) нам остается только вернуть ей ее же значение TApplication. Надеюсь объяснил понятно.

Также советую ознакомиться (позволит понять основные принципы):http://borland.xportal.ru/forum/viewtopic.php?t=3130

З.Ы. то что вы не можете найти адресс своей ф-и говорит о том, что где-то неправильно дано ее объявление — проверьте хвост этой ф-и в *.cpp своего приложения — должно быть ...(void *). Удачи!
joynter
Отправлено: 09.09.2004, 13:07


Станционный диспетчер

Группа: Участник
Сообщений: 137



спасибо еще раз

Вернуться в Вопросы программирования в C++Builder