Strange behavior Console.WriteLine() with SystemEvents - c#

The Console.WriteLine() does not output anything to the screen, while the handler SystemEvents_SessionSwitch() is called in blocking computer. But if in the Main() method call at least once the method Console.WriteLine(), then the method in the handler will work. What is the reason for this strange behavior / bug?
I'm using Windows 8 64 bit, .NET Framework 4.0
using System;
using Microsoft.Win32;
namespace TestWindowsEvents
{
class Program
{
static void Main(string[] args)
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
//Console.WriteLine("Test"); //if uncomment this line, then Console.WriteLine() in SystemEvents_SessionSwitch() will work
Console.ReadKey();
}
static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
Console.WriteLine("SessionSwitch"); //this does not working
System.Diagnostics.Debug.WriteLine("SessionSwitchDebug"); //and this does not working too..
}
}
}
Updated:
The handler itself SystemEvents_SessionSwitch () is called. I specifically checked this by putting a breakpoint. And after locking computer breakpoint activated. But Console.WriteLine() does not output any text to console...

I can tell from the description of the problem that you are using .NET 4.5. Your Console.ReadKey() method takes a lock, new behavior in 4.5, it prevents other threads from writing to the console and mess up the display.
That lock prevents your event handler from writing to the console. It runs on another thread, necessary because you are using a console mode program that doesn't pump a message loop. The SystemEvents class will create its own to ensure the events fire. The upvoted answer is wrong about that.
What it tries to write does eventually make it to the console, but that of course happens a millisecond before the console window closes so you never see it.
This new 4.5 behavior does spell doom to quicky programs to test something. You'll need a better way to decide that your program is done, the "Hit any key to continue" method doesn't work so well anymore. A rather lame alternative that doesn't take the lock could be:
while (!Console.KeyAvailable) System.Threading.Thread.Sleep(100);
UPDATE: this problem was fixed in a .NET 4.5 update delivered through Windows Update. Not exactly sure when I got the update, somewhere around August 2013.

The event is simply not called. In your check the documentation, it says:
This event is only raised if the message pump is running. In a Windows
service, unless a hidden form is used or the message pump has been
started manually, this event will not be raised.

Related

Windows Hooks do not trigger events and windows starts lagging. (Using globalmousekeyhook in C#)

I currently work with the Steelseries GameSense SDK to make my own effects etc. for my keyboard and mouse.
To light up my mouse and keyboard on clicks and presses, I use the globalmousekeyhook library.
Unfortunately, the mouse and keyboard events don't get triggered.
Also, my mouse starts lagging, and keyboard input gets delayed.
The lag and the delay only stay for about half a minute.
I suspect that windows removes the hooks because it detects the lag.
I also tried this example program and everything works fine there.
Here is the code:
private static readonly IKeyboardMouseEvents GlobalHook = Hook.GlobalEvents();
static InputManager()
{
Logger.Log("Starting...", Logger.Type.Info);
GlobalHook.KeyDown += KeyEvent;
GlobalHook.MouseDownExt += MouseEvent;
Logger.Log("Ready!", Logger.Type.Info);
}
And the event functions:
private static void KeyEvent(object sender, KeyEventArgs eventArgs)
{
Logger.Log(eventArgs.KeyCode.ToString());
}
private static void MouseEvent(object sender, MouseEventArgs eventArgs)
{
Logger.Log(eventArgs.Button.ToString());
}
You can find the whole class (and the project) here.
The constructor is the only thing that gets executed in the program.
What I found regarding the lag is that the event function has to be fast. That cannot be the problem in my case because the Logger.Log() function is fast, and the lag also occurs when using Console.WriteLine().
As I said, the example program runs fine. I tried copying the example code, but that made no difference. The only real difference between my program and the example program is that the example uses .Net Core but I use .Net Framework (4.8). Could that be the reason? If it is the reason, is there any way to use the library with .Net Framework?
I look forward to any help.
There are two issues:
You need a message pump in order to receive hook messages. For this you can use the following code, as shown in the example you link
Application.Run(new ApplicationContext());
You now have two things you are trying to do on the same thread: pump the messages and wait for input. Instead, split them into different threads:
private static void Main(string[] args)
{
Logger.Log("Program started. Welcome.", Logger.Type.Info);
////GameSense.Controller.Start();
new Thread(() => Console.ReadLine()).Start();
InputManager.Start();
Application.Run(new ApplicationContext());
InputManager.End();
Application.Exit(); // needed to close down the message pump and end the other thread
}

timer in console application

I am creating a device application using .NET compact framework 2.0. There is a system.threading.timer in my application which executes some code. It works fine. My problem is when I am running the app by double clicking on the exe in the bin folder, the timer starts and execute all it works but it never stops. It runs in the background even after closing the app by clicking the X-button or from the file menu close button. I don't understand how and where I stop or dispose of the timer so that it doesn't run after closing the app. May be something like a form_closing event in window form application. I had searched a lot in Google but did't find any proper answer.
The application is use to generate digital output for a device
here is some code of timer event:
public static void Main()
{
// Some code related to the device like open device etc
// Then the timer
System.Threading.Timer stt =
new System.Threading.Timer(new TimerCallback(TimerProc), null, 1, 5000);
Thread.CurrentThread.Join();
}
static void TimerProc(Object stateInfo)
{
// It is my local method which will execute in time interval,
// uses to write value to the device
writeDigital(1, 0);
GC.Collect();
}
It is working fine when I run the code in debug mode, timer stops when I stop the program. But not working when I run the exe.
You could create and dispose it in Main() and pass it to any methods that require it?
private static void Main()
{
using (var timer = new System.Threading.Timer(TimerProc))
{
// Rest of code here...
}
}
More importantly, this line of code:
Thread.CurrentThread.Join();
will never return, because you are asking the current thread to wait for the current thread to terminate. Think about that for a moment... ;)
So your solution is probably to just remove that line of code.
All about GC.Collect();
Your stt object is used once and after that is pointed out to being removed and its memory reclaimed.
If you don't belive call stt.ToString(); at the end of main function, it will extend the stt live till the end of main function.
Solution(s)?
You can define the stt object as a static - it guarantees that it will be alive till the end of live of you program
recommended solution is to use GC.KeepAlive(stt); which you can call at the end of main function which will keep the stt away from destroying process.

