Jump to content
vhanla

How to completely hide application from taskbar (on launch)?

Recommended Posts

Hello, I was trying to use `Application.MainFormOnTaskbar := False` in a FMX application, but it doesn't exits there.

So after looking for answers, I found this one:


 

uses

  ...

  FMX.Platform.Win, Winapi.Windows,...

begin

  Application.Initialize;

  ShowWindow(ApplicationHWND, SW_HIDE);

...

This kind of works, but it is not as "silent"ish as the VCL counterpart, because it still shows a blank button being added to the taskbar then disappears before completely showing its icon.

image.png.366a60edf8d85e414418ad4fa418810a.png This is more noticeable when FMX application it not pinned. It shows it in small amount of time, before hiding it but is noticeable.

 

Is there any way to completely hide it on launch?

 

I'm writing a tool to center the taskbar's icons, and also another one to pin icons and launch from its position (pinned .lnk with different arguments are allowed more than once) like mac's stacks but with fancy FMX effects and animations, but launching them (being it a FMX application and as stated before it has that taskbar issue) is noticeable since my other tool rearranges its position and it looks weird, but normal VCL application doesn't do that.

image.png.dee85f946cb36a055f07905458d50e42.png

 

I also tried mixing VCL with FMX as MonkeyMixer method suggests, with main application VCL which is hidden and launches the FMX form, yet it still has the same issue, it shows an incomplete icon in the taskbar to fastly disappear, and since my other tool center icons, it is expected that it rearranges taskbar's icons giving an effect like shaking, which is very annoying.

glitchfmxtaskbar.thumb.gif.b6bab81d4acc41392c3b9d35180bd112.gif

In this gif animation I show what I mean. The FMX version is the last icon, when it is launched the taskbar's icons restart due to that mentioned issue (might fix in the centering application, but without injecting code is hard, though is planned for distant future, I don't want to deal with explorer.exe unexpected crashes yet), while the other launches from pinned icons is a VCL application, and as you can see it doesn't try to create a taskbar button, just remains hidden from the beginning.

Notice that I don't want those applications to be visible because (otherwise) taskbar's thumbnail will interfere in "usability", and that is not wanted.

However, I might fix the centering application with delaying and etc ways, but the original question is regarding to hide it completely from taskbar on launch, and to keep it running in background is an option, but I still want it to solve that issue as is (required).

 

 

Edited by vhanla
stress "on launch" importance
  • Like 1

Share this post


Link to post

Thanks, actually changing GWL_EXSTYLE with SetWindowLong is for hiding it from Alt Tab list. Tried that too, it still shows the taskbar button for a very little amount of time, then it disappears. Unlike VCL applications, FMX applications somehow still tries to show its taskbar icon.

 

`ApplicationHWND` itself without even creating form neither running it, shows its taskbar icon.

 

e.g. in projects file (dpr) I uncomment Application.CreateForm... and Application.Run;

but add var Handle := ApplicationHWND; after Application.Initialize; the taskbar icon is created and obviously hidden since application terminates after that.

image.png.0ed52ee52288420dde4cf462b9063337.png

When that incompleted FMX application is launched, current foreground application (e.g. explorer) is lost and focuses on a non visible application (our app) just to return to the original foreground window (since it terminates), weird thing is taskbar still shows its icon "flashing" to fastly disappear.

image.png.27af619ef255f4f988f37593b7d39e87.pngimage.png.134f884f92ae859b6e3091b86d6a0d99.png

Another interesting thing is, that creating a FMX application (in this case 2D mutidevice application) it always creates a Unit2 /TForm2 as main initial form even though there is no Unit1, at least here on my Delphi 10.3 Update 3 Rio installation.

 

So debuggin it with IDA shows a call to  FMX::Platform::Win::TPlatformWin::CreateAppHandle which indeed calls Winapi.Windows.ShowWindow just by calling ApplicationHWND function.

image.thumb.png.86c9ecb514c9d3d43d16e09c11d6650a.png

