Jump to content

Connect TFrame from BPL to MainForm


artem_niko

Recommended Posts

Hello!

I want load BPL, as plugin, where I create, in this BPL, one Frame1 with component of TUniLabel1.

I need load this BPL, that then press on TUniButton on my MainForm and then set TUniLabel1.Caption:=<value from MainForm>.

This is my code in MainForm, he succsess work and load BPL:

procedure TMainForm.LoadModuleFromBPL;
var
  UniFormLoadedModule: TUniFrame;
  AClass: TPersistentClass;
  LoadedBPL: HModule;
begin
  LoadedBPL := LoadPackage(ExtractFilePath(ParamStr(0)) + 'Test.bpl');
  if LoadedBPL <> 0 then
  begin
    AClass := GetClass('TUniFrame1');
    UniFormLoadedModule:=TComponentClass(AClass).Create(UniTabSheet1) as TUniFrame;
    UniFormLoadedModule.Parent:=UniTabSheet1;
    UniPageControl1.ActivePage := Ts;
  end;
end;

This is code in my Frame1, in my BPL:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, uniGUITypes, uniGUIAbstractClasses,
  uniGUIClasses, uniGUIFrame, uniGUIBaseClasses, uniLabel;

type
  TUniFrame1 = class(TUniFrame)
    UniLabel1: TUniLabel;
    procedure UniFrameReady(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


implementation

  uses MainModule, ServerModule, Main, UnitPDFViewer;

{$R *.dfm}


procedure TUniFrame1.UniFrameReady(Sender: TObject);
begin
  UniLabel1.Caption:=UniMainModule.LoggedUser;
end;

initialization
  RegisterClass(TUniFrame);


end.

He does not work because when I compile my BPL, I give this error:

"[dcc32 Error] E2223 $DENYPACKAGEUNIT 'UniGUIVars' cannot be put into a package"

What I must do?

Link to comment
Share on other sites

  • 6 months later...

Hello to all!

At the moment, I do that what.

This is code of my Package1.bpl:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, uniGUITypes, uniGUIAbstractClasses,
  uniGUIClasses, uniGUIFrame, uniGUIBaseClasses, uniLabel;

type
  TUniFrame1 = class(TUniFrame)
    UniLabel1: TUniLabel;
    procedure UniFrameCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

implementation

{$R *.dfm}

procedure TUniFrame1.UniFrameCreate(Sender: TObject);
begin
  UniLabel1.Caption:=TimeToStr(MainForm.nowTime);
end;

initialization
  RegisterClass(TUniFrame);


end.

And this is code in my MainForm, in my Application:

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, uniGUITypes, uniGUIAbstractClasses,
  uniGUIClasses, uniGUIRegClasses, uniGUIForm, uniButton, uniGUIBaseClasses,
  uniEdit, uniPageControl, uniGUIFrame, uniPanel, uniTimer;

type
  TMainForm = class(TUniForm)
    UniEdit1: TUniEdit;
    UniButton1: TUniButton;
    UniPageControl1: TUniPageControl;
    UniTabSheet1: TUniTabSheet;
    UniTimer1: TUniTimer;
    procedure UniButton1Click(Sender: TObject);
    procedure UniTimer1Timer(Sender: TObject);
    procedure UniEdit1Change(Sender: TObject);
  private
    FPackageHandle: Integer;
    { Private declarations }
  public
    nowTime: TDateTime;
    { Public declarations }
  end;

function MainForm: TMainForm;

implementation

{$R *.dfm}

uses
  uniGUIVars, MainModule, uniGUIApplication;

function MainForm: TMainForm;
begin
  Result := TMainForm(UniMainModule.GetFormInstance(TMainForm));
end;

procedure TMainForm.UniButton1Click(Sender: TObject);
var
  AClass: TClass;
  AFrame: TUniFrame;
begin
  FPackageHandle:=0;
  if FPackageHandle = 0 then
  begin
    FPackageHandle:=LoadPackage('Package1.bpl');
    AClass:=GetClass('TUniFrame1');
      if Assigned(AClass) {and AClass.InheritsFrom(TUniFrame)} then
      begin
        AFrame:=TCustomFrameClass(AClass).Create(UniTabSheet1) as TUniFrame;
        AFrame.Parent:=UniTabSheet1;
        AFrame.Align:=alClient;
        AFrame.Show;
      end;
  end;
end;

procedure TMainForm.UniEdit1Change(Sender: TObject);
begin
  nowTime:=StrToTime(UniEdit1.Text);
end;

procedure TMainForm.UniTimer1Timer(Sender: TObject);
begin
  UniEdit1.Text:=TimeToStr(Now);
end;

initialization
  RegisterAppFormClass(TMainForm);

end.

I have not get errors and my App and Package1.bpl successfuly compiling and my UniFrame1 creating in my App.

What I want? I want this: in my App exist something global variables with something values and I want tranfer this values of this variables, for example, to UniLabel1.Caption in my created UniFrame1. What I  must do, that it is work? Please, help me, who know how do this!

Link to comment
Share on other sites

  • 1 year later...

Hello!

Can anybody help me create connect between MainProject and BPL, using UniGUI?

In attach two project. 

What I want? I want connect BPL in MainProject and get in connected BPL global value from MainProject (from UniEdit1).

Please, help me with this question! 🙏

Test.zip

Link to comment
Share on other sites

Se você quiser comunicação entre os objetos envolvidos, eles devem ter métodos que podem ser lidos ou escritos.
Se você está no quadro e quer obter valor a partir do principal, você deve ter um método público no principal que lhe dá acesso e assim por diante.

  • Like 1
Link to comment
Share on other sites

17 hours ago, herculanojs said:

Se você quiser comunicação entre os objetos envolvidos, eles devem ter métodos que podem ser lidos ou escritos.
Se você está no quadro e quer obter valor a partir do principal, você deve ter um método público no principal que lhe dá acesso e assim por diante.

Excellent, dear @herbernlopez! It's working! 🙏😃

Thank's! 

If I will have some question about this theme, I ask you!

Now, I'm going think about new architecture of my project! 

 

 

P.S.

And I still have a couple of questions:
1. If I add any forms, etc. to the BPL, will they receive a string value from my frame, which was connected as a BPL in the main project?
2. What is the best way to develop a BPL: launch the IDE separately or use the menu in the screenshot above and add it as a file in the main project, working in one IDE?

image.png.87e5c8641ca510da2a14fd86258a17f9.png

3. How to recompile the BPL so that it can be loaded again in the main project without restarting the main project?
I see the algorithm of actions as follows:
1. Make changes to the BPL (add some components, code, expand its functionality);
2. Compile the BPL file somewhere;
3. Copy the compiled BPL to the folder where the main project looks for my BPL files;
4. I click on the button in the main project and my BPL is loaded again, but the main project does not close and does not restart.

There are two problems right now that I cannot fix:
1. It is not possible to unload all packages and classes first (added the DoUnloadPackage function to the main project);
2. And it is not possible to compile the BPL itself, tk. if you tell it the directory where to save, for example, like here:

image.thumb.png.ddc953013c6df377c16e3f4ebe4454ba.png
then a message is displayed that cannot be compiled. I believe this is due to the fact that the main project does not unload the loaded BPL file that I am trying to update.

In general, please help with the elimination of problem number 1, or maybe problem number 2 will go away by itself later.

If not for question # 3, everything works, BPL is loaded, but you have to restart the main project, which is wrong ... 🤔

Test_new.zip

Link to comment
Share on other sites

On 8/22/2021 at 9:32 PM, Артем said:

Excellent, dear @herbernlopez! It's working! 🙏😃

Thank's! 

If I will have some question about this theme, I ask you!

Now, I'm going think about new architecture of my project! 

 

 

P.S.

And I still have a couple of questions:
1. If I add any forms, etc. to the BPL, will they receive a string value from my frame, which was connected as a BPL in the main project?
2. What is the best way to develop a BPL: launch the IDE separately or use the menu in the screenshot above and add it as a file in the main project, working in one IDE?

image.png.87e5c8641ca510da2a14fd86258a17f9.png

3. How to recompile the BPL so that it can be loaded again in the main project without restarting the main project?
I see the algorithm of actions as follows:
1. Make changes to the BPL (add some components, code, expand its functionality);
2. Compile the BPL file somewhere;
3. Copy the compiled BPL to the folder where the main project looks for my BPL files;
4. I click on the button in the main project and my BPL is loaded again, but the main project does not close and does not restart.

There are two problems right now that I cannot fix:
1. It is not possible to unload all packages and classes first (added the DoUnloadPackage function to the main project);
2. And it is not possible to compile the BPL itself, tk. if you tell it the directory where to save, for example, like here:

image.thumb.png.ddc953013c6df377c16e3f4ebe4454ba.png
then a message is displayed that cannot be compiled. I believe this is due to the fact that the main project does not unload the loaded BPL file that I am trying to update.

In general, please help with the elimination of problem number 1, or maybe problem number 2 will go away by itself later.

If not for question # 3, everything works, BPL is loaded, but you have to restart the main project, which is wrong ... 🤔

Test_new.zip 944,84 kB · 0 downloads

You have to see how you will implement your scenario to avoid such problems.
1) You can upload the BPL and after using it download it. This would avoid the issue of not being able to update.
Without downloading the BPL, unfortunately, you will not be able to perform its update, and would have to be dropping the application to be able to perform this maintenance. So you have to think carefully about the construction of the project.

