The Process of the Service Is Killed After the Application Is Removed from the Application Tray

The process of the service is killed after the application is removed from the application tray

Here is a workaround I came across and works well for re-starting a service if its process is killed on closing the application. In your service, add the following code.

I came across this workaround in this thread.

@Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());

PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);

super.onTaskRemoved(rootIntent);
}

Seems to be a bug that the process of the application is killed. There is no point for a service to run if its process is killed.

Tray icon does not disappear on killing process

There is no solution to this problem. If you kill process with task manager, it does not receive termination notification, and hence can not remove its icon from the tray. Try avoiding killing process this way. You can use net start/stop to kill a service or services.msc GUI.

App isn't killed when removed from recent tasks when using service

You are talking about the OS Process hosting your application, and not the "task" (which is an Android construct). Android is responsible to killing OS processes and reclaiming them. It does it when it wants to, if it wants to, and you have no control over this. You cannot assume that your OS Process will be killed in any specific case.

You need to write your code in such a way that you can deal with anything that happens.

NotifyIcon remains in Tray even after application closing but disappears on Mouse Hover

The only solution that worked for me was to use the Closed event and hide and dispose of the icon.

icon.BalloonTipClosed += (sender, e) => { 
var thisIcon = (NotifyIcon)sender;
thisIcon.Visible = false;
thisIcon.Dispose();
};

How to close WPF system tray application from another app?

As most of the time, I had to figure it out myself.
Here's how.

First: we have the process. The process has no main window, no windows at all, so all communication with windows is off the table. But the process has threads. And the threads have their message queue, though it's accessible with Win32 API.

So here's the receiving end:

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application {

// (...)

/// <summary>
/// Sent as a signal that a window or an application should terminate.
/// </summary>
const uint WM_CLOSE = 0x0010;

/// <summary>
/// Retrieves a message from the calling thread's message queue. The function dispatches incoming sent messages until a posted message is available for retrieval.
/// </summary>
/// <param name="lpMsg">MSG structure that receives message information from the thread's message queue.</param>
/// <param name="hWnd">A handle to the window whose messages are to be retrieved. The window must belong to the current thread. Use <see cref="IntPtr.Zero"/> to retrieve thread message.</param>
/// <param name="wMsgFilterMin">The integer value of the lowest message value to be retrieved.</param>
/// <param name="wMsgFilterMax">The integer value of the highest message value to be retrieved.</param>
/// <returns>Non-zero for any message but WM_QUIT, zero for WM_QUIT, -1 for error.</returns>
[DllImport("user32.dll")]
static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);

/// <summary>
/// Waits indefinitely for a specific thread message.
/// </summary>
/// <param name="signal">Signal, message value.</param>
private void WaitForSignal(uint signal) => GetMessage(out var msg, IntPtr.Zero, signal, signal);

/// <summary>
/// WPF application startup.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override async void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
// ... initialization code ...
await Task.Run(() => WaitForSignal(WM_CLOSE));
Shutdown();
}

// (...)

}

Sending end:

/// <summary>
/// Demo.
/// </summary>
class Program {

/// <summary>
/// Sent as a signal that a window or an application should terminate.
/// </summary>
const uint WM_CLOSE = 0x0010;

/// <summary>
/// Posts a message to the message queue of the specified thread. It returns without waiting for the thread to process the message.
/// </summary>
/// <param name="threadId">The identifier of the thread to which the message is to be posted.</param>
/// <param name="msg">The type of message to be posted.</param>
/// <param name="wParam">Additional message-specific information.</param>
/// <param name="lParam">Additional message-specific information.</param>
/// <returns></returns>
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostThreadMessage(uint threadId, uint msg, IntPtr wParam, IntPtr lParam);

/// <summary>
/// Closes a windowless application pointed with process name.
/// </summary>
/// <param name="processName">The name of the process to close.</param>
static void CloseWindowless(string processName) {
foreach (var process in Process.GetProcessesByName(processName)) {
using (process) {
foreach (ProcessThread thread in process.Threads) PostThreadMessage((uint)thread.Id, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}
}
}

/// <summary>
/// Main application entry point.
/// </summary>
/// <param name="args">Command line arguments.</param>
static void Main(string[] args) => CloseWindowless("MyAppName");

}

And the voodoo magic behind: P/Invoke part is pretty obvious. What's more interesting is WPF Application.OnStartup override behavior.

If the method is synchronous and does not exit, the application hangs.
If it's marked asynchronous however, it doesn't have to exit. It waits indefinitely for anything awaitable. This is exactly what we needed, because we can invoke Shutdown() only from the main UI thread. We cannot block that thread, so we have to wait for messages on another thread. We send the WM_CLOSE to all process threads, so it will get it. When it ends, the Shutdown method is called from the main thread and that's it.

What's best in this solution it doesn't need System.Windows.Forms reference.



Related Topics



Leave a reply



Submit