Notice the icon in the taskbar, it belongs to that FMX application.

 

Anyhow, I tried using the non ApplicationHWND method, which is the one finding the current process id window to hide, which also works.

Calling HideAppInTaskbar(Form Handle) from FormCreate shows that before even processing that call, its icon is already added to explorer's taskbar.

image.thumb.png.08a198fc170401d5949243ae200b593f.png

This procedure does what is expected, to hide the taskbar's icon, but it doesn't avoid its creation in the first place, so it is always visible after launching, at least for a very short period of time.

That's because after Application.Run, FMX.Platform.Win.TPlatformWin.Run procedure calls Fmx.Forms.TApplication.RealCreateForms, which also calls Fmx.Forms.TApplication.CreateForm -> Fmx.Forms.TCommonCustomForm.Create -> public Fmx.Forms.TCommonCustomForm.InitializeNewForm -> Fmx.Forms.TCommonCustomForm.CreateHandle which as similar as ApplicationHWND it is called from Fmx::Platform::Win::TPlatformWin::CreateWindow GetApplicationHWND -> Fmx.Platform.Win.TPlatformWin.UpdateApplicationHwnd ends up calling Fmx.Platform.Win.TPlatformWin.CreateAppHandle 

image.thumb.png.fe8a4b0fe81af7dee4b80437d21aba42.png

Which indeed calls ShowWindow with nCmdShow parameter using argument 1 (SW_SHOWNORMAL), then it follows other calls to finally end up with FormCreate procedure in our main form, so those suggested tricks to hide the taskbar icon are finally applied, after it was shown in the first place.

 

However, since every application is a binary, it can be patched, so I tried patching it in the binary to 0 (SW_HIDE) and it worked, no more issues.

push 1 in hex 6a 01 (BA 01 00 00 00 in x64), just replaced with 64 00 in the binary/executable using a hex editor, and voilà it finally worked as I was requiring. No more tiny little amount of time showing the taskbar icon just to hide it afterwards.

 

Notice that it might differ in your project, but mine was located at this hex pattern location in my binary/executable (which was not found more than once).

ff 8b d8 6a 01 53 e8 so I just look for it and patch after each build. Only 32 bit builds.

48 89 4d 70 ba 01 00 00 00 e8 in x64 builds (debug&release mode). At least with Delphi Rio 10.3.3

 

 

 

Finally, the culprit seems to be function TPlatformWin.CreateAppHandle: HWND in FMX.Platform.Win.pas file, which calls Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL) instead of SW_HIDE). However it was called from TPlatformWin.CreateWindow function when ParentWnd = 0, which means no parents are found.

Then it follows ParentWnd := ApplicationHWND; <--- this function, as mentioned before, leads to create and show a non visible window, just to get the application handle, the procedure in question is TPlatformWin.UpdateApplicationHwnd when there is no parent handle. But modifying those delphi source code files don't work, so I ended patching it after the binary is created.

 

[Update]

Thanks to this answer at SO

https://stackoverflow.com/a/10471855/537347 

the solution was just a matter to copy the FMX.Platform.Win.pas file to your project's directory and make the changes to CreateAppHandle function:

 

function TPlatformWin.CreateAppHandle: HWND;
var
 ...
begin
  ...
  Result := CreateWindowEx(WS_EX_WINDOWEDGE or WS_EX_APPWINDOW, FMAppClass.lpszClassName, PChar(FTitle),
                           WS_POPUP or WS_GROUP, 0, 0, 0, 0, GetDesktopWindow, 0, hInstance, nil);
  if FApplicationHWND = 0 then // this is checked by ApplicationHWND function
	Winapi.Windows.ShowWindow(Result, SW_HIDE) // make sure our application never shows in taskbar icon in this case
  else
	Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL);
end;                         

Originally, there is no conditional and uses the SW_SHOWNORMAL argument only, this fixes that.

 

Now, I'm not worried about patching the created binary/exe anymore. Just remember to remove it from public repositories as it is a copyrighted material.

 

