2017-08-15 11 views
0

トレイにコンテキストメニューを表示するためにwinforms NotifyIconを使用するWPFアプリがあります。次の手順を実行するとアイコンが消えます。右ここダイアログ Alt + F4の後にNotifyIconを非表示にする原因は何ですか?

  • Altキー+ F4キー
  • であることを解任

  • モーダルダイアログを表示するコンテキストメニュー項目を選択し、トレイ
  • に通知アイコンをクリックしてください

    1. 私がこのバグを見る最小の例。

      XAML:背後

      <Window x:Class="killtrayicon.MainWindow" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
          xmlns:local="clr-namespace:killtrayicon" 
          mc:Ignorable="d" 
          Title="MainWindow" Height="350" Width="525"> 
      <Grid> 
          <Button Content="button" Click="Button_Click"/> 
      </Grid> 
      </Window> 
      

      コード:

      namespace killtrayicon 
      { 
          using System.Windows; 
      
          /// <summary> 
          /// Interaction logic for MainWindow.xaml 
          /// </summary> 
          public partial class MainWindow : Window 
          { 
           private System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon(); 
      
           public MainWindow() 
           { 
            InitializeComponent(); 
      
            notifyIcon.Icon = Properties.Resources.icon; 
            notifyIcon.Visible = true; 
            notifyIcon.Text = "test"; 
            notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(); 
            notifyIcon.ContextMenu.MenuItems.Add("click", (s, e) => 
            { 
             MessageBox.Show("menu"); 
            }); 
           } 
      
           private void Button_Click(object sender, RoutedEventArgs e) 
           { 
            notifyIcon.Icon = Properties.Resources.icon; 
           } 
          } 
      } 
      

      私のメインウィンドウのボタンをクリックすると、アイコンをリセットし、通知アイコンが再び表示されます。したがって、通知アイコン自体は削除されていません。 NotifyIconのインスタンスを調べると、アイコンがリセットされる前に表示され、Iconプロパティがリソース内の有効なICOを指していることがわかります。

      トレイアイコンをクリックしてモーダルダイアログを表示すると、この問題は発生しないため、コンテキストメニューが問題であると思われます。

      NotifyIconがAlt + F4に応答しないようにするにはどうすればよいですか?

      編集:この質問はと重複していますが、この問題には問題を再現するためのサンプルコードがありません(デッドリンク)。Microsoftに提出された問題へのリンクもデッドリンクです。実際の解決策。

  • +0

    死んだリンクがなくても良い言葉遣いの質問をするにはどうしたらいいですか? – cppguy

    答えて

    1

    解決策を発見しました。 NotifyIconは、Shell_NotifyIconで作成されたアイコンによって生成されたウィンドウメッセージの受信者として隠しファイルNativeWindowを作成します。そのウィンドウは他のウィンドウと同様にAlt+F4を処理するデフォルトのウィンドウprocを使用しています。これをWM_CLOSEに変更します。 Win32 APIを使用して、NativeWindowHWNDをサブクラス化し、WM_CLOSEを傍受し、それを無視する必要があります。その後、隠されたトレイアイコンウィンドウをサブクラス化するために、あなたのNotifyIconにコードを追加

    public static class Comctl32 
    { 
        public const string DLL = "comctl32.dll"; 
    
        public const uint WM_CLOSE = 0x0010; 
        public const uint WM_NCDESTROY = 0x0082; 
    
        public delegate IntPtr SubclassWndProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam, UIntPtr uIdSubclass, UIntPtr dwRefData); 
    
        [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 
        public static extern bool SetWindowSubclass(
         [param: In] 
          IntPtr hWnd, 
         [param: In] 
          SubclassWndProc pfnSubclass, 
         [param: In] 
          UIntPtr uIdSubclass, 
         [param: In] 
          UIntPtr dwRefData); 
    
        [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 
        public static extern bool RemoveWindowSubclass(
         [param: In] 
          IntPtr hWnd, 
         [param: In] 
          SubclassWndProc pfnSubclass, 
         [param: In] 
          UIntPtr uIdSubclass); 
    
        [DllImport(DLL, CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)] 
        public static extern IntPtr DefSubclassProc(
         [param: In] 
          IntPtr hWnd, 
         [param: In, MarshalAs(UnmanagedType.U4)] 
          uint uMsg, 
         [param: In] 
          UIntPtr WPARAM, 
         [param: In] 
          UIntPtr LPARAM); 
    } 
    

    まず、COMCTL32.DLLからいくつかのWin32メソッドを追加します。それは公共のではありませんので、あなたは、窓口で取得するためにリフレクションを使用する必要があります:

    private Native.Comctl32.SubclassWndProc subclassWndProc; 
    
    ... 
    
    // Get the HWND from the notify icon 
    Type notifyIconType = typeof(System.Windows.Forms.NotifyIcon); 
    BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance; 
    var window = notifyIconType.GetField("window", hidden).GetValue(this.notifyIcon) as System.Windows.Forms.NativeWindow; 
    
    // Inject our window proc to intercept window messages 
    this.subclassWndProc = this.TrayWndProc; 
    Native.Comctl32.SetWindowSubclass(window.Handle, this.subclassWndProc, UIntPtr.Zero, UIntPtr.Zero); 
    

    その後WM_CLOSE傍受Alt+F4を無視します。 WM_NCDESTROYのサブクラス化を解除することも確認してください。

    private IntPtr TrayWndProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam, UIntPtr uIdSubclass, UIntPtr dwRefData) 
    { 
        switch (uMsg) 
        { 
         // Ignore the close message to avoid Alt+F4 killing the tray icon 
         case Native.Comctl32.WM_CLOSE: 
          return IntPtr.Zero; 
    
         // Clean up subclassing 
         case Native.Comctl32.WM_NCDESTROY: 
          Native.Comctl32.RemoveWindowSubclass(hWnd, this.subclassWndProc, UIntPtr.Zero)) 
          break; 
        } 
    
        // Invoke the default window proc 
        return Native.Comctl32.DefSubclassProc(hWnd, uMsg, wParam, lParam); 
    } 
    
    関連する問題