3

According to this question it is possible to hide fmx taskbar icon by changing window style to WS_EX_TOOLWINDOW. In XE2 and XE3 this code works:

uses FMX.Platform.Win, Winapi.Windows;

procedure TForm1.Button1Click(Sender: TObject);
var h:THandle;
begin
  h := FmxHandleToHWND(Handle);
  ShowWindow(h, SW_HIDE);
  SetWindowLong(h, GWL_EXSTYLE, GetWindowLong(h, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
  ShowWindow(h, SW_SHOW);
end;

In XE4 this solution does not work (application button should become hidden but nothing happens). any body have any idea?

Thanks.

Community
  • 1
  • 1
mh taqia
  • 3,506
  • 1
  • 24
  • 35
  • 3
    this work fine for me on XE3 (without MainformOnTaskbar): uses FMX.Platform.Win ; procedure TForm2.Button1Click(Sender: TObject); var h:THandle; begin h := FmxHandleToHWND(Handle); ShowWindow(h, SW_HIDE); SetWindowLong(h, GWL_EXSTYLE, GetWindowLong(h, GWL_EXSTYLE) or WS_EX_TOOLWINDOW); ShowWindow(h, SW_SHOW); end; – bummi May 27 '13 at 08:30
  • MainformOnTaskbar determines whether or not the main form is unowned. Probably has no meaning in FMX where the main form is probably always unowned. So using tool window style will be enough. – David Heffernan May 27 '13 at 08:42
  • Suggested code does not work on XE4. – mh taqia May 27 '13 at 10:43
  • Is it your goal to prevent your app from appearing on the taskbar all together(Icon + Title) or is it just removing the Icon(Title visible)? – Peter May 27 '13 at 11:59
  • My goal is only icon, the title is not important. – mh taqia May 27 '13 at 12:06
  • That's what I figured, you should know that the question you linked isn't really relevant to this question since there the goal was to remove the application from the taskbar all together (Icon+Title) – Peter May 27 '13 at 12:10
  • Well, I want to remove Icon+Title, ok? – mh taqia May 27 '13 at 12:12
  • you should change your question then to reflect your choice. – Peter May 27 '13 at 12:15
  • It's really poor when you say "doesn't work". Describe exactly how the code fails. Compile time? Runtime? Do not make us guess. – David Heffernan May 27 '13 at 17:14
  • Taskbar icon should become hidden after click on button but nothing happens. It is clear that above code has no syntax problems. I'm surprised your comment. – mh taqia May 27 '13 at 18:53
  • It's not clear and "doesn't work" is never enough. Be explicit. – David Heffernan May 28 '13 at 06:56
  • I found the solution. – mh taqia May 29 '13 at 07:57
  • Can you share the solution you have found please? I have a similar issue with hiding the taskbar button and changing its caption. – VGeorgiev Dec 10 '13 at 12:30
  • @VGeorgiev: I shared the requested code. Please upvote the question to negate unfair downvote ;) – mh taqia Dec 10 '13 at 15:09

5 Answers5

4

Just tried this in XE7 and of course it didn't work. However a little look into FMX.PlatformWin shows the application handle is now exposed through the ApplicationHWND function, so the code that works on XE7 (don't forget to include unit FMX.Platform.Win and Winapi.Windows) is...

procedure HideAppOnTaskbar (AMainForm : TForm);
var
  AppHandle : HWND;
begin
  AppHandle := ApplicationHWND; 
  ShowWindow(AppHandle, SW_HIDE);
  SetWindowLong(AppHandle, GWL_EXSTYLE, GetWindowLong(AppHandle, GWL_EXSTYLE) and (not     WS_EX_APPWINDOW) or WS_EX_TOOLWINDOW);
  //ShowWindow(AppHandle, SW_SHOW);
end;

The ShowWindow at the end is optional - it seems to make no difference. You can remove the extended styles and restore the WS_EX_APPWINDOW style to show the toolbar icon again.

Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
2

It seems that in XE4 FM apps there is no more handle for the application object. So we need to get the parent of the main form. Below two small methods to hide/show your app on the taskbar.

procedure HideAppOnTaskbar (AMainForm : TForm);
var
  AppHandle : HWND;