However, I left the patching method incase your Delphi license/edition doesn't include FMX source code.

Edited by vhanla
added hex pattern to patch for x86 and x64, and modification to original FMX source code

Share this post


Link to post
3 hours ago, vhanla said:

Thanks, actually changing GWL_EXSTYLE with SetWindowLong is for hiding it from Alt Tab list. Tried that too, it still shows the taskbar button for a very little amount of time, then it disappears. Unlike VCL applications, FMX applications somehow still tries to show its taskbar icon.

 

`ApplicationHWND` itself without even creating form neither running it, shows its taskbar icon.

 

e.g. in projects file (dpr) I uncomment Application.CreateForm... and Application.Run;

but add var Handle := ApplicationHWND; after Application.Initialize; the taskbar icon is created and obviously hidden since application terminates after that.

image.png.0ed52ee52288420dde4cf462b9063337.png

When that incompleted FMX application is launched, current foreground application (e.g. explorer) is lost and focuses on a non visible application (our app) just to return to the original foreground window (since it terminates), weird thing is taskbar still shows its icon "flashing" to fastly disappear.

image.png.27af619ef255f4f988f37593b7d39e87.pngimage.png.134f884f92ae859b6e3091b86d6a0d99.png

Another interesting thing is, that creating a FMX application (in this case 2D mutidevice application) it always creates a Unit2 /TForm2 as main initial form even though there is no Unit1, at least here on my Delphi 10.3 Update 3 Rio installation.

 

So debuggin it with IDA shows a call to  FMX::Platform::Win::TPlatformWin::CreateAppHandle which indeed calls Winapi.Windows.ShowWindow just by calling ApplicationHWND function.

image.thumb.png.86c9ecb514c9d3d43d16e09c11d6650a.png

Notice the icon in the taskbar, it belongs to that FMX application.

 

Anyhow, I tried using the non ApplicationHWND method, which is the one finding the current process id window to hide, which also works.

Calling HideAppInTaskbar(Form Handle) from FormCreate shows that before even processing that call, its icon is already added to explorer's taskbar.

image.thumb.png.08a198fc170401d5949243ae200b593f.png

This procedure does what is expected, to hide the taskbar's icon, but it doesn't avoid its creation in the first place, so it is always visible after launching, at least for a very short period of time.

That's because after Application.Run, FMX.Platform.Win.TPlatformWin.Run procedure calls Fmx.Forms.TApplication.RealCreateForms, which also calls Fmx.Forms.TApplication.CreateForm -> Fmx.Forms.TCommonCustomForm.Create -> public Fmx.Forms.TCommonCustomForm.InitializeNewForm -> Fmx.Forms.TCommonCustomForm.CreateHandle which as similar as ApplicationHWND it is called from Fmx::Platform::Win::TPlatformWin::CreateWindow GetApplicationHWND -> Fmx.Platform.Win.TPlatformWin.UpdateApplicationHwnd ends up calling Fmx.Platform.Win.TPlatformWin.CreateAppHandle 

image.thumb.png.fe8a4b0fe81af7dee4b80437d21aba42.png

Which indeed calls ShowWindow with nCmdShow parameter using argument 1 (SW_SHOWNORMAL), then it follows other calls to finally end up with FormCreate procedure in our main form, so those suggested tricks to hide the taskbar icon are finally applied, after it was shown in the first place.

 

However, since every application is a binary, it can be patched, so I tried patching it in the binary to 0 (SW_HIDE) and it worked, no more issues.

push 1 in hex 6a 01 (BA 01 00 00 00 in x64), just replaced with 64 00 in the binary/executable using a hex editor, and voilà it finally worked as I was requiring. No more tiny little amount of time showing the taskbar icon just to hide it afterwards.

 

Notice that it might differ in your project, but mine was located at this hex pattern location in my binary/executable (which was not found more than once).

ff 8b d8 6a 01 53 e8 so I just look for it and patch after each build. Only 32 bit builds.

