2011-12-01 3 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. Это заставит приложение Tray работать в фоновом режиме, поэтому я использую «taskkill» для удаления приложения. Он отлично работал в Win7 и Vista, но не работает должным образом в Win XP. Но я не написал никакого кода, специфичного для среды. Любая возможная подсказка?

+2

Ну, у меня была подобная ситуация. То, что я сделал, было отключено от компонента NotifyIcon в событии Form_Closing, и он работал хорошо. –

+3

Менее опасным способом может быть способ общения с вашим приложением, с помощью деинсталлятора. (хотя у меня нет знаний в этой области) –

+8

Вы не хотите писать такой код. Не убивайте, спросите красиво. –

ответ

1

Не должно быть трудно закрыть текущий экземпляр, используя что-то вроде труб или TCP, если вам не нравится делать это и не работает .NET4.0.

Как все подразумевают, проблема заключается в том, что, убивая ваш процесс, у него нет возможности отменить регистрацию своего экземпляра значка в трее, поэтому он работает до тех пор, пока Windows не попытается отправить ему событие (при следующем перемещении мышь над ним), в этот момент Windows удалит его.

В зависимости от того, какой установщик вы используете, это может быть довольно легко или сложнее. Самые популярные рамки установщика допускают плагины, а некоторые из них поддерживают Pipes, и многие другие поддерживают запросы TCP. Кроме того, напишите небольшой исполняемый файл, который может выполнить ваш установщик, прежде чем он начнет процесс удаления, который связывается с вашим основным приложением и отправляет сообщение «Закрыть».

В заключение, если вы можете использовать .NET4.0, я бы предложил посмотреть встроенное пространство имен System.IO.Pipes и включенные классы.

8

Это похоже на то, что я использую. Простая плавающая клавиатура, которую я добавил в интерфейс сенсорной галереи. Пользователь хотел также иметь мою клавиатуру как отдельное приложение на своем рабочем столе. Поэтому я сделал это, создал для него приложение для лотка. Теперь - что, если его открыть, и они запустили мою галерею?

У них было бы две клавиатуры.

Уверенный - пользователь может завершить первый, но его проще просто закончить. Нет никаких последствий для меня, убивая его, поэтому я это делаю. Но значок в трее остается, так как он ждет события. Чтобы обойти это, я обновляю область Лоток.

Обращаем внимание: - Это будет работать только при установке на английском языке. Чтобы заставить это работать на другом языке, измените «Пользовательская зона уведомления о рекламе» и «Область уведомлений» на переведенную/эквивалентную строку.

[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

Этот ответ работает лучше всего, по крайней мере для моей среды, являющейся окнами 10x64. Он удаляет значки из показанных и скрытых, которые были найдены в: (http://maruf-dotnetdeveloper.blogspot.com/2012/08/c-refreshing-system-tray-icon.html), не удалите отображаемые. –

+0

Ищите локализованные строки в% windir% \ system32 \ \ explorer32.exe.mui, используя Resource Hacker. Вам необходимо установить желаемый языковой пакет Windows (MUI). – mcandal

Смежные вопросы