2011-12-01 13 views
5

Tengo una aplicación que tiene un icono de bandeja del sistema. Mientras desinstalo estoy matando el proceso si se está ejecutando. Entonces, como no estoy deteniendo la aplicación, el ícono permanece en la bandeja del sistema y se eliminará solo si colocamos el mouse sobre él. Escribí un código que corría el cursor a lo largo de la bandeja y devolvía el cursor a su posición inicial. Esto es lo que he hecho:Actualizando iconos de la bandeja del sistema programáticamente

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

Esto funciona bien en todos los casos, excepto cuando la opción "No mostrar los iconos de notificación" está activado. ¿Hay alguna manera de que pueda actualizar la bandeja en este caso?

EDIT Como sugerí los comentarios, cambié mi enfoque. En lugar de matar la aplicación de la bandeja, establecí una comunicación entre mi servicio de aplicación (sí, olvidé mencionar, también tengo un servicio que se ejecuta junto con la aplicación) y la aplicación de la bandeja. Durante la desinstalación, detengo el servicio, desde el método de parada de servicio envié un mensaje de socket de un formato particular a la aplicación de bandeja y solicité que se cerrara y establecía la visibilidad del icono de notificación como falsa. Esto dejaría la aplicación de la bandeja ejecutándose en segundo plano, así que estoy usando "taskkill" para eliminar la aplicación. Funcionó bien en Win7 y Vista, pero no funciona correctamente en Win XP. Pero no he escrito ningún código específico del entorno. ¿Alguna pista posible?

+2

Bueno, una vez tuve una situación similar. Lo que hice fue deshacerse del componente NotifyIcon en el evento Form_Closing y funcionó bien. –

+3

Una forma menos hacky podría ser tener una forma de comunicarse con su aplicación, desde el desinstalador. (aunque no tengo conocimiento en esta área) –

+8

No desea escribir código como este. No mates, pregunta amablemente. –

Respuesta

1

No debería ser difícil cerrar la instancia actual usando algo como pipes, o TCP si no tiene ganas de hacerlo y no está ejecutando .NET4.0.

Como todos insinúan, el problema es que matando su proceso no tiene la oportunidad de anular el registro de su instancia de icono de bandeja, por lo que se queda hasta que Windows intenta enviarle un evento (la próxima vez que se mude) el mouse sobre él) en cuyo punto Windows lo eliminará.

Según el instalador que esté utilizando, esto podría ser bastante fácil o más difícil. La mayoría de los frameworks de instaladores populares permiten complementos, y algunos de ellos admiten Pipes, muchos más soportan solicitudes TCP. Alternativamente, escriba un pequeño ejecutable que su instalador pueda ejecutar antes de que comience el proceso de desinstalación, que se comunica con su aplicación principal y envía un mensaje de cierre.

Como nota final, si puede usar .NET4.0, le sugiero que mire el espacio de nombres System.IO.Pipes incorporado y las clases incluidas.

8

Eso es similar a lo que uso. Un teclado flotante simple que agregué a la interfaz de una galería táctil. El usuario también quería tener mi teclado como una aplicación independiente en su escritorio. Así que hice esto, creé una aplicación de bandeja para eso. Ahora, ¿qué ocurre si está abierto y lanzan mi galería?

Tendrían dos teclados.

Claro, el usuario podría terminar el primero, pero es más fácil terminarlo. No hay repercusiones de que lo mate, así que lo hago. Pero el icono de la bandeja permanece, ya que está esperando un evento. Para evitar esto, actualizo el área de la bandeja.

Tenga en cuenta - Esto solo funcionaría en una instalación de configuración regional en inglés. Para que esto funcione en otro idioma, cambie "Área de notificación promocionada por el usuario" y "Área de notificación" a la cadena traducida/equivalente.

[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

¿No hay alguna forma de que puedas comprobar si la aplicación ya se está ejecutando y decirles o enfocarla, en lugar de eliminarla y volver a iniciarla? – mbomb007

+0

Esta respuesta funciona mejor, al menos para mi entorno Windows 10x64. Quita los íconos tanto de los mostrados como los ocultos que el que se encontró en: (http://maruf-dotnetdeveloper.blogspot.com/2012/08/c-refreshing-system-tray-icon.html) no eliminar los que se muestran. –

+0

Busque cadenas localizadas en% windir% \ system32 \ \ explorer32.exe.mui utilizando Resource Hacker. Necesita instalar el paquete de idioma de Windows deseado (MUI). – mcandal

Cuestiones relacionadas