Параметры для закрытия приложения пользовательского интерфейса из службы Windows в C # - PullRequest
0 голосов
/ 31 августа 2011

Я бы хотел услышать любые варианты закрытия приложения Win UI из службы Windows. Мой сервис работает под системной учетной записью. Приложение пользовательского интерфейса запускается для каждого вошедшего в систему пользователя, поэтому может быть много экземпляров приложения. Мне нужно закрыть их все. Я знаю имя процесса пользовательского интерфейса и могу связываться с каждым экземпляром процесса и kill it. НО в приложении есть иконка в трее, которая остается видимой (иконка-призрак, исчезает при наведении мышью) после завершения процесса. Я хотел бы закрыть приложение пользовательского интерфейса правильно, с помощью управляемого или неуправляемого кода. Любые идеи будут с благодарностью.

ДОПОЛНЕНИЕ 1: Приложение UI не имеет главного окна, а только значок в трее (компонент NotifyIcon).

ДОПОЛНЕНИЕ 2: Я могу изменить исходный код приложения пользовательского интерфейса. Но он написан так, что не позволяет ему получать сообщения окна CUSTOM, только стандартные.

ДОПОЛНЕНИЕ 3: Приложение пользовательского интерфейса не показывает никакой формы, оно просто создает ApplicationContext и выполняет NotifyIcon в контексте.

Program.cs

public static class Program
{
    [STAThread]
    private static void Main()
    {
        ApplicationContext context = new TrayApplicationContext();
        Application.Run(context);
    }
}

ТИА Иван

Ответы [ 3 ]

1 голос
/ 31 августа 2011

Вызов Process.CloseMainWindow вместо Kill.

Если у вас есть доступ к исходному коду приложения WinUI, то в основной форме (той, которую вы запускаете в Application.Run(mainFormGoesHere)) подпишитесь на событие закрытия и сделайте notifyIcon.Visible = false; непосредственно перед выходом.Это известная проблема с NotifyIcon и системным треем.

Если это стороннее приложение, то надеемся, что в них тоже реализовано что-то подобное для правильной очистки после того, как его попросят закрыть через CloseMainWindow()

Еще один подход - попытатьсяобновите системный трей с вашего сервиса, как описано здесь

public const int WM_PAINT = 0xF;
[DllImport("USER32.DLL")]
public static extern int SendMessage(IntPtr hwnd, int msg, int character, IntPtr lpsText);


//Send WM_PAINT Message to paint System Tray which will refresh it.
SendMessage(traynotifywnd,WM_PAINT,0,IntPtr.Zero);
0 голосов
/ 31 августа 2011

Может быть, глупо, и я не уверен, что это может работать в течение нескольких сеансов.
Определить пользовательское сообщение и отправить его в широковещательную рассылку, используя PostMessage;в вашем приложении перехватывайте входящие сообщения и, если вы получите свое, закройте изящно.

В службе:

public const int HWND_BROADCAST = 0xffff;
[DllImport("user32")]
public static extern bool PostMessage(int hwnd, int msg, int wparam, int lparam);
int WM_MYMSG = WM_USER + 1;

Когда вам нужно отправить сообщение:

PostMessage(HWND_BROADCAST,WM_MYMSG,0,0);

В вашем приложении:

int WM_MYMSG = WM_USER + 1;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MYMSG) Close();
    base.WndProc(ref m);
}

РЕДАКТИРОВАНИЕ:

Если вы хотите переопределить WndProc, вам нужна форма, ноэто не значит, что вам нужно показывать форму: в вашем приложении создайте форму и запустите ее, а в коде формы вы пишете:

private void Form1_Shown(object sender, EventArgs e)
{
    // Show here tray icon
    ....
    ....

    // Hide form
    this.Hide();
}
int WM_MYMSG = WM_USER + 1;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MYMSG) Close();
    base.WndProc(ref m);
}
0 голосов
/ 31 августа 2011

Попробуйте отправить сообщение WM_CLOSE приложению:

const uint WM_CLOSE = 0x10;

[DllImport("user32.dll",EntryPoint="SendMessage", SetLastError=true)]
public static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int
lParam);

SendMessage(hWnd, WM_CLOSE, 0, 0);

hWnd - дескриптор главного окна процесса, которое вы пытаетесь закрыть.Возможно, вам также понадобится отправить то же сообщение на дескриптор окна значка уведомления


ОБНОВЛЕНИЕ Поскольку вы не можете получать пользовательские сообщения, вы можете попробовать это:

  1. перечисление всех окон
  2. итерация по каждому окну и получение идентификатора процесса
  3. , если идентификатор процесса совпадает с тем, который вы хотите завершить, отправьте ему WM_CLOSE

получение идентификатора процесса для hWnd:

[DllImport("user32")]
static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
...