DLL i Form1

problemy z funkcjonowaniem bibliotek, komponentów itp.

DLL i Form1

Nowy postprzez duf » sobota, 12 czerwca 2010, 09:25

do projektu dll można dołączyć formę ( odkrycie! ) File->New->Form, ale gdy próbuję ją wywołać otrzymuję access violation:
DLL project.
Kod: Zaznacz cały
#include "Unit1.h"
extern "C" __declspec (dllexport) void Funkcja()
{
  Form1->Show();
}

Main cpp
Kod: Zaznacz cały
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  HINSTANCE DLLHandle = LoadLibrary(L"Projectmydll.dll");

   if(DLLHandle != NULL)
   {
      typedef (*aFunkcja)();

      aFunkcja Funkcja = (aFunkcja)GetProcAddress(DLLHandle, "_Funkcja");

      if( Funkcja != NULL) Funkcja();
      else ShowMessage( "Brak funkcji" );
   }
   else ShowMessage( "Lack of dll." );

   FreeLibrary(DLLHandle);
}

Czy jest to w ogóle możliwe takie wywołanie formy?
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez Cyfrowy Baron » sobota, 12 czerwca 2010, 14:22

duf napisał(a):
Kod: Zaznacz cały
#include "Unit1.h"
extern "C" __declspec (dllexport) void Funkcja()
{
  Form1->Show();
}


Tak nie można. W bibliotece DLL można wywoływać formularz, ale tylko dynamicznie. Więcej przeczytasz o tym w serwisie Cyfrowy Baron w dziale: teoria -> tworzenie dll.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez duf » sobota, 12 czerwca 2010, 15:36

A można wywołać formularz nie modalnie? Oczywiście dynamicznie.
Kod: Zaznacz cały
extern "C" __declspec (dllexport) void Funkcja()
{
  TForm1* newform = new TForm1(Form1);
  newform->Show();
}

Powstaje poważny błąd. Myślę, że ma to związek ze zwolnieniem biblioteki w głównej aplikacji. Jeżeli dobrze myślę to czy należałoby zwalniać bibliotekę dopiero po zamknięciu okna?
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez Cyfrowy Baron » sobota, 12 czerwca 2010, 15:55

Przy wywołaniu niemodalnym powstaje problem ze zwolnieniem biblioteki. Należałoby dodać do formularza w bibliotece funkcję, która w chwili jego zamknięcia wysyła komunikat do aplikacji, a ta dopiero wtedy zwalnia bibliotekę. Pewnie istnieje prostszy sposób, ale nigdy się nad tym nie zastanawiałem.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez duf » czwartek, 24 czerwca 2010, 10:47

Zgodnie z propozycją wyglądałoby to mniej więcej tak:
App
Kod: Zaznacz cały
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HINSTANCE DLLHandle = LoadLibrary(L"Project1.dll");

TForm* form;

if(DLLHandle != NULL)
{
     typedef TForm* (*aFunkcja)();

     aFunkcja Funkcja = (aFunkcja)GetProcAddress(DLLHandle, "_Funkcja");

     if( Funkcja != NULL ) form = Funkcja();
      else ShowMessage( "Lack of Funkcja" );
}
else ShowMessage( "Lack of dll." );

if ( !form ) return;

form->Close();

FreeLibrary(DLLHandle);
}


DLL
Kod: Zaznacz cały
extern "C" __declspec(dllexport) TForm* Funkcja()
{
  TForm1* newform = new TForm1(Form1);
  newform->Show();
  return newform;
}

Al to nie działa bo i nie może działać. Spróbowałem przesłać wskaźnik do dll ale też nic z tego:
App
Kod: Zaznacz cały
TForm* form;

typedef TForm* (*aFunkcja)(TForm**);
typedef void (*aClose)(TForm**);

if( Funkcja != NULL ) form = Funkcja( &form );

if ( !form ) return;

Close( &form );

FreeLibrary(DLLHandle);

DLL
Kod: Zaznacz cały
extern "C" __declspec(dllexport) TForm* Funkcja ( TForm** form )
{
  *form = new TForm1( Form1 );
  (*form)->Show();
  return *form;
}
void Close( TForm** form )
{
  //(*form)->Close();
  delete *form;
}

Wprawdzie okno powstaje nie modalne ale wraz z nim komunikat access violation.
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez Cyfrowy Baron » czwartek, 24 czerwca 2010, 11:02

Wprawdzie okno powstaje nie modalne ale wraz z nim komunikat access violation.


Jeżeli okno biblioteki wywołujesz jako niemodalne, a jednocześnie w aplikacji tuż po wywołaniu niemodalnego okna z biblioteki zwalniasz tą bibliotekę to nic dziwnego, że masz błąd.

