我最近升级到XE4,现在正在从XE3查找更改和所谓的修复程序。

让我非常惊讶的是,任务栏上的按钮的上下文菜单不再显示。

复制非常容易:只需在XE4中创建一个新的Firemonkey项目并在Windows上运行它即可。右键单击任务栏应用程序按钮,然后查看上下文菜单是否出现。我指的是带有“关闭”,“还原”,“最小化”等的菜单。
这仅适用于Windows XP和Server2003。在Win7上,它可以工作并显示“关闭”菜单项。

现在按钮的标题也不同了。它应为“ Form 1”作为主窗体的标题,但应为Project1作为可执行文件的名称。
这是所有Windows版本上的。

有人可以帮我吗?人们仍然使用XP,这种行为对于用户来说是非常意外的。

谢谢

最佳答案

自从我问这个问题以来已经过去了一段时间,但是我在此期间找到了一个解决方案,并将其发布,以防对其他人有用。

标题错误和菜单丢失的问题是由于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.


顺便说一句,此代码基于来自网络的两个样本。我不知道作者是谁,但我赞扬他们的想法。
仍然存在一个问题。首次最小化应用程序时,应用程序窗口的按钮会临时出现,而不是表单按钮。在应用恢复或最小化后,这种情况不再发生。

关于delphi - Windows XP with FM3中缺少任务栏按钮上下文菜单,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18349845/

10-13 07:17