[ FranjoZG @ 28.06.2022. 09:29 ] @
Delphi XE 10.1

U Dll-u sam kreirao formu i data modl. Testirano, radi ok.

U OnShow event-u forme (u Dll-u) otvaraka konekcije na bazu, postavlja neke parametre...

Prebacio sam prikaz forme u TabSheet-u, sada zablokira program. Forma se prikaže ok, ali je nedostupna, ne može se pristupiti niti jednoj edit kontroli na njoj. Još jednom: kada nisam postavljao formu na TabSheet, kada joj nisam odredio parent, sve je radilo OK.
Probao sam kreirati formu u glavnog programu, ne pozivati ovu iz Dll-a, na isti način je prikati na TabSheet-u, tada radi.
Debugirao sam Dll, OnShow prođe cijeli, nigdje ne blokira.

Iz osnovne forme:
Code:

  function IzOnlineUAdresar(ID: integer; ParentControl: HWND): integer; stdcall; external 'C:\projekti\Xe\MySQLConnection\Win32\Debug\MySQLConnection.dll';
...
   i := IzOnlineUAdresar(i, TabSheet2.Handle);
   if i > 0 then ShowMessage('New IO:' + i.ToString);


Funkcija u Dll-u:
Code:

  function IzOnlineUAdresar(id: integer; ParentControl: HWND): integer; stdcall;
  begin
          frmUpisUAdresar := TfrmUpisUAdresar.CreateParented(ParentControl);
    // ovo sam dodao, mada ne treba...
          frmUpisUAdresar.ParentWindow := ParentControl;
   // Ovako je radilo:
   //    frmUpisUAdresar := TfrmUpisUAdresar.Create(nil);
        result := frmUpisUAdresar.ShowModal;
  end;


Ima li tko pojma o čemu se radi? Forma mora biti u TabSheet-u. Sada sve testiram u XE 10.1, a kasnije će program koji poziva funkciju iz Dll-a biti u D2007.
[ Almedin @ 28.06.2022. 13:29 ] @
Kao je to zamišljeno da radi, forma u TabSheet-u a poziva se sa ShowModal?
[ FranjoZG @ 28.06.2022. 13:50 ] @
Mora se blokirati ostatak programa dok se ne završi obrada na formi iz Dll-a. Obrada vrati ID koji mi je kasnije protreban i kad njega obradim, može se koristiti ostatak programa.
Može bilo koje drugo rješenje, ovo mi je prvo palo na pamet...
[ Almedin @ 28.06.2022. 14:06 ] @
Zašto mora biti u TabSheet-u?
[ savkic @ 28.06.2022. 14:15 ] @
Forma je u dllu a glavna aplikacija u nezavisnom programu?

Ne moze to tek tako, VCL zavisi od TApplication i mnogih stvari a tu se desava da dll nema veze sa VCL/TApplication u glavnom programu.

Moras da radis kao da su to programi radjeni u Delphiju i C++, cist WinApi i Handle (HWND).

Probaj da formu u dllu napravis sa CreateParented i prosledis HWND parenta iz glavnog programa, sto je verovatno TabPage. Eventualno da napravis formu pa da onda setujes ParentWindow.
[ FranjoZG @ 28.06.2022. 16:19 ] @
Forma je u dll-u, a gnalvna app je u programu koji poziva taj dll.
Probao sam i sve radi ako radim show forme, ako radim showmodal tada blokira.
Probao sam sa CreateParented, provjerio sam HWND koji dođe u dll - ispravan je, ista priča - blokira. Isto je kao ako napravim Create, a kasnije dodijelim parent.
Provjeravao sam OnShow forme jer se tamo sve događa (učitavnja podataka iz baze, append u tablicu...). Prođu sve naredbe i nakon toga blokira.