You can also place updates in a verification directory for the application to read. When it finds a new update, it prompts open sessions to exit or sets a time for automatic termination. After the end of all sessions, then the application unloadpackages the loaded BPLs and properly replaces the new ones.

Do not place the application running directly in the Delphi working directory where you compile the BPLs. Try to leave the test application running in another location.

Link to comment
Share on other sites

13 hours ago, herculanojs said:

Вы должны посмотреть, как вы будете реализовывать свой сценарий, чтобы избежать таких проблем.
1) Вы можете загрузить BPL и после его использования загрузить его. Это позволит избежать проблемы невозможности обновления.
Без загрузки BPL, к сожалению, вы не сможете выполнить его обновление, и вам придется отказаться от приложения, чтобы иметь возможность выполнять это обслуживание. Поэтому вам придется тщательно подумать о строительстве проекта.

Можно также поместить обновления в каталог проверки для чтения приложением. Когда он находит новое обновление, он предлагает открытым сеансам выйти или устанавливает время для автоматического завершения. После окончания всех сеансов приложение выгружает загруженные BPL и корректно заменяет новые.

Не размещайте приложение, выполняемое непосредственно, в рабочий каталог Delphi, в котором компилируются BPL. Попробуйте оставить тестовое приложение запущенным в другом месте.