Pisząc o wysyłaniu komunikatu miałem na myśli haki systemowe, a nie sprawdzanie co zwraca funkcja biblioteki, gdyż to akurat nie zadziała. Piszą o komunikatach chodzi mi o to, że przed zamknięciem okna biblioteki to okno wysyła komunikat np. za pomocą funkcji SendMessage do aplikacji, ta odbiera komunikat i dopiero wtedy zwalnia bibliotekę. W takim przypadku uchwyt do biblioteki DLLHandle musi być zadeklarowany jako globalny, gdyż aplikacja nie zwalnia go wewnątrz funkcji w której biblioteka została załadowana, lecz dopiero po odebraniu komunikatu. To oznacza, że aplikacja musi nasłuchiwać komunikatów, można do tego celu wykorzystać komponent TApplicationEvents.
Trochę to skomplikowane dlatego sądzę, że musi istnieć prostszy sposób.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez duf » czwartek, 24 czerwca 2010, 15:56

Zrobiłem to w ten sposób jak poniżej. Tylko mam obawy czy nie ma tu wycieku pamięci pomimo, że program zachowuje się bezproblemowo. Jedynym mankamentem jest to, że biblioteka zwalniana jest dopiero po zamknięciu głównej aplikacji. Martwi mnie jeszcze sprawa kilkukrotnego otworzenia i zamknięcia okna w dll. Czy tu nie ma wycieku pamięci.

APP
h
Kod: Zaznacz cały
TForm1* form;
typedef void (*aCloseForm)(TForm1**);
aCloseForm CloseForm;
HINSTANCE DLLHandle;


cpp
Kod: Zaznacz cały
void __fastcall TForm1::Button1Click(TObject *Sender)
{
DLLHandle = LoadLibrary(L"Project1.dll");

if(DLLHandle != NULL)
{
     typedef TForm1* (*aFunkcja)(TForm1**);

     aFunkcja Funkcja = (aFunkcja)GetProcAddress(DLLHandle, "_Funkcja");
     CloseForm = (aCloseForm)GetProcAddress(DLLHandle, "_CloseForm");

     if( Funkcja != NULL ) form = Funkcja( &form );
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  if ( form ) CloseForm( &form );
  FreeLibrary(DLLHandle);
}
//---------------------------------------------------------------------------


DLL
Kod: Zaznacz cały
#include "Unit1.h"
extern "C" __declspec(dllexport) TForm1* Funkcja(TForm1** form)
{
  if ( !form ) return NULL; 
  *form = new TForm1(Form1);
   Form1 = *form;
   (*form)->Show();
   return *form;
}

extern "C" __declspec(dllexport) void CloseForm( TForm1** form )
{
  if ( Form1 != NULL )
  {
     delete *form;
     *form = NULL;
     return *form;
  }
}

Unit1.cpp
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  Action = caFree;
  //delete Form1;
  Form1 = NULL;
}
//---------------------------------------------------------------------------
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez Cyfrowy Baron » czwartek, 24 czerwca 2010, 16:54

Nom... biblioteka jest zwalniana podczas zamykania aplikacji. Wystarczy w tej sytuacji wywołać FreeLibrary(DLLHandle) w zdarzeniu OnClose głównego formularza aplikacji, a cała ta reszta którą dodałeś jest zbędna. Mocno to przekombinowałeś.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez duf » czwartek, 24 czerwca 2010, 18:16

Cyfrowy Baron napisał(a):Wystarczy w tej sytuacji wywołać FreeLibrary(DLLHandle) w zdarzeniu OnClose głównego formularza aplikacji, ...

Niestety nie wystarczy.
Avatar użytkownika
duf
Intelektryk
Intelektryk
 
Posty: 175
Dołączył(a): czwartek, 9 października 2008, 13:02
Podziękował : 17
Otrzymał podziękowań: 2
System operacyjny: Windows 10
Kompilator: XE8
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez polymorphism » czwartek, 24 czerwca 2010, 19:56

A nie możesz po prostu załadować biblioteki w konstruktorze TForm1(aplikacji), a wyładować w destruktorze?

Kod: Zaznacz cały
TForm1* Funkcja(TForm1** form) { ... } 

Jaki jest sens parametru form, jeśli nic z niego nie wynika?

Kod: Zaznacz cały
 *form = new TForm1(Form1); 

Jak mniemam Form1 jest tym globalnym wskaźnikiem wygenerowanym przez IDE, problem w tym, że on na nic nie wskazuje, jeśli TForm1 jest tworzona w cytowany sposób. Z tego co pamiętam, DLL-ka, podobnie jak aplikacja, ma swój obiekt Application. Możesz go tam spokojnie podać jako właściciela okna.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: DLL i Form1

Nowy postprzez Cyfrowy Baron » piątek, 25 czerwca 2010, 07:22

duf napisał(a):Niestety nie wystarczy.

Wystarczy, wystarczy, przeczytaj uwagi polymorphism odnośnie tego TForm1, to zbędny element. Dlatego napisałem, że przekombinowałeś. By wywołać okno z biblioteki nie trzeba się tak gimnastykować, wystarczy zdefiniować w bibliotece okno i wywoływać je przez funkcję, wszystko co chcesz przekazać do okna biblioteki możesz robić przez argumenty funkcji.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Biblioteki i komponenty

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 3 gości

cron