begin
  AppHandle := GetParent(FmxHandleToHWND(AMainForm.Handle));
  ShowWindow(AppHandle, SW_HIDE);
  SetWindowLong(AppHandle, GWL_EXSTYLE, GetWindowLong(AppHandle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
end;

procedure ShowAppOnTaskbar (AMainForm : TForm);
var
  AppHandle : HWND;
begin
  AppHandle := GetParent(FmxHandleToHWND(AMainForm.Handle));
  ShowWindow(AppHandle, SW_HIDE);
  SetWindowLong(AppHandle, GWL_EXSTYLE, GetWindowLong(AppHandle, GWL_EXSTYLE) and (not WS_EX_TOOLWINDOW));
  ShowWindow(AppHandle, SW_SHOW);
end;

We could also have used "Application.MainForm" instead of passing the mainform, but this variable is not assigned during the "OnCreate" Event of the mainform.

So in your "OnCreate" Event off your mainform you can simply write:

procedure TMyMainForm.FormCreate(Sender: TObject);
begin
  HideAppOnTaskbar (self);
end;
Nicki
  • 21
  • 1
  • I tested suggested code. It does not work (has no effect). I think this code works only on XE3; also note that the function FmxHandleToHWND does not exists on XE4 anymore. – mh taqia Jun 07 '13 at 10:02
0
HWND hWnd = NULL;
DWORD pid, current_pid = GetCurrentProcessId();
do 
{
    hWnd = FindWindowExA(NULL, hWnd, "TFMAppClass", NULL);
    if(hWnd)
    {
        GetWindowThreadProcessId(hWnd, &pid);
        if(current_pid == pid)
            break;
    }
} while(hWnd);

::SetParent(FmxHandleToHWND(Handle), NULL);
::ShowWindow(hWnd, SW_HIDE);
mh taqia
  • 3,506
  • 1
  • 24
  • 35
  • Thanks. The "TFMAppClass" pointed me in the right direction. I looked for something like that with Spy++, but have obviously missed it. – VGeorgiev Dec 11 '13 at 10:46
  • There is one problem with this code though. The `ShowWindow(FindWindowA("TFMAppClass", NULL), SW_HIDE)` will hide the first window with this class it finds, which might not be the one for your app. What if you have two Firemonkey apps running, or two instances of one... It would be better to use something like `FindWindow('TFMAppClass', PChar(ChangeFileExt(ExtractFileName(ParamStr(0)), '')))` or even better combine it with `GetWindowThreadProcessId` and `FindWindowEx` to check if ti belongs to your process. – VGeorgiev Dec 11 '13 at 10:52
  • You should be using `EnumWindows()` instead of calling `FindWindow()` in a loop. – Remy Lebeau Dec 13 '18 at 20:19
0
procedure HideAppOnTaskbar;
var
  appHandle: HWND;
  pid, current_pid: DWORD;
  name: String;

begin
  //ShowWindow(FindWindowA('TFMAppClass', nil), SW_HIDE);

  name := ChangeFileExt(ExtractFileName(ParamStr(0)), '');

  appHandle := 0;
  pid := 0;
  current_pid := GetCurrentProcessId();
  repeat
  begin
    //appHandle := FindWindowExA(0, appHandle, 'TFMAppClass', nil);
    appHandle := FindWindowExA(0, appHandle, 'TFMAppClass', PAnsiChar(AnsiString(name)));
    if (appHandle>0) then
    begin
      GetWindowThreadProcessId(appHandle, pid);
      if (current_pid = pid) then break;
    end;
  end
  until (appHandle>0);

  //SetParent(FmxHandleToHWND(Handle), nil);
  ShowWindow(appHandle, SW_HIDE);

end;
0

This is for Delphi 10.3, it might work in other versions too.

I don't know if you noticed, but whenever your code reachs FormCreate procedure, your FMX application will already have created a taskbar button, at least on Delphi 10.3.3 Rio, which is something we might not like. So if you use the suggested methods your application will fastly show its icon in the taskbar just to hide it.

So if you have access to Delphi's VCL/FMX source code files, and you don't like to show your application taskbar icon not even for a millisecond, you just have to modify FMX.Platform.Win.pas file located at c:\Program Files (x86)\Embarcadero\Studio\20.0\source\fmx\ directory, then copy it to your projects directory, so it will be picked instead of the original one, and modify the CreateAppHandle function as suggested below:

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 // modified/added line
    Winapi.Windows.ShowWindow(Result, SW_HIDE) // modified/added line
  else // modified/added line
    Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL);
end;   

That's it, you won't need the other methods, notice it also has CreateWindowEx passing the styles for your window, if you want to hide it from Alt-Tab list too, replace WS_EX_APPWINDOW with WS_EX_TOOLWINDOW instead.

vhanla
  • 750
  • 5
  • 15