Good day!
Thank you very much for the answer.
Do you mean to unload the BPL immediately after loading it in the main project? Can you show an example when uploading BPL? Because the code that I used, it does not work.

Link to comment
Share on other sites

17 hours ago, Артем said:

Good day!
Thank you very much for the answer.
Do you mean to unload the BPL immediately after loading it in the main project? Can you show an example when uploading BPL? Because the code that I used, it does not work.

You cannot download a package while using resources from the package.

Link to comment
Share on other sites

6 hours ago, herculanojs said:

You cannot download a package while using resources from the package.

I'm already understand this.

Can you show how you unload package? How right do this.

In future, I will show to user message when new package will be create and then user make unload package and load again.

But I need example how unload package.

Link to comment
Share on other sites

3 minutes ago, herculanojs said:

function unloadPackage()

This?

procedure TMainForm.DoUnloadPackage(Module: HModule);
var
  i: Integer;
  M: TMemoryBasicInformation;
begin
  { Make sure there aren't any instances of any
    of the classes from Module instantiated, if
    so then free them.  (This assumes that the
    classes are owned by the application) }

  for i := Application.ComponentCount - 1 downto 0 do
  begin
    VirtualQuery(
      GetClass(Application.Components[i].ClassName),
      M, SizeOf(M));
    if (Module = 0) or
      (HMODULE(M.AllocationBase) = Module) then
      Application.Components[i].Free;
  end;
  UnRegisterModuleClasses(Module);
  UnLoadPackage(Module);
