Отсутствует контекстное меню кнопки панели задач в 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.
Кстати, этот код основан на двух примерах из сети. Я не знаю, кто авторы, но я отдаю им должное за идею.
Осталась одна проблема. Когда приложение впервые свернуто, кнопка окна приложения временно появляется вместо кнопки формы. После того, как приложение восстановлено или свернуто, этого больше не происходит.