how to reliable capture display setting changed - c#

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.

Related

How to make windows service that prevents focus steal?

I am dabbling with Windows services.
From what I've read and the tutorials I've covered (one example) I see that all the work must be done in the OnStart method of the service.
As far as I understand it (from the only tutorials I was able to find, which were completely basic) after the OnStart method returns the service can't do anything if you haven't, somehow, configured it in the method.
I saw the use of timers in said method to trigger events every X seconds but what I am looking for is to detect window focus changes (when a program tries to bring its window to the front). The solution in this answer works perfectly when I try it in a console application but I want to use it in my service.
However, simply registering the eventhandler in the OnStart method does not work - it doesn't get triggered and has no effect. I tried putting a timer just to keep the OnStart method going but that didn't help, either - the timer was running and it was doing work each tick but the eventhandler never fired (I put a File.AppendText for each timer tick and each time the handler fires but in the text file I used as a control only the timer ticks were appended).
Lastly, I tried running a Task (by using Task.Run to create a new thread) which ran an endless loop in a separate method from OnStart but that just made the service start hang as it went on and on.
Code:
protected override void OnStart(string[] args)
{
File.WriteAllText("file.txt", "START");
eventLog.WriteEntry("Entered OnStart method.");
// Update the service state to "Start Pending".
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Start Pending.", EventLogEntryType.Information);
// Update the service state to "Running".
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Running.", EventLogEntryType.Information);
Task.Run(KeepBusy());
}
private static Action KeepBusy()
{
Automation.AddAutomationFocusChangedEventHandler(OnFocusChangedHandler);
while (true)
{
Thread.Sleep(1000);
}
}
In short - if I correctly understand services can only perform work in the OnStart method I am disgusted at how stupid this seems and can't figure out how to make a "listener" service

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);

How to create a scheduled long running process using windows service in c#

I want to create a windows service that performs some really long and heavy work. The code is inside OnStart method like this:
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(
#"C:\MMS\Logs\WinServiceLogs.txt",
DateTime.Now + "\t MMS Service started."
);
this.RequestAdditionalTime(5*60*1000);
this.RunService();
}
this.RunService() sends a request to WCF service library hosted on IIS. It does some really long processes, ranging from 1-20 min, depending on the data it has to process. This service that I'm writing is supposed to be scheduled to run every day in the morning. So far, it runs and works fine, but when the time goes over a few seconds or min, it generates timeout exception. This causes the windows service to be in unstable state, and I can't stop or uninstall it without restarting the computer. Since, I'm trying to create an automated system, this is an issue.
I did do this.RequestAdditionalTime(), but I'm not sure whether it's doing what it's supposed to or not. I don't get the timeout error message, but now I don't know how to schedule it so it runs every day. If the exception occurs, then it won't run the next time. There were several articles and SO's I found, but there's something I'm missing and I can't understand it.
Should I create a thread? Some articles say I shouldn't put heavy programs in OnStart, where should I put the heavy codes then? Right now, when the service starts, it does this huge data processing which makes the Windows Service status to "Starting", and it stays there for long time until either the program crashes due to timeout, or completes successfully. How can I start the service, then set the status to Running while the code is running to do some data processing?
Your situation might be better suited for a scheduled task as Lloyd said in the comments above. But if you really want to use a Windows service, this is what you would need to add/update in your service code. This will allow your service to list as started and not timeout on you. You can adjust the timer length to suit your needs.
private Timer processingTimer;
public YourService()
{
InitializeComponent();
//Initialize timer
processingTimer = new Timer(60000); //Set to run every 60 seconds
processingTimer.Elapsed += processingTimer_Elapsed;
processingTimer.AutoReset = true;
processingTimer.Enabled = true;
}
private void processingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Check the time
if (timeCheck && haventRunToday)
//Run your code
//You should probably still run this as a separate thread
this.RunService();
}
protected override void OnStart(string[] args)
{
//Start the timer
processingTimer.Start();
}
protected override void OnStop()
{
//Check to make sure that your code isn't still running... (if separate thread)
//Stop the timer
processingTimer.Stop();
}
protected override void OnPause()
{
//Stop the timer
processingTimer.Stop();
}
protected override void OnContinue()
{
//Start the timer
processingTimer.Start();
}

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.

AppDomain.CurrentDomain.DomainUnload not be raised in Console app

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();
}
}

Categories