AppDomain.CurrentDomain.DomainUnload not be raised in Console app - c#

I have an assembly that when accessed spins up a single thread to process items placed on a queue. In that assembly I attach a handler to the DomainUnload event:
AppDomain.CurrentDomain.DomainUnload += new EventHandler(CurrentDomain_DomainUnload);
That handler joins the thread to the main thread so that all items on the queue can complete processing before the application terminates.
The problem that I am experiencing is that the DomainUnload event is not getting fired when the console application terminates. Any ideas why this would be?
Using .NET 3.5 and C#

Unfortunately for you, this event is not raised in the default AppDomain, only in app domains created within the default one.
From the MSDN documentation:
This event is never raised in the
default application domain.

You'll need to subscribe the event for the specific domain. You also can't rely on the domain get unloaded at termination time. Remove the comment from this code to see that:
using System;
using System.Reflection;
class Program {
static void Main(string[] args) {
var ad = AppDomain.CreateDomain("test");
ad.DomainUnload += ad_DomainUnload;
//AppDomain.Unload(ad);
Console.ReadLine();
}
static void ad_DomainUnload(object sender, EventArgs e) {
Console.WriteLine("unloaded, press Enter");
Console.ReadLine();
}
}

Related

Windows.System.User events not being raised in UWP

I am trying to have some logic when Windows user is being changed while my UWP app is running and for that in my OnLaunchApplicationAsync method I have:
var userWatcher = Windows.System.User.CreateWatcher();
userWatcher.AuthenticationStatusChanged += AuthenticationStatusChanged;
and I also have
private void AuthenticationStatusChanged(Windows.System.UserWatcher sender, Windows.System.UserChangedEventArgs args)
{
// Some logic
}
But the problem is that when I log off with my current user and sign in with another one, the expected event is not being raised.
I have also tried out userWatcher.Updated for updating user data as well as userWatcher.AuthenticationStatusChanging with the same result.
Am I doing this in a wrong way?
You need to start the watcher, otherwise these events are not fired.

C# Execute code before application exits for background app

This is not a duplicate of this post. I got my solution from this post but it does not work not to mention my app is a winforms app, not a console app.
So I have a project that is running in the background. Basically, I created a Windows forms application but I am not calling the Form in Program.cs. I created a class that listens to when the application exits:
class ShutDownManager
{
public ShutDownManager()
{
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
}
static bool exitSystem = false;
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig)
{
Console.Writeline("I'M OUT OF HERE");
return true;
}
}
I create an instance of this class in Program.cs's Main function.
However this does not seem to fire. It works like a charm in Console applications but when it comes to my forms application (without the form) it doesn't work. What could be the problem?
My code in Main:
static void Main()
{
ShutDownManager sdm = new ShutDownManager();
StartUpManager.AddApplicationToCurrentUserStartup();
Timers timers = new Timers();
}
Let me break down your situation: An excerpt from learn.microsoft.com on SetConsoleCtrlHandler
Each console process has its own list of application-defined HandlerRoutine functions that handle CTRL+C and CTRL+BREAK signals. The handler functions also handle signals generated by the system when the user closes the console, logs off, or shuts down the system. A console process adds or removes additional handler functions by calling the SetConsoleCtrlHandler function, which does not affect the list of handler functions for other processes.
As you notice, this seems to be referring to Console process only. And it cannot tell you when other application exit, but only about this application. In addition it can notify you of LOGOFF and SHUTDOWN. Also, since there is no console (as you want a background process), there is no CTRL-C or CTRL-BREAK processing involved.
Conclusion: the best case is that you can only be notified about LOGOFF and SHUTDOWN
Relevant information from the same page for winforms app:
This function provides a similar notification for console application and services that WM_QUERYENDSESSION provides for graphical applications with a message pump.
What is the problem with your code?
Well, it is designed to provide a callback when the system has LOGOFF or SHUTDOWN when the application is running. Needless to say, your application has already exited to receive such events. So you have to wait after registering your callback.
What is the best way to do it?
You should write a service for this. And if I am not mistaken, service already gets a notification for LOGOFF and SHUTDOWN
How to write a simple C# service has a good example.
EDIT:
For more comprehensive understanding , you might want to look at the MSDN docs about ServiceBase class. Also, you should look at the OnSessionChange event, which is notified about all session events. It has some useful code excerpt at SessionChangeDescription class doc. Similarly for OnShutdown event
Now if you can't do windows service, you will have to create a Form from your winform application and make the Form invisible. You should then handle the WM_QUERYENDSESSION event or use the SystemEvents.SessionEnding Event to handle the situation
Sample code for that
var frm = new Form();
frm.Activated += (s, e) => { frm.Visible = false; };
SystemEvents.SessionEnded += (s, e) => { /* your code to handle logoff and shutdown */ };
Application.Run(frm);