end;

procedure TMainForm.UniButton1Click(Sender: TObject);
var
  hm:Hmodule;
  FrC : TUniFrameClass;
  Frame : TUniFrame;
begin
  hm := LoadPackage('Package1.bpl');
  if hm <> 0 then
  begin
    if FindClass('TUniFrameTest') <> nil then
    begin
      FrC := TUniFrameClass(FindClass('TUniFrameTest'));
      if FrC <> nil then
      begin
        frame := FrC.Create(self);
        frame.Align := alClient;
        frame.Parent := UniTabSheet1;

        if frame <> nil then
        begin
          if IsPublishedProp(frame,'GlobalValue') then SetPropValue(frame,'GlobalValue',UniEdit1.Text);
        end;
      end;
     end;
  end
  else
  begin
    //Unload package:
    DoUnloadPackage(hm);
  end;
end;

 

Link to comment
Share on other sites

2 minutes ago, Артем said:

Este?


procedure TMainForm.DoUnloadPackage(Module: HModule);
var
  i: Integer;
  M: TMemoryBasicInformation;
begin
  { Make sure there aren't any instances of any
    of the classes from Module instantiated, if
    so then free them.  (This assumes that the
    classes are owned by the application) }

  for i := Application.ComponentCount - 1 downto 0 do
  begin
    VirtualQuery(
      GetClass(Application.Components[i].ClassName),
      M, SizeOf(M));
    if (Module = 0) or
      (HMODULE(M.AllocationBase) = Module) then
      Application.Components[i].Free;
  end;
  UnRegisterModuleClasses(Module);
  UnLoadPackage(Module);
end;

procedure TMainForm.UniButton1Click(Sender: TObject);
var
  hm:Hmodule;
  FrC : TUniFrameClass;
  Frame : TUniFrame;
begin
  hm := LoadPackage('Package1.bpl');
  if hm <> 0 then
  begin
    if FindClass('TUniFrameTest') <> nil then
    begin
      FrC := TUniFrameClass(FindClass('TUniFrameTest'));
      if FrC <> nil then
      begin
        frame := FrC.Create(self);
        frame.Align := alClient;
        frame.Parent := UniTabSheet1;

        if frame <> nil then
        begin
          if IsPublishedProp(frame,'GlobalValue') then SetPropValue(frame,'GlobalValue',UniEdit1.Text);
        end;
      end;
     end;
  end
  else
  begin
    //Unload package:
    DoUnloadPackage(hm);
  end;
end;

 


 

 

UnRegisterModuleClasses(Module);

UnLoadPackage(Module);

 

I think that alone is enough.
Now as I already informed you, you won't be able to release a package while resources of it are being used.

You instantiated a frame inside the package and are using it in a form. As long as this frame is not destroyed, this package cannot be released.

To work with packages which will have form, frames, etc. must plan the application well in advance.

Link to comment
Share on other sites

2 minutes ago, herculanojs said:

 

 

UnRegisterModuleClasses(Module);

UnLoadPackage(Module);

 

I think that alone is enough.
Now as I already informed you, you won't be able to release a package while resources of it are being used.

You instantiated a frame inside the package and are using it in a form. As long as this frame is not destroyed, this package cannot be released.

To work with packages which will have form, frames, etc. must plan the application well in advance.

Ok, I'm understand you.

So, if in my main project create new TabSheet for my BPL, I must close this TabSheet and this action remove all components and resources, using from loaded BPL?

Is it will be another?

Link to comment
Share on other sites

6 minutes ago, Артем said:

Ok, eu entendo você.

Então, se no meu projeto principal criar novo TabSheet para o meu BPL, devo fechar este TabSheet e essa ação remover todos os componentes e recursos, usando de BPL carregado?

Será outra coisa?

I think it would be the steps:
1) Load package - loadpackage()
2) Create tabsheet - with frame
3) Close tabsheet
4) release package - unloadpackage()

Or as I mentioned, you can create a control that identifies that there are new resources (bpls) that must be loaded, if the user is using any of these new bpls.
Then inform him that he should reload the application for a new update.

 

