Search code examples
delphidllvcldelphi-10-seattle

How display a background image and center a panel in a dll Form?


I want load a image that will be the background of a maximized Form that stays in a dll.

The dll is called from a Vcl Form Application but have a trouble where not is possible load the background image on Form, the dll always crashes.

Thank you by you help.

===========================================================================

Executable

unit Unit2;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  end;

var
  Form2: TForm2;

implementation  {$R *.dfm}

procedure LoadDLL;
type
  TShowformPtr = procedure; stdcall;
var
  HDLL: THandle;
  Recv: TShowformPtr;
begin
  HDLL := LoadLibrary('lib.dll');
  if HDLL <> 0 then
  begin
    @Recv := GetProcAddress(HDLL, 'Recv');
    if @Recv <> nil then
    Recv;
  end;
  //FreeLibrary(HDLL);
end;

procedure TForm2.btn1Click(Sender: TObject);
begin
LoadDLL;
end;

end.

Dll

Main:

library Project2;
uses
  SysUtils, Classes, Unit1, Unit2;

{$R *.res}

procedure Recv; stdcall;
begin
  showform;
end;

exports
  Recv;

begin
end.

Unit1 (Form):

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    img1: TImage;
    pnl1: TPanel;
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
   Params.WndParent:= Application.Handle;
  Params.ExStyle := Params.ExStyle or WS_EX_TOPMOST or WS_EX_TRANSPARENT;
  Params.ExStyle := WS_EX_TRANSPARENT or WS_EX_TOPMOST;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  brush.Style := bsclear;
  img1.Picture.LoadFromFile(IncludeTrailingBackslash(GetCurrentDir) + 'background.bmp');
  SetWindowPos(Form1.handle, HWND_TOPMOST, Form1.Left, Form1.Top, Form1.Width,
    Form1.Height, 0);

  ShowWindow(Application.handle, SW_HIDE);

  pnl1.Top := (self.Height div 2) - (pnl1.Height div 2);
  pnl1.Left := (self.Width div 2) - (pnl1.Width div 2);
end;

end.

Unit2:

unit Unit2;

interface

Uses
  windows,
  Unit1,
  SysUtils;

  procedure showform;

implementation

procedure showform;
begin
  Form1 := TForm1.Create(Form1);
  sleep(100);
  Form1.Show;
  Form1.Pnl1.Visible := True;
end;

end.

Solution

  • Your question has a lot of problems, so I would try to answer it as best I can, considering the lack of details.

    1. You are using forms so you are building a VCL application. You need to let the IDE assign the VCL framework to your project.

    2. This line is terribly wrong:

      Form1 := TForm1.Create(Form1);  
      

      In rare circumstances show a from own itself. I would go and say that most probably this is why your application crashes. See this for details about forms in DLLs.

      If you cannot properly debug your application put a beep before that line and one after (make a delay between them).

    3. I think your question should be rather called "how to debug a Delphi project".

      What you need to do is to get the exact line on which the program crashes. This will give you an insight of why the error/crash (by the way, you never shown the exact error message) appears.

      Go check HadShi (recommended) or EurekaLog (buggy) or Smartinspect (I never tried it. Price is similar to the other two). Make sure that you are running in debug mode, the Integrated debugger is on (see IDE options) and that the debug information is present in your EXE/DLL.

      PS: you can still debug your app without have one of the three loggers shown above. Just configure your project properly to run in Debug mode!

      To debug the DLL see the 'Run->Parameters' menu. Define there a host application that will load your DLL. If the error is the DLL, the debugger will take control and put the cursor to the line of code that generated the crash.

    4. I don't know what the final purpose/what is that you want to achieve. Because of this I must warn you that you might need to take into consideration these questions:

      • Do you need to use ShareMM?

      • Why are you building this as a DLL? Can't the application be written as a single EXE? Or two EXEs that communicate with each other?