I have created a Windows Form application for smart device in c# which will raise an
event whenever there is a change in registry data. I have used RegistryState and the following code from msdn site. I am able to successfully raise the event.
RegistryState state;
private void Form1_Load(object sender, EventArgs e)
{
// SystemState state; // This instance will go out of scope if defined here
RegistryState state = new RegistryState("HKEY_LOCAL_MACHINE\\MyKey", "MyValue");
state.Changed += new ChangeEventHandler(state_Changed);
}
But when I use the same code and create a console application, event is not getting triggered.
What could be the reason? Does RegistryState have any limitations?
You'd have to use Reflector to dig into it, but my strong suspicion is that down in its depths the ReegistryState class works a lot like the SHChangeNotifyRegister API. It uses Windows Messaging to signal state changes, so it must have a message pump that's watching for and dispatching those messages and some place to send them when they come in. A console app doesn't have a message pump, and therefore while the message is likely getting queued that the registry has changed, there's nothing pulling that message off and forwarding it to your RegistryState handler.
It would be easy enough to test (and work around). Just add a message pump to your app that does a the usual GetMessage/TranslateMessage/DispatchMessage periodically.
Related
I have an app that I need to clean up some resources before it shuts down. I've got it handling the event using:
AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
private static async void OnProcessExit(object? sender, EventArgs e)
{
Console.WriteLine("We");
Thread.Sleep(1000);
Console.WriteLine("Are");
Thread.Sleep(1000);
Console.WriteLine("Closing");
}
But the event never gets fired? At least I don't see it, it instantly closes. I've tried this in an external and internal console and neither seem to catch it.
Using Linux Ubuntu 20.10
While you might see it as overkill in the beginning, I can recommend wrapping your console app in .NET Generic Host. This enables you to easily handle resource initialisation and cleanup, it also encapsulates logging and DI and nested services if available. The console app becomes easy to startup in an integration test, install as a Windows service (e.g. via Topshelf) or just keep running as a console app.
https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host
To get started you can run in command prompt
dotnet new worker
Then in Worker.cs you can override the StopAsync
public override async Task StopAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000);
_logger.LogInformation("Ended!");
}
Running with dotnet run you will see logging each second, and when you Ctrl+C you will see "Ended!" after 1 second - here you do any resource cleanup needed.
Normally you should use AppDomain.ProcessExit rather than AppDomain.CurrentDomain.ProcessExit. Is there a specific reason why you're using the second form?
How is your console app closing? Is it a normal exit after finishing its work, or failing due to an unmanaged exception, or dying due to a rude shutdown (eg Ctrl-C, Environment.FailFast, etc)?
In the first two cases AppDomain.ProcessExit should be invoked normally. But if that isn't happening for some reason, you can use Try..Finally to do resource cleanup.
In the third case, it's very likely that AppDomain.ProcessExit won't be invoked. And there's not a lot you can do about that.
Are you using a Debug or Release build? Because shutdown behaviour can be different depending on the build type. In addition, apps hosted within Docker might have unusual shutdown behaviour.
I have a pool of RabbitMQ channels under one connection. And I'm trying to implement the Publisher Confirms feature. I've built the pool in a way that it creates new channels as demand for channels increases. But now, I have to manage the closure of these channels too.
I plan to implement a solution like in the RabbitMQ tutorials using a outstandingConfirms list.
I came to the problem that I have to somehow close a channel (when I'm above my 'soft' threshold of objects in the pool) when the last message in a channel is ack-ed or nack-ed.
As you can see in the code below, the sender parameter is actually the channel itself, I thought I could use this directly to close the channel if there are no pending messages anymore. But I faced the fact that channels should not be used by more than one thread simultaneously. This same channel will be available in the pool and can be picked up by the application for usage.
These are the event subscriptions:
protected void OnBasicAcks(object sender, BasicAckEventArgs e)
{
//sender = channel object
//todo close channel after all pending messages (n)acked
}
protected void OnBasicNacks(object sender, BasicNackEventArgs e)
{
//sender = channel object
//todo close channel after all pending messages (n)acked
}
Also here I can read that blocking operations are allowed in callback handlers:
As of version 3.5.0 application callback handlers can invoke blocking
operations (such as IModel.QueueDeclare or IModel.BasicCancel)
But does this also apply to the closure of the channel itself?
In short, this is my problem. My questions are:
Can I use the channel passed through the sender parameter directly to do operations like IModel.Close()?
I just want to prevent getting deadlocks on channels or other weird stuff. Any advice or best practice for my problem?
And something completely different: can I create a new channel while I'm in the OnBasicAcks method?
If you are using the latest RabbitMQ.Client (v5.1, I think), the callbacks are all invoked on the ThreadPool using async so you're generally okay calling those methods in callbacks. I would, however, avoid hijacking the callback thread to do any long-running tasks as they are managed per-channel by the RabbitMQ client.
So, to answer specifically.
Should be fine, looking at the source code, it doesn't lock anything that would prevent close from being called. Just be wary of anything in your code that would deadlock.
It's best to control access to the session in your own code so that you aren't calling a single channel from multiple threads expecting anything to happen in a specific order.
Should work fine, you're on a TPL task thread, so no reason it shouldn't work.
If you want more details on how the client works, you can look at the source, particularly the ModelBase.cs file, and the asynchronous worker service it creates for callbacks.
I have 2 projects in same c# solution. One project is normal wpf application and other one is windows service. When wpf application updates some variables in database, windows service needs to update accordingly.
In my wpf application, I have a save method which updates a static field like
private void ConfigurationPanelSave_Click(object sender, RoutedEventArgs e)
{
bool isSuccess = SaveData();
if (isSuccess)
{
DatabaseInteractivity.HasChanges = true; //static member to indicate data has been changed
}
}
In windows service project, i have DatabaseInteractivity object and a timer event which is being called after 30 second interval (to see if data has been changed, if changed it re-reads some configurations)
private void timer_elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (DatabaseInteractivity.HasChanges)
{
ConfigurationReader.ReadConfiguration();
DatabaseInteractivity.HasChanges = false;
}
}
The problem is, when i save data through wpf application, it updates the static member (HasChanges) of DatabaseInteractivity class to true and when timer_elapsed event is called, HasChanges in windows service project is always false.
Shouldn't it be true for the first time when timer event is called?
I have read many articles and different approaches but I'm interested to know why it's not happening.
No, that isn't how static members work. Your WPF application and your service will be running in two separate processes. As they exist in different application domains, each process has its own version of the static member DatabaseInteractivity.HasChanges. They are completely unrelated to each other; they exist in different locations in memory. Changing one will have no effect on the other.
You need to look into inter-process communication. For example, your Windows service could provide a WCF or Thrift service end-point, to which your WPF application could connect. The end-point would have a method that the application would call to notify your service that data had been saved.
Static objects are static accross the thread you're running on.
I'm guessing you are running a wpf application thread and a windows service thread.
Even if the dll's (aka sources) are the same, they are still running from a different thread and they can't access each others variables.
I've created a managing application. On of the things my application does, is register on a plugin which can detect whenever or not a fingerprint reader gets plugged in or plugged out. The class subscribes on the event like such:
//Subscribe to the plug, unplug and imageAcquired events from the GrFingerXCtrlClass library.
FingerXCtrlClass.SensorPlug += ReaderPlug;
FingerXCtrlClass.SensorUnplug += ReaderUnplug;
FingerXCtrlClass.ImageAcquired += ImageAcquired;
First when I was actively working on the program, I've developed a WPF application. Through this application I could see some of the lists and switch some settings so I am sure my service works well. In this WPF application, I've created my service by instantiating it:
ProjectServiceLogic logic = new ProjectServiceLogic();
Now I've created an installer. Thus I had a ProjectService-class, initializing the application. This is being done like so:
protected override void OnStart(string[] args)
{
log.Debug("Starting service...");
_worker = new Thread(new ThreadStart(StartService));
_worker.IsBackground = true;
_worker.Name = "ServiceThread";
_worker.SetApartmentState(ApartmentState.STA);
_worker.Start();
log.Debug("Successfully started service");
}
void StartService()
{
serviceLogic = new ProjectServiceLogic();
while (!_shutdownEvent.WaitOne(0))
{
}
}
The program gets installed and the service starts. When debugging the service, I notice the subscribing code gets executed. However, the events are not triggered when I plug in a device while it does trigger when running it locally through the WPF application, instantiating the service logic. Why doesn't it work now?
_worker.SetApartmentState(ApartmentState.STA);
Selecting a Single Threaded Apartment requires you to implement the contract of an STA thread. Just two basic requirements: you can never block the thread and you must pump a message loop. The message loop is essential to allow COM to provide the guarantee that method calls on the COM object are always made from the thread that created the object, thus ensuring thread-safety. Also the mechanism in .NET that makes Control.BeginInvoke and Dispatcher.BeginInvoke work.
A COM component counts on having that guarantee in place, it often relies on the message dispatcher to take care of its own inter-thread marshaling. Like Dispatcher.BeginInvoke does.
Two things go wrong when you don't in fact pump a message loop as required. First of all, as expected, any calls you make on the object from a worker thread will deadlock. COM will use PostMessage to ask the STA thread to dispatch the call. But that won't happen when the thread isn't retrieving messages from the message queue. Second thing that goes wrong is likely what you see happening here, the component itself uses PostMessage to raise events on the STA thread. With the failure mode that the event is never raised. Also classically the way WebBrowser misbehaves, you never get the DocumentCompleted event.
You'll need to pump a message loop, Application.Run(). Either the Winforms or the WPF version of it will do, take your pick. A Winforms example is here
All
I have an application that allows a user to communicate with multiple serial devices.
A manager class is used to start the application, which creates a new thread for each serial device. Inside this thread, the serial device is created and the thread and serial device object are stored inside the manager class for later when needed.
The serial device class then creates a com port class on it's own new thread which is used to connect to the com port and send / receive data. When data is received an event is fired up to the serial device class which in turn fires an event to the manager class, which in turn fires an event to the UI to alert the user that new data has arrived.
My problem comes that when the com port class fires it's event to notify the serial port class, the serial port class receives the event and continues processing under the com port thread. Likewise if the user sends any information down to the com port, it all runs under the UI thread.
I will add code as an edit later, but for now, if anyone can spot anything obvious I would be seriously greatful.
I have tried receiving the event in the serial device class and then invoking a method to see if that makes it run under the correct thread but that was no good.
I know the serial device thread is running as I do an Application.Run inside the class after it's created it's com port classes.
I'm not using any background workers as these threads are meant to exist for the life of the application and I understand background workers are meant to be used for short running calculations.
Many thanks
EDIT:
Forgot to mention, this is a Winforms app in .NET 2.0, so no Dispatcher available
EDIT:
Okay, so it looks like that the information is being passed up inside the DataReceived thread (I think as it isn't the com port thread either).
I also tried using a BackgroundWorker for the serial device class but this also didn't make any difference.
Help?
.NET 2.0 has SynchronizationContext. It's a slight pain (you have to pass the context from the UI thread to the others) but it should do the trick.
More info here: http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
It sounds as if you need to create a kind of messaging mechanism to send messages from the UI thread to the correct port-thread. A queue might work. Let the UI thread post messages on the queue and have the port-thread process these messages.
Switching from the port-thread to the UI thread can be done using Dispatcher.CurrentDispatcher
Is this what you are looking for?
EDIT I am assuming a WinForms application