4
votes

I have a mixed CBuilder/Delphi dll that I load from a non-VCL host application. I'm using RAD Studio XE2. Upon loading the dll I set the Application handle to the host's main form, which has the effect of keeping my forms and dialogs off of the taskbar. However I would like to show the progress bar on the taskbar and have it stack with the host application. I've googled and searched extensively but can't find anything similar.

Dr. Bob wrote a nice tutorial here on the various features of the taskbar and from that I've gotten a progress bar showing up in the main application's taskbar button, but I really want to create a second 'stacked' icon for the progress bar, which a lot of applications do. Dr. Bob's example assumes you are part of the main application and uses this code to add a tab:

if not Application.MainFormOnTaskBar then
  FormHandle := Application.Handle
else FormHandle := Application.MainForm.Handle;
TaskbarList.AddTab(FormHandle);

which doesn't do anything in my case. I've tried

FormHandle := FindWindow('TfmProg', NIL);
TaskbarList.addTab(FormHandle);

but that doesn't change anything.

I've created the form with Application as the owner, and NIL. I've created it fsNormal or fsStayOnTop. Frankly, I've touched every parameter I can get at, but nothing seems to work.

1
If AddTab fails to add a tab, it should return an HResult telling you why. What does it tell you in this case? - Rob Kennedy
Hello @RobKennedy, the value returned is 0, or s_ok I think. I suspect the tab was being created correctly but parented wrong, maybe to a hidden form? - marcp

1 Answers

2
votes

You are correct to set Application.Handle to be the handle of the main form of the host app. This will make the host app's main window be the owner of your windows. However, as you have observed, that also keeps your top-level windows off the taskbar. That's because owned top-level window's do not appear in the taskbar.

To put an owned top-level window on the taskbar you should include the WS_EX_APPWINDOW extended window style. Add this in your form's CreateParams procedure.

procedure CreateParams(var Params: TCreateParams); override;
....
procedure TMyForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

Then you can use ITaskbarList3.SetProgressState and ITaskbarList3.SetProgressValue, passing your form's handle, to display taskbar progress for your form's taskbar button.


I must admit I find your code odd:

FormHandle := FindWindow('TfmProg', NIL);
TaskbarList.addTab(FormHandle);

Since the code is running in your DLL, which also created the form, you shouldn't be using FindWindow to obtain the handle. You can just use Form.Handle where Form is the reference to your form instance. That said, I'd still prefer the approach outlined above, using WS_EX_APPWINDOW, since it is resilient to window handle re-creation and feels rather simpler to me.