2

私は最近 XE4 にアップグレードしました。現在、XE3 からの変更点といわゆる修正点を見つけようとしています。

非常に驚いたのは、タスクバーのボタンのコンテキスト メニューが表示されなくなったことです。

複製は非常に簡単です。XE4 で新しい Firemonkey プロジェクトを作成し、Windows で実行するだけです。タスクバー アプリケーション ボタンを右クリックして、コンテキスト メニューが表示されるかどうかを確認します。「閉じる」、「復元」、「最小化」などのメニューを意味します。これは Windows XP および Server 2003 のみです。Win7 では機能し、「閉じる」メニュー項目が表示されます。

また、ボタンのタイトルも異なります。メイン フォームのキャプションとして "Form 1" である必要がありますが、代わりに実行可能ファイル名として Project1 になっています。これはすべての Windows バージョンにあります。

誰かがこれで私を助けることができますか? 人々はまだ XP を使用しており、この動作はユーザーにとってまったく予期しないものです。

ありがとう

4

1 に答える 1

0

質問してからしばらく経ちましたが、その間に解決策を見つけたので、他の人に役立つ場合に備えて投稿します.

間違ったキャプションと欠落したメニューの問題は、Delphi XE4 が Firemonkey アプリのウィンドウ構造を変更したことに起因しています。それ以前は、メイン フォームのウィンドウはタスク バーに配置され、適切なキャプションとコンテキスト メニューがありました。XE4 では、アプリは「TFMAppClass」というクラス名で新しいウィンドウを作成し、それをタスクバーに配置されるメイン アプリケーション ウィンドウとして使用します。メイン フォーム ウィンドウは、その兄弟です。
これにより、タスクバー ボタンのキャプションを設定できず、コンテキスト メニューがなく、ボタンのクリックに適切に応答せず、メイン フォームが非表示のときにボタンを非表示にできません。

そのため、タスクバーからアプリ ウィンドウを非表示にして、代わりにフォーム ウィンドウを表示する必要がありました。ただし、アプリ ウィンドウのスタイルは最小化/復元のたびにリセットされ、タスク バーに再表示されるため、1 回実行するだけでは十分ではありません。

アプリ ウィンドウを非表示にするには、単に を呼び出します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.

ところで、このコードはネットからの 2 つのサンプルに基づいています。著者が誰であるかはわかりませんが、アイデアの功績を称えます。
残っている問題が 1 つあります。アプリを最初に最小化すると、フォーム ボタンではなく、アプリ ウィンドウのボタンが一時的に再表示されます。アプリが復元または最小化された後、これはもう起こりません。

于 2013-12-12T08:22:56.110 に答える