You don't need to scan components loaded in the package.
Once you destroy the frame, the package can be released.

Link to comment
Share on other sites

3 minutes ago, herculanojs said:

I think it would be the steps:
1) Load package - loadpackage()
2) Create tabsheet - with frame
3) Close tabsheet
4) release package - unloadpackage()

Or as I mentioned, you can create a control that identifies that there are new resources (bpls) that must be loaded, if the user is using any of these new bpls.
Then inform him that he should reload the application for a new update.

 

You don't need to scan components loaded in the package.
Once you destroy the frame, the package can be released.

Then it turns out that when switching between different TabSheet, which I have loaded BPLs, I have to globally somewhere in the main project to store the name of the BPL, which is located on the selected tab? Or, all the same, when you delete a dynamically created TabSheet, all components, including the BPL loaded on it, will also be deleted and that's it?

Link to comment
Share on other sites

4 minutes ago, Артем said:

Então acontece que ao alternar entre diferentes TabSheet, que eu carreguei BPLs, eu tenho que globalmente em algum lugar no projeto principal para armazenar o nome do BPL, que está localizado na guia selecionada? Ou, mesmo assim, quando você excluir um TabSheet criado dinamicamente, todos os componentes, incluindo o BPL carregado nele, também serão excluídos e é isso?

If you are going to download the package, you must somehow keep the ID (hmodule) identifying the package associated with TabShett or the resource that loaded the package, in order to have the reference to release the package.

Just closing and destroying the resource does not free the package from memory.

Link to comment
Share on other sites

2 minutes ago, herculanojs said:

If you are going to download the package, you must somehow keep the ID (hmodule) identifying the package associated with TabShett or the resource that loaded the package, in order to have the reference to release the package.

Just closing and destroying the resource does not free the package from memory.

MainProject.zip

Link to comment
Share on other sites

Last question)

In BPL, I can't create UniForm1 (as Free form)?

Because in BPL not existing MainModule and that's why I can't write:

function UniForm1: TUniForm1;
begin
  Result := TUniForm1(UniMainModule.GetFormInstance(TUniForm1));
end;

 

Link to comment
Share on other sites

On 8/26/2021 at 10:24 PM, Артем said:

Última pergunta)

No BPL, não posso criar o UniForm1 (como formulário livre)?

Porque no BPL não existe MainModule e é por isso que eu não posso escrever:


function UniForm1: TUniForm1;
begin
  Result := TUniForm1(UniMainModule.GetFormInstance(TUniForm1));
end;

 

I think you have to understand the working dynamics of uniGUI forms regardless of bpl issue, as well as keep in mind that to deal with BPL you must work with object-oriented view and not procedural programming as is customary in Delphi.
Bpl is nothing more than the box where things will be.
If there is a form in bpl, you have to understand how uniGUI handles forms in order to create that form class that you pasted into bpl. You will create something derived from what is in bpl.
Gives a look at object-oriented concepts

Link to comment
Share on other sites

  • 5 months later...

Again hello to all! :)

I'll try to describe the situation.
At the moment, BPL is loaded into UniTabSheet, everything is ok.
Now, if I start the main project, include my BPL in it, and then make some changes to it and I need to re-enable it in the main project, then I cannot, because an error is given that the BPL has already been loaded.
What I need?
I needed what I could without stopping the main project i.e. without rebooting it, reconnect the updated BPL again.
With this in mind, I have a few questions that I need help with:
1. How to reconnect BPL without restarting the main project? Help to add the package unloading code, at least by its name.
2. If, in one browser, you start two project sessions, then if my BPL was already loaded in the first project, then the second user cannot upload or download it, because. a message is displayed that the BPL has already been loaded. On the one hand, this check is correct, it will not be possible to download the package a second time. But, on the other hand, the second user, in his session, may not need to work with the previously loaded BPL, or vice versa. How can I make sure that both users can download the BPL as they need it and so that it does not depend on whether someone downloaded the BPL or not? After all, each user has his own session after authorization goes.

Test_new_2.zip

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...