Forma mora biti na tab-u jer je takav program, mora izgledati kao da je sastavni dio glavnog programa. Zbog nekih stvari koje ima u Xe, a nema u D2007 sam tako krenuo. Mogao sam zaobići, a sada mi se ne da raditi sve ispočetka, a i volio bih shatiti kako to napraviti.
[ Almedin @ 28.06.2022. 17:41 ] @
Radi se o tome da ne možeš raditi ShowModal formi koja je u TabSheet-u, taman i da je forma u istoj aplikaciji. Moraš promijeniti logiku. Nije jasno šta tačno želiš postići sa ShowModal.
[ bokinet @ 28.06.2022. 22:42 ] @
Postoji osnovna razlika izmedju Show i ShowModal oko formi koja je da ovaj drugi nacin prikaza forme prikazuje formu po sistemu pitstop-a i privremenog zaustavljanja izvrsavanja koda dok se forma ne zatvori tj. ne izvrsi neka operacija/vrati neka povratna vrednost.

Prost primer MessageBox.
[ Milan Milosevic @ 29.06.2022. 04:55 ] @
Probaj da blokiraš rad programa na neki drugi način i da izbegneš ShowModal.
Možda je duži put, ali rešićeš se frusrtacije u konačnom, pa kasnije probaj da nađeš rešenje.
Recimo da ISključiš glavnu formu pri pokretanju forme iz dll, a da je ponovno uključiš kod zatvaranja pomoćne forme
Code:

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
   if Form2 = nil then  Form2:= TForm2.Create(self);
    Form2.Visible:=true;
    Form1.Enabled:=false;
end;

.....

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
  Form1.Enabled:=true;
 Form2:=nil;
end;





[Ovu poruku je menjao Milan Milosevic dana 29.06.2022. u 06:17 GMT+1]
[ Almedin @ 29.06.2022. 06:09 ] @
Problem je sto njemu iz nekog razloga forma treba u TabSheet-u i vjerovatno treba onemogućiti sve akcije na toj formi gdje je TabSheet.
[ FranjoZG @ 29.06.2022. 08:30 ] @
Eto, jedan dan popodne da ne palim komp....

Ta forma iz dll-a mora biti u tabshet-u jer je osnovni program tako koncipiran, ne mogu to mijenjati. Možda da na tabsheet postavim panel pa na njega novu formu. Bi li to što promjenilo?

Onako kako je napisao Milosevice sam probao napraviti, radi, ali je sada drugi problem: kako da znam da je ta forma iz dll-a zatvorena? Na njoj imam dva gumba: "Upiši" i "Odustani". Oni ili upišu podatke ili zaborave promjene i zatvore formu. Nakon toga se kontrola predaje osnovnom programu.
Ono što se radi na toj formi je dosta osjetljivo i ne želim ostaviti mogućnost da bilo što stranka promjeni na podacima dok se ne završi upis, a ako ostavim mogućnost, kladim se da hoće bez obzira što im kažem...

Sada mi je palo na pamet, idem probati: PageControl je na formi u osnovnom programu, preko cijele forme. Probat ću formu iz dll-a kreirati na toj formi i sakriti cijeli pagecontrol dok se ne završi posao na novoj formi...

U neke klase koje sam kreirao sam prosljeđivao procedure iz osnovne forme koje su se izvršavale u određenim uvjetima, a pozivale su se unutar klase. Može li tako i sa formom koja je u dll-u? Ako može, rješio sam problem: show forme, proslijedim joj proceduru iz osnovne forme koja se izvrši na gumb...
[ FranjoZG @ 29.06.2022. 10:14 ] @
ShowModal definitinvno ne prolazi...
Rješio sam tako da kreiram u osnovnom programu proceduru koja odradi što treba nakon zatvaranja forme iz dll-a.
Sada se pojavio drugi problem:

Testirao sam tako što sam kreirao formu u test programu, van dll-a i napravio s njom što treba - radi OK. Kada sam to napravio s formom u dll-u javlja mi: "Control frmUpisUAdresar' has no parent window"
Potpuno jednako sam napravio kao s formom koja radi.
u osnovnom programu:
Code:

   DBGrid1.Visible := false;
   frmProbaUpisa := tfrmProbaUpisa.Create(nil);
   frmProbaUpisa.Parent := TabSheet1;
   frmProbaUpisa.ProcGotovo := Gotovo;
   frmProbaUpisa.Show;


