Jump to content
Anna Blanca

Why i can't hide Form1 in DLL?

Recommended Posts

Hello. I'm trying add Form in my DLL, and i hide it with next constraction:

procedure Start;

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.ShowMainForm := False;
Application.Run;
end;

exports
Start;

 Earlier, in previous versions Delphi, my DLL worked normal, but exactly in 12-th Delphi version, all broked. When i launch my library through app, it's working normal, but when i launch through rundll32.exe - no one component on Form1 not working. What Embarcadero broked in this time and how fix it? 

P.S. I attach my project to this topic, you can open it and look all youselfe. 

Fucking DLL.zip

Share this post


Link to post
Posted (edited)

Your Start() function is not compatible with rundll32. It's a wonder your code ever worked at all. You are invoking undefined behavior.

 

Read: INFO: Windows Rundll and Rundll32 Interface

 

Your Start() function MUST have the following signature in order for rundll32 to call it correctly:

procedure Start(hwnd: HWND; hinst: HINSTANCE; lpszCmdLine: PAnsiChar; nCmdShow: Integer); stdcall;
Edited by Remy Lebeau

Share this post


Link to post
Posted (edited)
19 hours ago, Remy Lebeau said:

Your Start() function is not compatible with rundll32. It's a wonder your code ever worked at all. You are invoking undefined behavior.

Hm-m-m, earlier, in Delphi 11, all worked normal and my library launched by rundll32.exe normal.

So, and what is HINSTANCE? When i use it in my code, IDE underlining it by red.... No one module in uses not help.

Edited by Anna Blanca

Share this post


Link to post
6 hours ago, Anna Blanca said:

So, and what is HINSTANCE? When i use it in my code, IDE underlining it by red.... No one module in uses not help.

HInstance is the instance (var) of the module, derived from System.pas (type HINST). Should be always defined and available  'cause it is used at loading time (look SysInit.pas)

 

FYI, MainInstance in the HInstance of the MAIN APPLICATION (not the module like dll, library, ...).

Share this post


Link to post
6 hours ago, DelphiUdIT said:

FYI, MainInstance in the HInstance of the MAIN APPLICATION (not the module like dll, library, ...).

In this case, my DLL is main application. So, what library i must add in uses? 

 

And i want message you, if my DLL launch normal, when i  not hide Form1, when i not use  Application.ShowMainForm := False; 

Share this post


Link to post
12 minutes ago, Anna Blanca said:

my DLL is main application

A DLL is a library and it can run only in the processes of a main application (rundll32 or other app).

Share this post


Link to post
Posted (edited)
17 hours ago, Anna Blanca said:

Hm-m-m, earlier, in Delphi 11, all worked normal and my library launched by rundll32.exe normal.

"Seeming to work fine" is a possible result of Undefined Behavior. That doesn't mean the code was right, though.  rundll32 requires a very specific signature for the entry point function that it calls, and your code was not satisfying that requirement.  Fix that first, and if your UI problem still occurs then we can focus on that next.

17 hours ago, Anna Blanca said:

So, and what is HINSTANCE? When i use it in my code, IDE underlining it by red.... No one module in uses not help.

Sorry, I keep forgetting that Delphi doesn't define HINSTANCE as a type. Use System.HINST or Winapi.Windows.HINST or THandle instead.

Edited by Remy Lebeau

Share this post


Link to post
Posted (edited)
26 minutes ago, Remy Lebeau said:

Sorry, I keep forgetting that Delphi doesn't define HINSTANCE. Use System.HINST or Winapi.Windows.HINST or THandle instead.

I wrote that, HINSTANCE is a global var. HINST is the type.

Edited by DelphiUdIT

Share this post


Link to post
16 hours ago, Anna Blanca said:

So, and what is HINSTANCE? When i use it in my code, IDE underlining it by red.... No one module in uses not help.

Edited 15 hours ago by Anna Blanca

image.thumb.png.36381ac08bdabf04badcb27b8c1be187.png

image.thumb.png.ad1b7399bf9e49539f302a62ec9bb50b.png

Share this post


Link to post
On 7/17/2025 at 6:42 PM, Remy Lebeau said:

Sorry, I keep forgetting that Delphi doesn't define HINSTANCE as a type. Use System.HINST or Winapi.Windows.HINST or THandle instead.

 

On 7/17/2025 at 6:57 PM, DelphiUdIT said:

I wrote that, HINSTANCE is a global var. HINST is the type.

Thanks for you all, but one problem is still now. I can't make LNK-file from my DLL:

