Отсутствует контекстное меню кнопки панели задач в Windows XP с FM3

Недавно я обновился до XE4 и сейчас нахожусь в процессе поиска изменений и так называемых исправлений из XE3.

Меня очень удивило то, что контекстное меню для кнопки на панели задач больше не появляется.

Его очень легко скопировать: просто создайте новый проект Firemonkey в XE4 и запустите его в Windows. Щелкните правой кнопкой мыши кнопку приложения на панели задач и посмотрите, появляется ли контекстное меню. Я имею в виду меню с "Закрыть", "Восстановить", "Свернуть" и т. Д. Это только в Windows XP и Server 2003. На Win7 работает и показывает пункт меню "Закрыть".

Также название кнопки теперь другое. Это должна быть "Форма 1" в качестве заголовка основной формы, но вместо этого это Project1 в качестве имени исполняемого файла. Это на всех версиях Windows.

Может ли кто-нибудь помочь мне с этим? Люди все еще используют XP, и это поведение совершенно неожиданно для пользователя.

Спасибо

1 ответ

Решение

Прошло некоторое время с тех пор, как я задал вопрос, но тем временем я нашел решение и опубликую его, если оно будет полезно для кого-то другого.

Проблема с неправильным заголовком и отсутствующим меню связана с тем, что Delphi XE4 изменил структуру окон приложений Firemonkey. До этого окно основной формы размещалось на панели задач и имело соответствующий заголовок и контекстное меню. В XE4 приложение создает новое окно с именем класса "TFMAppClass" и использует его в качестве основного окна приложения, которое размещается на панели задач. Главное окно формы - это родной брат этого окна.
Это приводит к тому, что невозможно установить заголовок кнопки панели задач, не иметь контекстного меню, неправильно реагировать на нажатия на кнопку и не скрывать кнопку, когда скрыта основная форма.

Итак, нужно было скрыть окно приложения от панели задач и вместо этого показать окно формы. Однако сделать это один раз недостаточно, поскольку стиль окна приложения сбрасывается при каждом сворачивании / восстановлении, и он появляется на панели задач.

Чтобы скрыть окно приложения, просто позвоните ShowWindow(AppWindowHandle, SW_HIDE),
Чтобы показать главное окно формы на панели задач, мы должны установить WS_EX_APPWINDOW расширенный стиль окна с SetWindowLong() и позвонить ShowWindow каждый раз, когда приложение отображается, восстанавливается и т. д. и выводить его на передний план.

Это делается путем помещения ловушки для перехвата сообщений WM_CREATE, WM_SHOWWINDOW и WM_ACTIVATE и применения стилей при вызове этих сообщений. Чтобы упростить использование, весь код размещается в одном блоке, а хук устанавливается в initialization часть.
Нет функций для вызова. Чтобы использовать устройство, просто поместите его где-то в uses пункт.

unit FM3TaskbarFix;

interface

implementation

{$IFDEF MSWINDOWS}
uses
  Winapi.Messages, Winapi.Windows, System.Sysutils, Fmx.Forms, Fmx.Platform.Win;

var
  GHookHandle: HHOOK;      // Handle for the hook we set
  GAppWnd    : HWND = 0;   // Handle of the main application window

function CallWndProc(nCode: Integer; iWParam: WPARAM; iLParam: LPARAM): LRESULT; stdcall;
var
  ActiveThreadID, WindowThreadID: DWORD;
  ProcMsg: TCWPStruct;
begin
  Result := CallNextHookEx(GHookHandle, nCode, iWParam, iLParam);

  if (nCode < 0) then
    Exit;

  ProcMsg := PCWPStruct(iLParam)^;

  case ProcMsg.message of
    WM_CREATE:
      // Save the "main" app window handle for later usage. There is only one window with the TFMAppClass class per app
      if (GAppWnd = 0) and (PCREATESTRUCT(ProcMsg.lParam)^.lpszClass = 'TFMAppClass') then
        GAppWnd := ProcMsg.hwnd;

    WM_ACTIVATE, WM_SHOWWINDOW:
    begin
      // Hide the app window. This has to be called on each minimize, restore, etc.
      if IsWindowVisible(GAppWnd) then
        ShowWindow(GAppWnd, SW_HIDE);

      // Only handle Show/Activate. wParam of 1 means the app is shown or activated, NOT hidden or deactivated
      // Also apply the style settings only to the Application.MainForm
      // We don't want to show other forms on the taskbar
      if (ProcMsg.wParam = 1) and
         (GetWindow(ProcMsg.hwnd, GW_OWNER) = GAppWnd) and Assigned(Application.MainForm) and
         (WindowHandleToPlatform(Application.MainForm.Handle).Wnd = ProcMsg.hwnd) then
      begin
        // Show the main form on the taskbar
        SetWindowLong(ProcMsg.hwnd, GWL_EXSTYLE, GetWindowLong(ProcMsg.hwnd, GWL_EXSTYLE) or WS_EX_APPWINDOW);
        ShowWindow(ProcMsg.hwnd, SW_SHOW);

        ActiveThreadID := GetWindowThreadProcessId(GetForegroundWindow, nil);
        WindowThreadID := GetWindowThreadProcessId(ProcMsg.hwnd, nil);
        AttachThreadInput(WindowThreadID, ActiveThreadID, True);
        try
          SetForegroundWindow(ProcMsg.hwnd);
          SetActiveWindow(ProcMsg.hwnd);
        finally
          AttachThreadInput(WindowThreadID, ActiveThreadID, False);
        end;
      end;
    end; { WM_ACTIVATE, WM_SHOWWINDOW }

  end; { case }
end;

initialization
  GHookHandle := SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, 0, GetCurrentThreadID);

finalization
  UnhookWIndowsHookEx(GHookHandle);

{$ENDIF}

end.

Кстати, этот код основан на двух примерах из сети. Я не знаю, кто авторы, но я отдаю им должное за идею.
Осталась одна проблема. Когда приложение впервые свернуто, кнопка окна приложения временно появляется вместо кнопки формы. После того, как приложение восстановлено или свернуто, этого больше не происходит.

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