Za formu u dll-u:
U osn. programu:
Code:

   i := qWebID.AsInteger;
   DBGrid1.Visible := false;
   i := IzOnlineUAdresar(i, Application, TabSheet1, Gotovo);
   if i > 0 then ShowMessage('New IO:' + i.ToString);

u dll-u:
Code:

function IzOnlineUAdresar(id: integer; Owner: TApplication; ParentControl: TWinControl; ProcKraj: tGotovo): integer; stdcall;
begin
        frmUpisUAdresar := TfrmUpisUAdresar.Create(nil);
        frmUpisUAdresar.Parent := ParentControl; // ova linija javlja grešku
        frmUpisUAdresar.ProcKraj := ProcKraj;
        frmUpisUAdresar.Show;
end;

[ Milan Milosevic @ 29.06.2022. 11:46 ] @
Jedostavno disable sve komponente koje ti netrebaju na formi kad prkažeš formu iz dlla, i ponovno ih uključi kada formu obrišeš.
Nemaš valjad hiljadu edit polja i dugmeta na formi. Ukoliko ih imaš previše možeš da vršiš prebrojavanje svih komponenata na formi i tako da ih isključiš ili uključiš.
[ FranjoZG @ 29.06.2022. 11:49 ] @
Milane, nism shvatio. Diseble komponenti na formi u osnovnom programu ili na formi iz dll-a? Kako će to utjecati na poruku da forma iz dll nema parent window?
[ Milan Milosevic @ 29.06.2022. 12:21 ] @
Citat:
FranjoZG: Milane, nism shvatio. Diseble komponenti na formi u osnovnom programu ili na formi iz dll-a? Kako će to utjecati na poruku da forma iz dll nema parent window?

Sad ja tebe nisam razumeo?

Ako sam dobro shvatio ti imaš Formu u bibljoteci koju pozivaš iz svoje aplikacije i lepiš je na TabSheet koji se nalazi na glavnoj formi aplikacije.
Želiš da korisnik ne može da menja ništa drugo dok ne odabere i klikne neko od dva dugmeta u dll formi.
Kad odabere, verovatno se nešto događa i dll forma se gasi, a sve ostale opcije su ponovo dostupne?
Ako na to misliš onda kad aktiviraš dll formu, isključiš sve ostale komponente na glavnoj formi.
Kad ugasiš dll formu onda opet uključiš sve elemente na glavnoj formi.
[ FranjoZG @ 29.06.2022. 12:33 ] @
Milane, to je jasno. Rijšio sam. Sada mi je problem što mi forma iz dll-a javlja da nema parent window u trenutku kada kažem:
frmUpisUAdresar.Parent := ParentControl;
ParentControl je tabsheet kao parametar koji prosljeđujem u dll funkciju gdje se kreira forma.
[ Milan Milosevic @ 29.06.2022. 12:40 ] @
Probaj sa
Code:

Function MilSetParent(hWndChild: THandle; hWndNewParent: THandle): THandle;
  stdcall; external 'user32.dll' name 'SetParent';


da podesiš parent.
[ Almedin @ 29.06.2022. 13:06 ] @
Funkciji u dll proslijedi HWND i kreiraj sa CreateParented.
[ FranjoZG @ 29.06.2022. 13:11 ] @
Almedin: probao, javlja istu grešku...
[ Almedin @ 29.06.2022. 13:41 ] @
Dll
Code:
library DllForm;

uses
  SysUtils,
  Classes,
  Windows,
  frmDll in 'frmDll.pas' {Form1};

{$R *.res}

procedure Dll_CreateForm(AParent: HWND);
var
  f: TForm1;
begin
  f := TForm1.CreateParented(AParent);
  f.Show;
end;

exports
Dll_CreateForm;

begin

end.


App
Code:
unit frmMain;

interface

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

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

procedure Dll_CreateForm(AParent:HWND); external 'DllForm.dll';

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Dll_CreateForm(Panel1.Handle);
end;

end.


Ovo radi kod mene.
[ FranjoZG @ 30.06.2022. 12:17 ] @
Hvala Almedin, radi. Probao sam to, ali sam očito nešto propustio...