procedure TForm1.CreateLink(const PathObj, PathLink, Desc, Param: String);
var
IObject : IUnknown;
SLink : IShellLink;
PFile : IPersistFile;
begin
IObject := CreateComObject(CLSID_ShellLink);
SLink := IObject as IShellLink;
PFile := IObject as IPersistFile;
SLink.SetArguments(PChar(Param));
SLink.SetDescription(PChar(Desc));
SLink.SetPath(PChar(PathObj));
PFile.Save(PWChar(WideString(PathLink)), FALSE);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
S : String;
begin
S := TPath.GetHomePath + '\Linker.lnk';
CreateLink('FileName.jpg', S, 'Company', 'Argument');
Timer1.Enabled := False;
end;

When i use it in my DLL - nothing no happen. But when i use this in sample EXE - all working normal. 

Share this post


Link to post
Posted (edited)

Hello, first of all is better that you tell us what do you expectt from the runing DLL (e.g. found a LNK file in .....).

I think there is some issues about your knowledge (I talk about Windows 11).

 

If you run from a cmd prompt a RUNDLL32, the HOMEPATH you refer is "C:\Users\YOUR ACCOUNT NAME\AppData\Roaming"

 

So, here is where the LNK file is created. And it is always created.

 

About the pointed link file (JPG): this file, without none path should be under UNKNOWN PATH. So the file will never be linked.

If you comile and run like an EXE instead, the path where the JPG file is "linked" is in the same directory as exe is.

 

The DLL works perfect as expected.

 

Notes:

 

1) Like I wrote before, you should PUT the "Timer1.Enabled := False;" at the begining of the event procedure.

2) Is missing the "CoInitializeEx(nil, COINIT_MULTITHREADED);": without that the CreateComObject will fail.

Edited by DelphiUdIT

Share this post


Link to post
Posted (edited)
4 hours ago, Anna Blanca said:

When i use it in my DLL - nothing no happen. But when i use this in sample EXE - all working normal. 

Where does it fail, exactly? Your code is not doing any error handling/reporting.

 

Are you creating a plain DLL, or a Runtime Package BPL? It is not safe to use Delphi-managed types like String across the DLL boundary in a plain DLL, without extra work (ie, like using the ShareMem unit in both EXE and DLL, etc).

 

Did you verify your timer is running correctly inside your DLL?

 

Does the thread that is calling into the DLL first call CoInitialize/Ex()? IShellLink is a COM object, so the COM library needs to be initialized on any thread that wants to access any COM object.

 

DO NOT be tempted to call CoInitialize/Ex() inside your DLL, unless it uses COM in a thread that it creates for itself. It is the responsibility of a thread creator to decide how COM interacts with that thread, not the responsibility of functions called by a thread.

Edited by Remy Lebeau

Share this post


Link to post
On 7/20/2025 at 5:41 PM, DelphiUdIT said:

Hello, first of all is better that you tell us what do you expectt from the runing DLL (e.g. found a LNK file in .....).

I think there is some issues about your knowledge (I talk about Windows 11).

 

If you run from a cmd prompt a RUNDLL32, the HOMEPATH you refer is "C:\Users\YOUR ACCOUNT NAME\AppData\Roaming"

 

So, here is where the LNK file is created. And it is always created.

 

About the pointed link file (JPG): this file, without none path should be under UNKNOWN PATH. So the file will never be linked.

If you comile and run like an EXE instead, the path where the JPG file is "linked" is in the same directory as exe is.

 

The DLL works perfect as expected.

 

Notes:

 

1) Like I wrote before, you should PUT the "Timer1.Enabled := False;" at the begining of the event procedure.

2) Is missing the "CoInitializeEx(nil, COINIT_MULTITHREADED);": without that the CreateComObject will fail.

O'K, but LNK-file not created. But earlier, in Delphi 11, it's created normal. 

Share this post


Link to post
22 hours ago, Remy Lebeau said:

Are you creating a plain DLL, or a Runtime Package BPL?

I'm creating plan DLL.

22 hours ago, Remy Lebeau said:

It is not safe to use Delphi-managed types like String across the DLL boundary in a plain DLL, without extra work (ie, like using the ShareMem unit in both EXE and DLL, etc).

I'm not acrossin DLL boundary. I'm just trying meke LNK-file in DLL, working through rundll32.exe, nothing more. 

Share this post


Link to post
29 minutes ago, Anna Blanca said:

I'm creating plan DLL.

As mentioned earlier, CoInitialize/Ex() is required to work with COM objects, like ShellLink.  But there is no call to CoInitialize/Ex() in your code.  In a VCL application, that is called automatically for you.  But in this case, rundll32 will not call it for you, so you will have to call it yourself.  Call CoInitialize/Ex() at the beginning of your Start() function, and call CoUnintialize() before exiting from Start(), eg:

procedure Start(hwnd: HWND; hinst: HINST; lpszCmdLine: PAnsiChar; nCmdShow: Integer); stdcall;
begin
  if Failed(CoInitialize(nil)) then
  begin
    // report the error some where ...
    Exit;
  end;
  try
    ...
  finally
    CoUninitialize;
  end;
end;

And add some error handling/logging to your CreateLink() function, eg:

procedure TForm1.CreateLink(const PathObj, PathLink, Desc, Param: String);
var
  IObject : IUnknown;
  SLink : IShellLink;
  PFile : IPersistFile;
begin
  try
    IObject := CreateComObject(CLSID_ShellLink);
    SLink := IObject as IShellLink;
    PFile := IObject as IPersistFile;
    OleCheck(SLink.SetArguments(PChar(Param)));
    OleCheck(SLink.SetDescription(PChar(Desc)));
    OleCheck(SLink.SetPath(PChar(PathObj)));
    OleCheck(PFile.Save(PWChar(WideString(PathLink)), FALSE));
  except
    // report the error somewhere ...
  end;
end;
29 minutes ago, Anna Blanca said:

I'm not acrossin DLL boundary. I'm just trying meke LNK-file in DLL, working through rundll32.exe, nothing more. 

If all you want is command-line access to the ShellLink object, then why use rundll32 at all?  You could use a Powershell script instead.  Look at the New-Object command:

 

Creating COM objects with New-Object

29 minutes ago, Anna Blanca said:

I'm just trying meke LNK-file in DLL, working through rundll32.exe, nothing more. 

Have you tried debugging your DLL yet?  Are you aware that the IDE can debug a DLL project?  Simply set rundll32 as the Host for the project, and then you can run the project and step through your code normally.  Where exactly is your code actually failing to behave the way you are expecting?

Edited by Remy Lebeau

Share this post


Link to post
1 hour ago, Anna Blanca said:

I'm creating plan DLL.

I'm not acrossin DLL boundary. I'm just trying meke LNK-file in DLL, working through rundll32.exe, nothing more. 

Try this.

 

The DLL is present, but you can build the project, and then simply run directly from terminal line this (you must be in the path where the DLL is present): 

 

RUNDLL32 d.dll,Start

 

Pay attention that you MUST CHANGE THE PATH AND THE FILENAME LINKED IN THE SOURCE, if you want that the link open the right file.

 

NOTE: In the other console windows that should open, is going to be printed the path of the LNK file.

 

Fucking DLL RUNDLL32.zip

Edited by DelphiUdIT

Share this post


Link to post
On 7/21/2025 at 7:30 PM, Remy Lebeau said:

If all you want is command-line access to the ShellLink object, then why use rundll32 at all?  You could use a Powershell script instead.  Look at the New-Object command:

I want make ShellLing object only with Delphi resources. 

On 7/21/2025 at 7:30 PM, Remy Lebeau said:

Have you tried debugging your DLL yet?  Are you aware that the IDE can debug a DLL project?  Simply set rundll32 as the Host for the project, and then you can run the project and step through your code normally. 

How i can make it?

Share this post


Link to post
On 7/21/2025 at 7:30 PM, Remy Lebeau said:

As mentioned earlier, CoInitialize/Ex() is required to work with COM objects, like ShellLink.  But there is no call to CoInitialize/Ex() in your code.  In a VCL application, that is called automatically for you.  But in this case, rundll32 will not call it for you, so you will have to call it yourself.  Call CoInitialize/Ex() at the beginning of your Start() function, and call CoUnintialize() before exiting from Start(), eg:

May be, better make that: 

procedure Start(hwnd: HWND; hinst: HINST; lpszCmdLine: PAnsiChar; nCmdShow: Integer); stdcall;
begin
  if Failed(CoInitialize(nil)) then
  begin
   CoUninitialize;
  end; 
end;

Not?

Share this post


Link to post
13 minutes ago, Anna Blanca said:

I want make ShellLing object only with Delphi resources. 

Why, though? This is clearly not the best solution for your use-case since you are having so much trouble with it for such a small task.

13 minutes ago, Anna Blanca said:

How i can make it?

Just as I described earlier.  Configure your DLL project's Run settings to specify rundll32 as its Host application.  Then you can run the project normally in the IDE, it will execute rundll32, and the debugger will attach to that process and let you debug the DLL code.

Share this post


Link to post
13 minutes ago, Anna Blanca said:

May be, better make that: 

Not?

Absolutely not.  Why would you consider uninitializing something it when it fails to initialize?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×