8

システム トレイ アイコンを持つアプリケーションがあります。アンインストール中に、実行中のプロセスを強制終了しています。そのため、アプリを正常に停止していないため、アイコンはシステム トレイに残り、マウスをその上に置いた場合にのみ削除されます。トレイに沿ってカーソルを実行し、カーソルを初期位置に戻すコードを作成しました。これは私がやったことです:

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string className, string windowName);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindowEx(IntPtr parent, IntPtr child, string className, string windowName);
        [DllImport("user32.dll")]
        static extern bool GetWindowRect(HandleRef handle, out RECT rct);

        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        void RefreshTray()
        {
            IntPtr taskbar_Handle = FindWindow("Shell_Traywnd", "");
            IntPtr tray_Handle = FindWindowEx(taskbar_Handle, IntPtr.Zero, "TrayNotifyWnd", "");

            RECT rct;

            if (!(GetWindowRect(new HandleRef(null, tray_Handle), out rct)))
            {
            }

            System.Drawing.Point init = Control.MousePosition;

            for (int i = rct.Left; i < rct.Right-20; i++)
            {
                Cursor.Position = new System.Drawing.Point(i, (rct.Bottom + rct.Top) / 2);
            }

            Cursor.Position = init;
         }

これは、「通知アイコンを表示しない」オプションが有効になっている場合を除いて、すべての場合にうまく機能します。この場合、トレイを更新する方法はありますか?

編集 コメントが示唆したように、私はアプローチを変更しました。トレイ アプリケーションを強制終了する代わりに、アプリケーション サービス (言い忘れましたが、アプリケーションと一緒にサービスも実行しています) とトレイ アプリケーションの間の通信を確立しました。アンインストール中にサービスを停止します。サービス停止メソッドから、特定の形式のソケット メッセージをトレイ アプリケーションに送信して閉じるように依頼し、通知アイコンの可視性を false に設定します。これにより、トレイ アプリケーションがバックグラウンドで実行されたままになるため、「タスクキル」を使用してアプリケーションを削除しています。Win7 と Vista では問題なく動作しましたが、Win XP では正しく動作しません。しかし、私は環境固有のコードを書いていません。考えられる手がかりはありますか?

4

4 に答える 4

12

それは私が使っているものと似ています。タッチ ギャラリー インターフェイスに追加したシンプルなフローティング キーボード。ユーザーは、私のキーボードをデスクトップ上のスタンドアロン アプリケーションとして使用することも望んでいました。だから私はこれを行い、そのためのトレイアプリを作成しました。今 - もしそれが開いていて、彼らが私のギャラリーを立ち上げたらどうしますか?

彼らは2つのキーボードを持っていました。

確かに - ユーザーは最初のものを終了できますが、ただ終了する方が簡単です。私がそれを殺しても影響はないので、そうします。ただし、イベントを待っているため、トレイアイコンは残ります。これを回避するために、トレイ領域を更新します。

注意- これは、英語ロケールのインストールでのみ機能します。これを別の言語で動作させるには、「ユーザー プロモーテッド通知領域」と「通知領域」を翻訳済みまたは同等の文字列に変更します。

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
    string lpszWindow);

[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

public static void RefreshTrayArea()
{
    IntPtr systemTrayContainerHandle = FindWindow("Shell_TrayWnd", null);
    IntPtr systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
    IntPtr sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
    IntPtr notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
    if (notificationAreaHandle == IntPtr.Zero)
    {
        notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32",
            "User Promoted Notification Area");
        IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null);
        IntPtr overflowNotificationAreaHandle = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero,
            "ToolbarWindow32", "Overflow Notification Area");
        RefreshTrayArea(overflowNotificationAreaHandle);
    }
    RefreshTrayArea(notificationAreaHandle);
}

private static void RefreshTrayArea(IntPtr windowHandle)
{
    const uint wmMousemove = 0x0200;
    RECT rect;
    GetClientRect(windowHandle, out rect);
    for (var x = 0; x < rect.right; x += 5)
        for (var y = 0; y < rect.bottom; y += 5)
            SendMessage(windowHandle, wmMousemove, 0, (y << 16) + x);
}
于 2012-02-29T14:18:05.177 に答える
2

パイプなどを使用して現在のインスタンスを閉じることは難しくありません。または、それを行う気がなく、.NET4.0 を実行していない場合は TCP を使用します。

誰もが暗示しているように、問題は、プロセスを強制終了すると、そのトレイ アイコン インスタンスの登録を解除する機会が得られないため、Windows がイベントをプロセスに送信しようとするまで (次にマウスをその上に移動するまで) 残り続けることです。 ) その時点で、Windows はそれを削除します。

使用しているインストーラーによって、これは非常に簡単な場合もあれば、より難しい場合もあります。ほとんどの一般的なインストーラー フレームワークはプラグインを許可し、それらのいくつかはパイプをサポートし、さらに多くは TCP 要求をサポートします。または、インストーラーがアンインストール プロセスを開始する前に実行できる小さな実行可能ファイルを作成します。これにより、プライマリ アプリと通信し、クローズ メッセージが送信されます。

最後に、.NET4.0 を使用できる場合は、組み込みの System.IO.Pipes 名前空間と含まれているクラスを確認することをお勧めします。

于 2012-01-19T17:49:40.727 に答える
2

このツールを使用 http://www.codeproject.com/Articles/19620/LP-TrayIconBuster

TrayNotifyWnd と NotifyIconOverflowWindow の ToolBarButtons を反復処理し、null ファイル名を持つものを削除します。

于 2013-07-10T15:11:05.793 に答える
0

この(http://maruf-dotnetdeveloper.blogspot.com/2012/08/c-refreshing-system-tray-icon.html)ソリューションがうまくいったことがわかりました。

于 2014-04-13T03:33:34.723 に答える