Sada imam novi problem! Testiranje sam radio tako što sam test program i dll radio u Delphi XE 10.1 Sada pokušavam dll ugraditi u program koji je rađen sa Delphi 2007.
Javlja mi greške. Provjerio sam parent koji šaljem u dll na kom se mora prikazati forma iz dll-a. To sam prmjenio, više nije tSheet već je forma iz osnovnog programa. Probano u testu - radi. Kada to napravim sa D2007, javalja greške, a naziv forme (drugačije ne mogu provjeriti što dobije dll) je nečitljiv (kineska slova).

Javlja čudno grešku: "EReadError, Error reading edNeki.Items.Strings: sysem error. Code: 1400. Invalid window handle"
kontrola edNeki je TDBComboBox sa zadanim stavkama.

Šaljem formu, a ne Handle forme jer moram preuzeti OnREsize forme iz glavnog programa da bi mi se forma iz dll-a ispravno prikazala pri promjeni veličine.

Dll učitavam dinamički. Ovo je definicija funkcije:
Code:

  tIzOnlineUAdresar = function(ID: integer; Owner: TApplication; ParentControl: TForm; PorcKraj: tGotovo): integer; stdcall;

ProcKraj je proc. iz osnovnog programa koje se poziva kada se završi rad na formi iz dll-a i kada se ta forma zatvori.
[ Almedin @ 30.06.2022. 12:23 ] @
Nemoj raditi tako. OnResize napravi u dll formi i postavi joj Align na alClient.
[ FranjoZG @ 30.06.2022. 12:37 ] @
Kako da znam u dll-u da je osnovna forma napravila resize ako ne preuzmem njezin OnResize?
[ Almedin @ 30.06.2022. 12:39 ] @
Tako sto postaviš Align na alClient i forma u dll ce se sama resizati.
[ Almedin @ 30.06.2022. 12:41 ] @
A može i drugačije, ako tinto ne odgovara. U dll kreiras i exportujes funkciju npr Dll_FormResize(w, h: integer) i pozivas je iz glavnog programa.
[ FranjoZG @ 30.06.2022. 14:49 ] @
Rješio sam manje-više sve. Radi ok. Sada se javlja problem koji ne znam kako riješiti. Zakuhao sam si bez veze, moglo je i drugačije, ali mi je u trom trenutku izgledalo baš zgodno rijšiti to sa dll-om...
Prilikom zatvaranja glavnog programa javlja mi "Acces violation at adress... in module 'Msftedit.dll'"

Koliko vidim po net-u radi se o richedit kontroli. Nigdje je ne koristim !!!

Dinamički pozivam dll:
Code:

      MySqlHandle := loadLibrary('C:\projekti\Xe\MySQLConnection\Win32\Debug\MySQLConnection.dll');
       @MyIZOnlineUAdresar := GetProcAddress(MySqlHandle, 'IzOnlineUAdresar');
       MyIZOnlineUAdresar(qWebID.AsInteger, Application, Form4.Handle, Gotovo); 


Procedura "gotovo" je us glavnom programu, a poziva se na gumb u formi iz dll-a: "Upis" ili "Odustani".
Code:

   FreeUpisUAdresar;
   if form4.MySqlHandle <> 0 then begin
      FreeLibrary(form4.MySqlHandle);
      form4.MySqlHandle := 0;
   end;
   Form4.UpisStarted := false;
   if Odgovor > 0 then ShowMessage('Upisano') else ShowMessage('NIJE upisano');


Procedure "FreeUpisUAdresar" je u dll-u:
Code:

    if Assigned(frmUpisUAdresar) then 
       FreeAndNil(frmUpisUAdresar);
    if Assigned(dm) then
       FreeAndNil(dm);   


Nigdje se na javlja greška, osim kada zatvaram cijeli program.
[ Almedin @ 30.06.2022. 15:09 ] @
U proceduri gotovo uništavaš formu iz koje je prozivaš?
[ FranjoZG @ 30.06.2022. 15:20 ] @
U jednoj proceduri osnovnog programa
- učitavam dll,
- pozivam proceduru u dll-u koja kreira formu

