-3

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.
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • 1
    You said that it crashes, what's the error? Have you debugged into the DLL to find where the error occurs? I don't see any images being set, is the image set to the panel background at designtime? – mirtheil Dec 04 '18 at 12:40
  • @mirtheil, *`is the image set to the panel background at designtime`* the background image not must be in panel and yes on Form1 of dll. Yes is defined in runtime here: `img1.Picture.LoadFromFile(IncludeTrailingBackslash(GetCurrentDir) + 'background.bmp');` –  Dec 04 '18 at 12:51
  • This doesn't crash. Please provide a [mcve], or at least provide some debugging information regarding the crash you are experiencing. – J... Dec 04 '18 at 12:53
  • @J..., yes crashes. The panel not is centralizes and image not is load to Form1 of dll. –  Dec 04 '18 at 12:55
  • Is the bitmap you try to load with `img1.Picture.LoadFromFile`in the correct folder? What is the error you get? – G Wimpassinger Dec 04 '18 at 13:02
  • There's loads wrong here. Unfortunately you've posted code after you've started your trial and error hacking. The call to ShowWindow gives that away. Use of global Form1 variable is all wrong. Not much incentive to fix all the errors because spreading an app between exe and dll is fraught with problems. – David Heffernan Dec 04 '18 at 13:08
  • @GWimpassinger, [here](http://prntscr.com/lqk6q4) is the folder with all binary files. The error is with VCL form app, he crashes and only the Form1 of dll is opened, but without any image in background or Panel centralized. –  Dec 04 '18 at 13:09
  • 3
    @Davison I just built the code you provided in your question - **it does not crash**. Nobody here is going to download a project and debug it for you so forget that idea right away. It's your job in asking the question to provide complete code that reproduces the problem you are having. Take the code you've given us, start from scratch, and *you* try to reproduce the problem. When you can ask a complete question, come back and [edit] your question with the details. – J... Dec 04 '18 at 13:12
  • These questions are really no use to anybody. What you need is not an answer to this question, but rather you need to learn strong debugging skills. Starting with the ability to narrow a problem down to a [mcve]. – David Heffernan Dec 04 '18 at 13:16
  • @J..., Could make upload of your version of example please? i want test here in my pc. –  Dec 04 '18 at 13:37
  • @Davison No - you have the code right there. It took me two minutes to make a new project with it. You're asking me to take five minutes to upload code that would take you two minutes to copy and paste yourself. That makes no sense at all. – J... Dec 04 '18 at 13:38
  • @J..., i need of your example to test, why probably my error was other that not is related with code. –  Dec 04 '18 at 13:42
  • No. You need to make a [Mcve]. – David Heffernan Dec 04 '18 at 13:52
  • @J..., I'm understanding. [This](https://www.sendspace.com/file/n7ynx0) is my version, not works like i said on question. Already tested in 2 diferent computers. –  Dec 04 '18 at 14:10
  • **PS:** The example linked on my previous comment is the same code present on question, but not works. –  Dec 04 '18 at 14:17
  • @Davison: I tested your sample and it did not crash. Used Delphi 10.2.3 Tokyo for that. But a few things come to my mind. Do not call `FreeLibrary` until you closed and freed the form from the dll. In your `showform` you write `Form1 := TForm1.Create(Form1)`, it only works because `Form1` is initially `nil`. You add `Unit1` and `Unit2`directly to your dll-project and not by adding it via `Project -> Add to the project`. Therefore those files are not shown in the project explorer. And `Applicaton.Handle`in the dll is *not* the same as `Application.Handle`in your real application. – G Wimpassinger Dec 04 '18 at 15:39
  • @GWimpassinger, thank you. Could you upload the binary files that you compiled with Delphi 10.2.3 Tokyo please? i want test in my pc. –  Dec 04 '18 at 15:48
  • 1
    Strange that you don't want to debug your own program. It's very hard to make any progress if you don't allow yourself the option on debugging. – David Heffernan Dec 04 '18 at 16:05
  • @DavidHeffernan, i think that the trouble is the version os IDE. I will install the Delphi Tokyo now. –  Dec 04 '18 at 16:30
  • Wouldn't it just be easier to make a [mcve] and then debug it? Perhaps you don't know how to debug a program? Wouldn't you like to learn? – David Heffernan Dec 04 '18 at 16:33
  • On IDE, i know debug only executables, not dll's. –  Dec 04 '18 at 16:58
  • 1
    Read "host application" [here](http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Debugger). – Sertac Akyuz Dec 04 '18 at 17:06
  • I discovered the trouble. The reason to not work was that i clicked in "Yes" in [this window](http://prntscr.com/lqosmk). I have a dll project where i added several Forms by **"Search path"** and only adding your unit, now i saw that also have the same troouble described in this question. Then how i can fix this without need create each Form by IDE and click in "No" option when this window asking appear? –  Dec 04 '18 at 18:14
  • You might try asking a question. Not that that seems to work very well... – Sertac Akyuz Dec 04 '18 at 18:17
  • So you don't know how to debug, and are content with that. You set your sights so low. – David Heffernan Dec 04 '18 at 21:10
  • why do you sleep 100 ms? – Gabriel Dec 05 '18 at 11:59
  • why do you need this to be in a DLL? why not a "normal" exe? – Gabriel Dec 05 '18 at 11:59

1 Answers1

0

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?

Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • A form can own itself - it's a really bad idea and can be the cause of problems, but not in this case. OP's code compiles and runs fine. The whole of points #3 and #4 should be comments - if that was OP's question it's off topic. Third party recommendations are off topic. Asking questions for clarification belongs in a comment. This really isn't an answer. – J... Dec 05 '18 at 12:25
  • it is the best we can do with the provided information :) – Gabriel Dec 05 '18 at 12:27
  • at least, the OP can now debug the code and see where it crashes. probably he was running in the 'release' mode or if he was in 'debug' mode the project was not correctly configured. we will be able to help him once we have that information. – Gabriel Dec 05 '18 at 12:27
  • If you've followed the other comments, OP is not terribly interested in debugging... – J... Dec 05 '18 at 12:35
  • Yes. I have seen, but I think he is a beginner with Delphi (also a beginner on SO). Debugging can sound like something complicated. This is why I steered my answer into the "debugging before asking" direction. If he is going to set the debugger correctly we will immediately know the exact error msg and the line of code that causes the problem. – Gabriel Dec 05 '18 at 14:07
  • Honestly I would compile his code, but I don't have access to Delphi now. So, we must help us in order to help him. Anyway, I would recommend him to go away from the DLL approach. I think he can do what he wants with a simple/single EXE app. – Gabriel Dec 05 '18 at 14:10
  • @Rigel, thank you by your answer, was very useful. I choose dll because in my executable is used [`SetThreadDesktop`](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setthreaddesktop) function and to call Forms, works only if they are inside a dll project. –  Dec 05 '18 at 18:21
  • 1
    @J A `TForm` cannot own itself. In the statement `TForm1.Create(Form1)`, `Form1` will either be `nil`, or it will point at an earlier instance of `TForm1`. – Remy Lebeau Dec 13 '18 at 23:23
  • @Davison you don't need to use a DLL in order to use `SetThreadDesktop()`. In fact, using a DLL will not help with whatever issue you are trying to solve by moving code into the DLL. It simply introduces another point of possible failure. – Remy Lebeau Dec 13 '18 at 23:25
  • @RemyLebeau, thank you very much by comments. I'm already using a executable without dll :-) and `SetThreadDesktop` already is working like expected. –  Dec 14 '18 at 15:37