The definitive code that prevents a c# console app from exiting [until custom cleanup code has completed]

Can we work together to come up with something that works for control-c, control-break, log off, window X button pressed, etc?
Here is what I have so far:
class Program
{
private static ConsoleEventHandlerDelegate consoleHandler;
delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);
static void Main(string[] args)
{
consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
SetConsoleCtrlHandler(consoleHandler, true);
System.Diagnostics.Process.GetCurrentProcess().Exited
+= delegate(object sender, EventArgs e)
{
GeneralManager.Stop();
};
Console.CancelKeyPress += delegate(object sender,
ConsoleCancelEventArgs e)
{
e.Cancel = false;
GeneralManager.Stop();
};
GeneralManager.Start();
}
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
Console.WriteLine("CTRL+C received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_BREAK_EVENT:
isclosing = true;
Console.WriteLine("CTRL+BREAK received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_CLOSE_EVENT:
Console.WriteLine("Program being closed!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
Console.WriteLine("User is logging off!");
GeneralManager.Stop();
break;
}
return true;
}
#region unmanaged
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
handlerProc, bool add);
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
#endregion
}
Two problems:
In the Managed Control-Break handler, if we set e.Cancel = true it fails with an exception for .Net4. This is noted in the MSDN article with no work-around: http://msdn.microsoft.com/en-us/library/system.consolecanceleventargs.cancel.aspx
I don't know how to cancel the close in the ConsoleCtrlCheck. I get a second or two to do some cleanup, but I'd rather cancel and make sure it all gets done properly.
UPDATE:
Thanks for the replies. Upvoted both. Will wait to see if anyone can come up with a reply that directly solves what I asked for, otherwise will accept one of the "use NT services" answers.
I need to wait for pending user requests to complete, disconnect them cleanly, run a few queries on the database to reflect the change(s) in state and so forth. It's a TCP server.
Then don't run it as a Console or any other kind of Client app.
Just run it as a Windows (NT) Service and the only events you'll have to worry about are Power loss and a stop signal.
Use a UPS and make sure you can close in a reasonable timespan.
I have not tried to do this kind of thing with a console app, but you may do better with a Windows Forms (or WCF app). They will give you a FormClosing event which is cancellable. Alternately, use a Windows Service if you are writing a network service, it provides an interface to cleanly stop your application.
If you are really keen on a console app, perhaps a try {} finally {} clause around all your code or something more exotic like a critical finaliser may allow you to run clean up code. But this is really not the right tool for the job.
And there are cases which you cannot prevent you app being closed, eg: power failure, or Task Manager kill command (and if an app didn't close via the X, Task Manager is the first tool I'd reach for).
So, code your service application such that all client requests are logged to a transaction log (like SQL server does). If you are unexpectedly interrupted (by whatever circumstance) anything which has happened up until that point is in the log. When your service next starts, replay that log.
One of your things to log will be "I was shutdown cleanly at time T". If you restart and don't find that item at the end of your log, you know something went wrong, and you can take whatever action is required.
If you need to know what your service is doing, use one of the many logging frameworks to pipe events to a second app, which just displays activity.
I spent couple hours looking at this and as I don't have time now to build a working code; as while it's probably short, getting it right would take a while. I'll just give you link to the various stuff that's needed to get this done:
http://pastebin.com/EzX3ezrf
Summarizing the lessons from the code in the paste:
Need a message pump to handle some/all of WM_QUERYENDSESSION, WM_ENDSESSION, CTRL_SHUTDOWN_EVENT (in c# SystemEvents.SessionEnding may cover some/all of these)
Easiest way to get a message pump is to make it a hidden form/window app, but I recall it's possible to build as a console app and add a message pump also. I didn't include that code in the paste though.
"If an application must block a potential system shutdown, it can call the ShutdownBlockReasonCreate function"
As AllocConsole is used to create the console, you need to use SetConsoleCtrlHandler and use ExitThread(1) in the handler. This is a "hack" that kills off the thread that would close the console otherwise. It's used in FarManager. see interf.cpp for example
You need to also initialize and clean up the console when using AllocConsole.
Pressing CTRL+C is reported to mess up the input. I'm not sure if FarManager is handling this scenario. There's some code in the CTRL_BREAK_EVENT handler in interf.cpp that I'm not sure what it does.
FarManager also handles WM_POWERBROADCAST, probably to do with suspending
If all that isn't enough (should be), you can also add the console into another process and IPC your messages to it like shown here. Why does closing a console that was started with AllocConsole cause my whole application to exit? Can I change this behavior?
RMTool can be used to simulate logoff/shutdown messages for testing: http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi
MSDN has some C# code also at microsoft.win32.systemevents.sessionending.aspx
and microsoft.win32.systemevents.aspx (hidden form example)
The mischel.com/pubs/consoledotnet/consoledotnet.zip has a sample winTest project with AllocConsole being used and some of the events handled.

Process.Kill() related crashes

Or not!
I have a fairly simple application timer program. The program will launch a user selected (from file dialog) executable and then terminate the process after the user specified number of minutes. During testing I found that a crash occurs when I call the Process.Kill() method and the application is minimized to the system tray.
The executable in question is Frap.exe which I use frequently and is the reason I wrote the app timer in the first place. I always minimize fraps to the tray, and this is when the crash occurs.
My use of Kill() is straight forward enough...
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited)
{
if (!p.HasExited)
p.Kill();
break;
}
System.Threading.Thread.Sleep(500);
}
In searching for alternatives methods to close an external application programmatically, I found only Close() and Kill() (CloseMainWindow is not helpful to me at all). I tried using Close(), which works providing the application is minimized the tray. If the app is minimized, Close() doesn't cause a crash but the app remains open and active.
One thing I noticed in a few posts posts regarding closing external applications was the comment: "Personally I'd try to find a more graceful way of shutting it down though." made in THIS thread found here at stack flow (no offense to John). Thing is, I ran across comments like that on a few sites, with no attempt at what a graceful or elegant (or crash-free!!) method might be.
Any suggestions?
The crash experienced is not consistant and I've little to offer as to details. I am unable to debug using VS2008 as I get message - cant debug crashing application (or something similar), and depending on what other programs I have running at the time, when the Kill() is called some of them also crash (also programs only running in the tray) so I'm thinking this is some sort of problem specifically related to the system tray.
Is it possible that your code is being executed in a way such that the Kill() statement could sometimes be called twice? In the docs for Process.Kill(), it says that the Kill executes asynchronously. So, when you call Kill(), execution continues on your main thread. Further, the docs state that Kill will throw a Win32Exception if you call it on an app that is already in the process of closing. The docs state that you can use WaitForExit() to wait for the process to exit. What happens if you put a call to WaitForExit() immediately following the call to Kill(). The loop looks ok (with the break statement). Is it possible that you have code entering that loop twice?
If that's not the problem, maybe there is another way to catch that exception:
Try hooking the AppDomain.CurrentDomain.UnhandledException event
(currentDomain is a static member)
The problem is that Kill runs asynchronously, so if it's throwing an exception, it's occurring on a different thread. That's why your exception handler doesn't catch it. Further (I think) that an unhandled async exception (which is what I believe you have) will cause an immediate unload of your application (which is what is happening).
Edit: Example code for hooking the UnhandledExceptionEvent
Here is a simple console application that demonstrates the use of AppDomain.UnhandledException:
using System;
public class MyClass
{
public static void Main()
{
System.AppDomain.CurrentDomain.UnhandledException += MyExceptionHandler;
System.Threading.ThreadPool.QueueUserWorkItem(DoWork);
Console.ReadLine();
}
private static void DoWork(object state)
{
throw new ApplicationException("Test");
}
private static void MyExceptionHandler(object sender, System.UnhandledExceptionEventArgs e)
{
// get the message
System.Exception exception = e.ExceptionObject as System.Exception;
Console.WriteLine("Unhandled Exception Detected");
if(exception != null)
Console.WriteLine("Message: {0}", exception.Message);
// for this console app, hold the window open until I press enter
Console.ReadLine();
}
}
My first thought is to put a try/catch block around the Kill() call and log the exception you get, if there is one. It might give you a clue what's wrong. Something like:
try
{
if(!p.HasExited)
{
p.Kill();
}
break;
}
catch(Exception ex)
{
System.Diagnostics.Trace.WriteLine(String.Format("Could not kill process {0}, exception {1}", p.ToString(), ex.ToString()));
}
I dont think I should claim this to be "THE ANSWER" but its a decent 'work around'. Adding the following to lines of code...
p.WaitForInputIdle(10000);
am.hWnd = p.MainWindowHandle;
...stopped the crashing issue. These lines were placed immediately after the Process.Start() statement. Both lines are required and in using them I opened the door to a few other questions that I will be investigating over the next few days. The first line is just an up-to 10 second wait for the started process to go 'idle' (ie. finish starting). am.hWnd is a property in my AppManagement class of type IntPtr and this is the only usage of both sides of the assignment. For lack of better explaination, these two lines are analguous to a debouncing method.
I modified the while loop only slightly to allow for a call to CloseMainWindow() which seems to be the better route to take - though if it fails I then Kill() the app:
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited) {
try {
if (!p.HasExited) // if the app hasn't already exitted...
{
if (!p.CloseMainWindow()) // did message get sent?
{
if (!p.HasExited) //has app closed yet?
{
p.Kill(); // force app to exit
p.WaitForExit(2000); // a few moments for app to shut down
}
}
p.Close(); // free resources
}
}
catch { // blah blah }
break;
}
System.Threading.Thread.Sleep(500);
}
My initial intention for getting the MainWindowHandle was to maximize/restore an app if minimized and I might implement that in the near future. I decided to see if other programs that run like Fraps (ie, a UI but mostly run in the system tray (like messanger services such as Yahoo et al.)). I tested with XFire and nothing I could do would return a value for the MainWindowHandle. Anyways, this is a serperate issue but one I found interesting.
PS. A bit of credit to JMarsch as it was his suggestion RE: Win32Exception that actually lead me to finding this work around - as unlikely as it seems it true.

