Как скрыть кнопку приложения firemonkey с панели задач (XE4)?

В соответствии с этим вопросом можно скрыть значок панели задач fmx, изменив стиль окна на WS_EX_TOOLWINDOW. В XE2 и XE3 этот код работает:

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;

В XE4 это решение не работает (кнопка приложения должна стать скрытой, но ничего не происходит). любое тело есть идеи?

Благодарю.

5 ответов

Решение
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);

Просто попробовал это в XE7 и конечно не получилось. Однако небольшой взгляд на FMX.PlatformWin показывает, что дескриптор приложения теперь доступен через функцию ApplicationHWND, поэтому код, который работает на XE7 (не забудьте включить модуль FMX.Platform.Win а также Winapi.Windows) является...

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;

ShowWindow в конце не является обязательным - кажется, нет никакой разницы. Вы можете удалить расширенные стили и восстановить стиль WS_EX_APPWINDOW, чтобы снова отобразить значок панели инструментов.

Похоже, что в приложениях XE4 FM больше нет дескриптора для объекта приложения. Итак, нам нужно получить родителя основной формы. Ниже два небольших метода, чтобы скрыть / показать ваше приложение на панели задач.

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;

Мы могли бы также использовать "Application.MainForm" вместо передачи основной формы, но эта переменная не была назначена во время события "OnCreate" основной формы.

Таким образом, в вашем "OnCreate" Event вне вашей основной формы вы можете просто написать:

procedure TMyMainForm.FormCreate(Sender: TObject);
begin
  HideAppOnTaskbar (self);
end;
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;

Это для Delphi 10.3, может работать и в других версиях.

Я не знаю, заметили ли вы, но всякий раз, когда ваш код достигает процедуры FormCreate , ваше приложение FMX уже создает кнопку на панели задач, по крайней мере, в Delphi 10.3.3 Rio, что нам может не понравиться. Поэтому, если вы используете предложенные методы, ваше приложение быстро отобразит свой значок на панели задач, чтобы скрыть его.

Поэтому, если у вас есть доступ к файлам исходного кода Delphi VCL/FMX, и вы не хотите, чтобы значок панели задач вашего приложения отображался даже на миллисекунду, вам просто нужно изменить FMX.Platform.Win.pasфайл, расположенный по адресу c:\Program Files (x86)\Embarcadero\Studio\20.0\source\fmx\каталог, затем скопируйте его в каталог ваших проектов, чтобы он был выбран вместо исходного, и измените CreateAppHandleдействовать, как предложено ниже:

      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;   

Вот и все, вам не понадобятся другие методы, обратите внимание, что он также имеет CreateWindowExпередавая стили для вашего окна, если вы хотите скрыть его и из списка Alt-Tab, замените WS_EX_APPWINDOWс WS_EX_TOOLWINDOWвместо.

Другие вопросы по тегам