3

WinForms UI の別のプロセスからシステム メニュー (最小化、復元などを含む) を表示しようとしています。GetSystemMenu や TrackPopupMenuEx などの相互運用呼び出しが必要であることは理解していますが、機能させることができませんでした。誰かがそれを行う方法のサンプルコードを提供できますか?

このコード スニペット (WPF 用) を見つけました: 別のアプリケーションのシステム メニューを開く

私はそれを次のように変更しました:

    const uint TPM_LEFTBUTTON = 0x0000;
    const uint TPM_RETURNCMD = 0x0100;
    const uint WM_SYSCOMMAND = 0x0112;

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    public void ShowContextMenu()
    {
        IntPtr wMenu = GetSystemMenu(ExternalWindowHandle, false);
        // Display the menu
        uint command = TrackPopupMenuEx(wMenu, TPM_LEFTBUTTON | TPM_RETURNCMD, 10, 10, ExternalWindowHandle, IntPtr.Zero);
        if (command == 0)
            return;
        PostMessage(ExternalWindowHandle, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero);
    }

質問のタイトルで述べたように、システム トレイのウィンドウを最小化したくありません。別のプロセス (ウィンドウ) から選択した場所にシステム メニューを表示したいと考えています。Windows のタスクバーとほぼ同じです。タスクバー(エクスプローラー)は、タスクバー上で右クリックするとシステムメニューを表示できるようです。

ありがとう、ステファン

4

1 に答える 1

5

コードの作業バージョンもあり、MSDN ライブラリをチェックしたところ、TrackPopupMenuEx メソッドが渡された "ExternalWindowHandle" 変数を機能させるには、ハンドルが表すウィンドウがフォアグラウンドにある必要があることがわかりました。デスクトップ。

MSDN ライブラリには次のように書かれています。

"通知アイコンのコンテキスト メニューを表示するには、アプリケーションが TrackPopupMenu または TrackPopupMenuEx を呼び出す前に、現在のウィンドウがフォアグラウンド ウィンドウである必要があります。そうでない場合、ユーザーがメニューまたはメニューを作成したウィンドウの外側をクリックしても、メニューは消えません (表示されている場合). 現在のウィンドウが子ウィンドウの場合, (最上位の) 親ウィンドウを前景ウィンドウとして設定する必要があります." http://msdn.microsoft.com/en-us/library/windows/desktop/ms648003(v=vs.85).aspx

つまり、ウィンドウがアクティブなウィンドウであり、フォアグラウンドにある場合にのみ機能します。たとえば、ビジュアル スタジオでデバッグしている場合、ウィンドウはフォアグラウンドにないため、つまり、ビジュアル スタジオはアプリではないため、機能しません。

同封の実際のコード例を参照してください。アプリ ウィンドウがフォーカス/フォアグラウンドにある場合にのみ機能することに注意してください。つまり、デバッグ中または別のウィンドウを使用している場合、TrackPopupMenuEx は常に 0 を返します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        const uint TPM_LEFTBUTTON = 0x0000;
        const uint TPM_RETURNCMD = 0x0100;
        const uint WM_SYSCOMMAND = 0x0112;

        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        public static void ShowContextMenu(IntPtr appWindow, IntPtr myWindow, Point point)
        {
            IntPtr wMenu = GetSystemMenu(appWindow, false);
            // Display the menu
            uint command = TrackPopupMenuEx(wMenu,
                TPM_LEFTBUTTON | TPM_RETURNCMD, (int)point.X, (int)point.Y, myWindow, IntPtr.Zero);
            if (command == 0)
                return;

            PostMessage(appWindow, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ShowContextMenu(new IntPtr(<<put your target window handle here>>), this.Handle, new Point(0, 0));
        }
    }
}
于 2013-03-05T19:21:00.540 に答える