U drugoj proceduri u osnovnom prog.
- pozivam proceduru iz dll-a koja uništava formu
- radim freelebrary

Te provedure ne javljaju greške, greška se javlja kad zatvaram program.

[Ovu poruku je menjao FranjoZG dana 30.06.2022. u 17:48 GMT+1]
[ Almedin @ 30.06.2022. 17:32 ] @
Šta radi procedura "gotovo" i odakle se poziva?
[ Milan Milosevic @ 01.07.2022. 06:18 ] @
Citat:
Te provedure ne javljaju greške, greška se javlja kad zatvaram program.

Verovatno oslobađaš nešto što ne postoji.
[ FranjoZG @ 01.07.2022. 08:32 ] @
Porc. "gotovo" je u osnovnom programu, prosljeđujem ju formi u dll-u. Iz forme se pozivana nakon klika na gumbe "Upiši" ili "Odustani". Ako se klikne na upiši - vraća ID novog zapisa, a ako se klikne na odustani - vraća -1.
Kreiranje, upis i destroy forme u dll-u radi ok, više puta uzastopno, ne javlja grešku. Greška se javlja kada zatvram osnovnu formu, tj. program. Prije toga pozivam "gotovo". U OnClose osnoven forme nema ništa pametno niti išta što bi moglo izazvati grešku...

Nemam više ideje gdje tražiti grešku. Koliko vidim po net-u, taj 'Msftedit.dll' ima veze sa richedit kontrolom, a nju ne koristim nigdje u test programu. Još ću probati izbaciti JVCL kontrole (datetimepicker) i staviti delphi-jeve.

Code:

procedure Gotovo(Odgovor: integer);
begin
   FreeUpisUAdresar; // proc. u dll-u koja uništava formu i data modul
   if form4.MySqlHandle <> 0 then begin 
      FreeLibrary(form4.MySqlHandle);
      form4.MySqlHandle := 0;
   end;
   Form4.UpisStarted := false;  // indikator da nije aktivna forma iz dll-a
   if Odgovor > 0 then ShowMessage('Upisano') else ShowMessage('NIJE upisano');
end;


proc. FreeUpisUAdresar (u dll-u)
Code:

  procedure FreeUpisUAdresar;
  begin
    if Assigned(frmUpisUAdresar) then 
       FreeAndNil(frmUpisUAdresar);
    if Assigned(dm) then
       FreeAndNil(dm);   
  end;


Proc. u osnovnom programu:
Code:

procedure TForm4.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   if UpisStarted then begin
     ShowMessage('Zatvorite upis');
     Action := caNone;
   end else Action := caFree;
end;


Našao sam u čemu je problem !!! Glava pa u zid... U formi (u dll-u) kreiram datamodul, a nigdje ga ne uništavam. Kad sam stavio dm.free sve radi i ne javlja grešku. Mada, prilično glupa poruka.

[Ovu poruku je menjao FranjoZG dana 01.07.2022. u 10:47 GMT+1]
[ Almedin @ 01.07.2022. 11:37 ] @
Pa imaš FreeAndNil(dm) koji uništava dm.
[ FranjoZG @ 03.07.2022. 18:41 ] @
Ovo kao da je ukleto, popravim jedno - ne radi drugo...
U petak nije bilo te greške. Vjerojatno sam nešto izmjenio, ali ne znam što. Vratio sam na staro sve čega sam se sjetio.

Forma iz dll-a ne prihvata ENTER.
Poziv iz glavnog programa:
Code:

procedure tForm4.Button1Click(Sender: TObject);
var i: integer;
begin
   i := qWebID.AsInteger;
   DBGrid1.Visible := false;
   UcijajFunk;
   IzOnlineUAdresar(i, Application, Form4.Handle, Gotovo);
end;