Key listener not firing (MouseKeyHook)

I'm starting out in C#, coded a lot in Java but having some trouble here. I'm trying to learn how to use MouseKeyHook for an application I'm developing. I cannot get the actual listener to fire off an event. Here's my listener code:
using System;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;
namespace ChromaHeatmap
{
class keyListener
{
private IKeyboardMouseEvents m_GlobalHook;
public void Subscribe()
{
// Note: for the application hook, use the Hook.AppEvents() instead
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.KeyPress += GlobalHookKeyPress;
}
private void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
{
Console.WriteLine("blah");
}
public void Unsubscribe()
{
m_GlobalHook.KeyPress -= GlobalHookKeyPress;
//It is recommened to dispose it
m_GlobalHook.Dispose();
}
}
}
And here's the part of my application code where I attempt to do something with the listener. If anyone can let me know what the best way is to loop here and wait for events, I'd appreciate it.
//Listen for key presses
keyListener heyListen = new keyListener();
heyListen.Subscribe();
while(true)
{
}
while(true) {}
This is a hold-and-catch-fire statement, the thread will burn 100% core and cannot execute the hook callback. You'll notice that the machine goes dead for 5 seconds when you press a key, the operating system is waiting for an opportunity to invoke the callback. But it won't wait forever and unceremoniously will destroy the hook so you regain control over the machine. Also the kind of mishap that will occur when you try to debug your event handler.
Windows needs an opportunity to safely call the hook callback. That requires your program to be "idle", not executing any code. The technical term for this is "pumping the message loop", your program must wait for a notification from the operating system that something interesting happened.
A very simple way is to use the Winforms project template as-is, you'll also get a window. Note how the Main() method in the project makes the call that you need instead of the while() loop. You must call Application.Run().
Check this post for code that avoids displaying a window.

serialPort_DataReceived don't work in exe file

i writed a program with Serial Port as this:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
serialLabel.BackColor = Color.Red;
storage = serialPort1.ReadExisting();
if (storage.Contains("CMGL"))
{
if (storage.Length > 65)
{
processUnreadedMessages(storage);
}
else
{
Thread.Sleep(500);
}
}
else if (storage.Contains("CMTI"))
{
serialPort1.Write("AT+CMGL\r");
Thread.Sleep(500);
}
storage = "";
serialLabel.BackColor = Color.Lime;
}
in visual studio when i run program works good!
but when i'l create setup for my program or run exe file, data don't receive to serialPort, and i don't get any error. but when i send data with this program it's work!
can you help Me?
the problematic lines are probably those:
serialLabel.BackColor = Color.Red;
and
serialLabel.BackColor = Color.Lime;
there's a slim chance it will still work in developent environment, but:
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object. Because this event is raised on a
secondary thread, and not the main thread, attempting to modify some
elements in the main thread, such as UI elements, could raise a
threading exception. If it is necessary to modify elements in the main
Form or Control, post change requests back using Invoke, which will do
the work on the proper thread.
[msdn]
try instead:
serialLabel.Invoke(new EventHandler(delegate
{
serialLabel.BackColor = Color.Red;
}));
Also:
make sure you don't touch GUI or anything that should be accessed from the thread it was created on without invoking (e.g. you also shouldn't write data to EventLog without Invoking) in your method processUnreadedMessages()
Check if there's no First Chance exceptions when you debug your application
check Application EventLog for messages generated by your application.
log data you received in serialPort1_DataReceived event to a file before you do anything else (this will check if DataReceived event is raised at all when it should)
subscribe to SerialPort.ErrorReceived event

how to reliable capture display setting changed

static void Main()
{
// Set the SystemEvents class to receive event notification when a user
// when display settings change.
SystemEvents.DisplaySettingsChanged += new
EventHandler(SystemEvents_DisplaySettingsChanged);
// For demonstration purposes, this application sits idle waiting for events.
Console.WriteLine("This application is waiting for system events.");
Console.WriteLine("Press <Enter> to terminate this application.");
Console.ReadLine();
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
Console.WriteLine("Display setting change .");
}
i have created a windows service.when i restart the system and login then change the display setting it will not work and event is not fire but the service is runing.
when i restart the service then i change the display setting then display setting event fire.
i think SystemEvents.DisplaySettingsChanged may depend on some service.
The SystemEvents class uses the WTSSession APIs under the covers, which rely on the Terminal Services service (TermService). If your service messes with SystemEvents before that service is started, it will fail in interesting ways. If you make your service depend on TermService, the SystemEvents init should work by the time your service starts.

Categories