2011-12-01 26 views
5

私はシステムトレイのアイコンを持つアプリケーションを持っています。アンインストール中に、実行中の場合はプロセスを終了します。したがって、アプリケーションを正常に停止していないので、アイコンはシステムトレイに残っており、マウスをマウスの上に置いた場合にのみアイコンが削除されます。私はトレーに沿ってカーソルを動かし、カーソルを最初の位置に戻すコードを書いた。システムトレーのアイコンをプログラムでリフレッシュ

 [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; 
     } 

このオプションは、「通知アイコンを表示しない」場合を除き、すべてのケースでは良い作品有効になっている:これは私がやっていることです。この場合トレイをリフレッシュできる方法はありますか?

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

+2

よく似たような状況が1度ありました。私がしたことは、Form_ClosingイベントのNotifyIconコンポーネントから取り除かれ、うまくいきました。 –

+3

アンインストーラから、アプリケーションとのやりとりをする方法があまりにもハッキリではないかもしれません。 (私はこの分野で知識がありませんが) –

+8

あなたはこのようなコードを書いたくありません。殺してはいけません。 –

答えて

1

パイプやTCPのようなものを使用して現在のインスタンスを閉じるのは難しくありません。そうしたくない場合や.NET4.0を実行していない場合はTCPを使用してください。

誰もが指摘しているように、プロセスを強制終了するとトレイアイコンインスタンスの登録を解除することはできないため、Windowsがイベントを送信しようとするまでスティックされます。その上にマウスを置いてください)、その時点でWindowsはそれを削除します。

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

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

8

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

これらのキーボードには2つのキーボードがあります。

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

注記 - これは英語のロケールインストールでのみ機能します。これを別の言語で動作させるには、「User Promoted Notification Area」と「Notification Area」を翻訳された同等の文字列に変更します。

[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); 
} 
+0

アプリがすでに実行されているかどうかを確認して、それらを教えたりフォーカスしたりするのではなく、それをやり直して再起動する方法はありますか? – mbomb007

+0

この回答は、少なくとも私の環境ではWindows 10x64で最も効果的です。表示されたものと非表示の両方からアイコンを削除します:http://maruf-dotnetdeveloper.blogspot.com/2012/08/c-refreshing-system-tray-icon.html)表示されているものを削除します。 –

+0

Resource Hackerを使用して、%windir%\ system32 \ \ explorer32.exe.muiにローカライズされた文字列を探します。必要なWindows言語パック(MUI)をインストールする必要があります。 – mcandal

関連する問題