How can I keep a console open until CancelKeyPress event is fired?

What is the best way to keep a console application open as long as the CancelKeyPress event has not been fired?
I would prefer to not use Console.Read or Console.ReadLine as I do not want to accept input. I just want to enable the underlying application to print to the console event details as they are fired. Then once the CancelKeyPress event is fired I want to gracefully shut down the application.
I'm assuming that "gracefully shut down the application" is the part you are struggling with here. Otherwise your application will automatically exit on ctrl-c. You should change the title.
Here's a quick demo of what I think you need. It could be refined a bit more with use of locking and Monitors for notification. I'm not sure exactly what you need though, so I'll just pose this...
class Program
{
private static volatile bool _s_stop = false;
public static void Main(string[] args)
{
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
while (!_s_stop)
{
/* put real logic here */
Console.WriteLine("still running at {0}", DateTime.Now);
Thread.Sleep(3000);
}
Console.WriteLine("Graceful shut down code here...");
//don't leave this... demonstration purposes only...
Console.ReadLine();
}
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
//you have 2 options here, leave e.Cancel set to false and just handle any
//graceful shutdown that you can while in here, or set a flag to notify the other
//thread at the next check that it's to shut down. I'll do the 2nd option
e.Cancel = true;
_s_stop = true;
Console.WriteLine("CancelKeyPress fired...");
}
}
The _s_stop boolean should be declared volatile or an overly-ambitious optimizer might cause the program to loop infinitely.
The _s_stop boolean should be declared volatile in the example code, or an overly-ambitious optimizer might cause the program to loop infinitely.
There is already a handler bound to CancelKeyPress that terminates your application, the only reason to hook to it is if you want to intercept the event and prevent the app from closing.
In your situation, just put your app into an infinite loop, and let the built in event handler kill it. You may want to look into using something like Wait(1) or a background process to prevent it from using tons of CPU while doing nothing.
This may be what you're looking for:
http://msdn.microsoft.com/en-us/library/system.console.cancelkeypress.aspx
Simply run your program or codes without debugging, on your keyboard key in CTRL + f5 instead of F5(debugging).

Categories

Resources