48 89 4d 70 ba 01 00 00 00 e8 in x64 builds (debug&release mode). At least with Delphi Rio 10.3.3

 

 

 

Finally, the culprit seems to be function TPlatformWin.CreateAppHandle: HWND in FMX.Platform.Win.pas file, which calls Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL) instead of SW_HIDE). However it was called from TPlatformWin.CreateWindow function when ParentWnd = 0, which means no parents are found.

Then it follows ParentWnd := ApplicationHWND; <--- this function, as mentioned before, leads to create and show a non visible window, just to get the application handle, the procedure in question is TPlatformWin.UpdateApplicationHwnd when there is no parent handle. But modifying those delphi source code files don't work, so I ended patching it after the binary is created.

 

[Update]

Thanks to this answer at SO

https://stackoverflow.com/a/10471855/537347 

the solution was just a matter to copy the FMX.Platform.Win.pas file to your project's directory and make the changes to CreateAppHandle function:

 


function TPlatformWin.CreateAppHandle: HWND;
var
 ...
begin
  ...
  Result := CreateWindowEx(WS_EX_WINDOWEDGE or WS_EX_APPWINDOW, FMAppClass.lpszClassName, PChar(FTitle),
                           WS_POPUP or WS_GROUP, 0, 0, 0, 0, GetDesktopWindow, 0, hInstance, nil);
  if FApplicationHWND = 0 then // this is checked by ApplicationHWND function
	Winapi.Windows.ShowWindow(Result, SW_HIDE) // make sure our application never shows in taskbar icon in this case
  else
	Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL);
end;                         

Originally, there is no conditional and uses the SW_SHOWNORMAL argument only, this fixes that.

 

Now, I'm not worried about patching the created binary/exe anymore. Just remember to remove it from public repositories as it is a copyrighted material.

 

However, I left the patching method incase your Delphi license/edition doesn't include FMX source code.

Would you mind creating a quality entry on Embarcadero website? Btw are you working with which Delphi version?

Share this post


Link to post
4 hours ago, vhanla said:

Thanks, actually changing GWL_EXSTYLE with SetWindowLong is for hiding it from Alt Tab list.

It is for both: https://devblogs.microsoft.com/oldnewthing/20031229-00/?p=41283

4 hours ago, vhanla said:

Tried that too, it still shows the taskbar button for a very little amount of time, then it disappears. Unlike VCL applications, FMX applications somehow still tries to show its taskbar icon.

Unlike VCL, FMX does not allow you to customize the creation of a Form’s HWND, so there is no option to remove the WS_EX_APPWINDOW style up front. Not without modifying FMX’s source code, as you have discovered.

4 hours ago, vhanla said:

Another interesting thing is, that creating a FMX application (in this case 2D mutidevice application) it always creates a Unit2 /TForm2 as main initial form even though there is no Unit1, at least here on my Delphi 10.3 Update 3 Rio installation.

Is there a Unit1 already present in the source folder, if not in the Project? When creating a new unit, the IDE looks at existing units in the folder and chooses the highest unused sequential number.

4 hours ago, vhanla said:

This procedure does what is expected, to hide the taskbar's icon, but it doesn't avoid its creation in the first place, so it is always visible after launching, at least for a very short period of time.

The best way to avoid creating the taskbar button at all is to not create any top-level HWNDs that have the WS_EX_APPWINDOW style. Something FMX tries to prevent you from doing.

  • Thanks 1

Share this post


Link to post
Quote
  4 hours ago, vhanla said:

Another interesting thing is, that creating a FMX application (in this case 2D mutidevice application) it always creates a Unit2 /TForm2 as main initial form even though there is no Unit1, at least here on my Delphi 10.3 Update 3 Rio installation.

Is there a Unit1 already present in the source folder, if not in the Project? When creating a new unit, the IDE looks at existing units in the folder and chooses the highest unused sequential number.

Or in the Default folders under Tools either shared repository or Default project.  

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

×