Kod u dll-u (ima viška koda, čistit ću kasnije):
Code:

        frmUpisUAdresar := TfrmUpisUAdresar.CreateParented(ParentControl);
        frmUpisUAdresar.IDUnosa := id;                 
        frmUpisUAdresar.Left := 0;
        frmUpisUAdresar.Top := 0;
        frmUpisUAdresar.WindowState := wsMaximized;
        frmUpisUAdresar.Align := alClient;
        Application.ProcessMessages;
        frmUpisUAdresar.Show;
        frmUpisUAdresar.Align := alClient;
        frmUpisUAdresar.Anchors := [akLeft, akTop, akBottom, akRight];
        frmUpisUAdresar.ProcKraj := ProcKraj;
        Application.ProcessMessages;
        frmUpisUAdresar.dbeJMBG.SetFocus;


kod u unit-u forme:
Code:

procedure TfrmUpisUAdresar.FormActivate(Sender: TObject);
begin
   ShowMessage('activate');
   PrikaziPodatke;
end;

procedure TfrmUpisUAdresar.dbeJMBGKeyPress(Sender: TObject; var Key: Char);
begin
   if Key = #13 then SelectNext(sender as TWinControl, true, true);
end;


Poroc. PrikaziPodatke učitava podatke iz baze...

GREŠKA:
- kursor je u tdbEdit-u "dbeJMBG"
- pritiskom na slova aktivira se OnKeyPress, dbeJMBG prihvaća unos
- pritiskom na ENTER aktivir se gumb iz glavnog programa "tForm4.Button1Click" i ide na ponovno kreiranje forme iz dll-a
- TAB kreće po kontrolama glavnog programa, a ne po vidljivoj formi iz dll-a.

Pokušao sam proceduru u kojoj se kreira forma promjeniti u funkciju koja vraća TWinControl, pa u glavnog programu dodao: NovaForm.SetFocus; nište se ne mijenja

Izgleda mi kao da je Button1 zadržao fokus.

Probao sam na obje forme staviti:
Code:

KeyPreview := true;

Ne pokrene se OnKeyPress na niti jednoj formi.



[Ovu poruku je menjao FranjoZG dana 03.07.2022. u 20:37 GMT+1]
[ FranjoZG @ 04.07.2022. 09:59 ] @
Još jedna zanimljiva pojava:
na osnovnoj formi imam nekoliko gumba, TEdit i TDBLookupComboBox. Nakon prikaza forme iz dll-a i postavljanja kursora na neko polje za unos, TAB mi se kreće po osnovnoj formi, a ne po formi iz dll-a. Ako s tab-om postavim fokus na TEdit ili TDBLookupComboBox tada se na formi iz dll-a, nakon pritiska na ENTER aktivira OnKeyPress, a ako je aktivan gumb na osnovnoj formi, forma iz dll-a ne doživljava ENTER.

Ima li tko ideju o čemu se radi. Rokovi su me davno prestigli...
[ savkic @ 06.07.2022. 05:16 ] @
Ovo vec ima veze kako VCL handluje keyboard u embeded formama, vidi da stavis OnShorcut event na dll formu (iskljuci KeyPreview na glavnoj) i proveri da li se poziva za enter. Ako ne onda stavi OnShortcut u glavnoj formi (isprobaj razne kombinacije KeyPreview).

Ako se event poziva za pritisak na Enter onda ga ili tu hendluj (proveri da li je aktivan edit koji ti treba) ili pusti kroz debugger i udji u VCL kod i gledaj red po red gde dalje ide na izvrsavanje (ActionList, MainForm, form, kontrola, application...) pa ga tamo hvataj.
[ tkaranovic @ 06.07.2022. 13:27 ] @
Da dodam:

Pravio sam sa WebBrowser komponentom slicno prikazivanje ali to je poseban slucaj radilo je kao odbojen progra.
Recimo kao je fokus na WebBrowser posle alt i enter se pojavi meni main prozora.
Znaci ne prva stavka u main meniju nego default meni prozora koji se pojavljuje kad se klikne na ikonu prozora.
Ako tako radi i dll radu slicno. Ako ni to ne radi onda radi bas razlicito iz dll.

Inace jos uvek pisem i gledam ove poruke sa WebBrowser komponentom.

Plus: Application ima kreiranje forme (CreateForm) i kad bi se tako mogla kreirati mozda bi drugacije radila.