Console Application with Message Pump - c#

I'm trying to write a console application (C# .NET) that makes use of un-managed code in a 3rd party DLL.
The external assembly makes extensive use of callbacks. The sample application I have uses Windows Forms.
The sample code (Windows Forms) makes use of ThreadPool.QueueUserWorkItem
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
It would seem that with windows forms there is a message pump that handles the callbacks. This is not the case with a console app so I need to construct my own.
I've tried adding a reset event
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
static void main()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
resetEvent.WaitOne();
}
private void ConnectToControlPanel()
{
//Call external function from unmanaged DLL
resetEvent.Set();
}
That doesn't work.
My problem seems to be very much like this one but there is no real solution other than using Win.Forms and calling Application.DoEvents()
Edit
I modified my code thus:
Task task = Task.Factory.StartNew(() => ConnectToControlPanel());
while (task.Status != TaskStatus.RanToCompletion)
{
Application.DoEvents();
Thread.Sleep(500);
}
This works, the callbacks get called on progress and the result is successful rather than a timeout.
It doesn't feel right though to have to run that ugly loop every time I make an external call.
I've also tried spinning up another thread that constantly calls Application.DoEvents() but that didn't work, so I'm assuming it's got something to do with running in the same thread that made the call.

Related

Events not firing from COM component when in Unit (Integration) Test

I have an unmanaged DLL which I'm trying to create a .NET wrapper library for but am getting different behavior when I try and run a NUnit(v3) test over it compared to if it is just run from a button click off a WinForm app.
Background: During startup of the DLL I call its Connect() method, which ultimately causes the DLL to make a TCP connection. When the TCP connection is established I then get notified by wiring up a handler to its "Connected" event.
Once connected I then call other commands on the DLL.
In a simple test Winforms app, I have 1 button which instantiates the "DLL" and then calls the Connect() method. When the thread completes, the app sits idle for about 2 seconds, and then the "connected" event handler fires as expected. The event does not return anything.
But because the connect() is an expensive operation, and because my library is destined for a larger application, I created a ConnectAsync() method in my library and made use of the async and await keywords, and a AutoResetEvent. The ConnectAsync() method returns an instance of the "instantiated" DLL after it gets notified that the TCP connection is up from the event.
A bit of refactoring to the test WinForms app, and it works as expected.
Next step was to make an integration test using NUnit. However when the ConnectAsync() method is called from an async test, I can see the TCP connection establish on the remote application, but the event handler never fires. A day's worth of testing, searching and trial and error could not turn up why the ConnectAsync() works perfect off a simple Winforms button but not from a UnitTest.
Here is the test code
[Test()]
public async Task Test1()
{
var conn = await GetConnection();
//assert some commands on the conn
}
private async Task<TCPConnector> GetConnection()
{
return await Task.Run(() =>
{
var mre = new AutoResetEvent(false);
var ctrl = new TCPConnector();
ctrl.serverName = server;
ctrl.serverPort = serverPort;
ctrl.onConnected += () => { mre.Set(); };
ctrl.Connect();
mre.WaitOne();
return ctrl;
});
}
I know this is not strictly a question, but I'm stumped and looking for ideas to try. Or pointers as to what is different between a button click event and a NUnit test execution.
In case it means something to somebody, the dll I'm calling is an unmanaged ActveX
Update1:
If use MSTest it works! So it has something to do with NUnit's startup environment.
Update2:
Through investigations in this SO post, I by chance replicated the same behaviour without any unit testing frameworks, but instead via reg free COM. So I'm now thinking it is something to do with how the COM is activated and consumed ?
Resolution
Finally found the answer.
Credit to Chris for his answer on this question. All I had to do was add a <comInterfaceExternalProxyStub /> section to the manifest as outlined, and bingo
UPDATE 4
Ignore the last updates and the resolution. They contain misdirection and false positives, and some lack of understanding of my behalf as I worked through the whole world of COM, Regfree COM, Interop, and COM Events. The problem is still unresolved.
The key issue remains that when the COM is run under the context of a unit test the COM events do not fire. When run in a plain .exe they work just fine
My guess, without knowing what exactly the unmanaged DLL is doing, is that it is an single threaded apartment (STA) COM dll. In this threading model, COM interop will marshall all calls to the DLL to the thread that creates the object (which in your unit test is blocked waiting on the auto reset event, thus nothing happens).
The event pattern works in the Winforms app because the main UI thread is an STA thread (check the attribute on your main method) and it is pumping messages, so callbacks are allowed and locks are superseded by COM message pumping.
If this is the case, the only way to test the wrapper would be to create an STA thread, run a message pump on it, then pass a message to the thread to trigger the creation of the COM object and the connection (in other words, it's a huge pain). What's worse is that the object will behave this way in a client application as well, so unless you create an STA thread in your wrapper and marshall all calls to it, you will not be able to use it asynchronously.
As Chris mentioned, it's because specific of working with COM Interop objects in STA threads. It happens because interop objects created in STA thread could be accessed (also event call) only from that thread.
All you need is to wrap the creation of any COM Interop in a separate thread.
Something like that that:
private async Task<TCPConnector> GetConnection()
{
return await Task.Run(() =>
{
var mre = new AutoResetEvent(false);
Create(mre);
mre.WaitOne();
return ctrl;
});
}
private TCPConnector ctrl;
private void Create(AutoResetEvent mre)
{
ThreadPool.QueueUserWorkItem(o =>
{
ctrl = new TCPConnector();
ctrl.serverName = server;
ctrl.serverPort = serverPort;
ctrl.onConnected += () => { mre.Set(); };
ctrl.Connect();
});
}

Using asynchronous functions with UI synchronously

I have an application (WinForms). It simply grabs some data, does some work on it, then uploads the result to some cloud storage. I'm now using some third party code which handles the authentication with the cloud storage for me. This code will create a WinForm, which hosts a browser control, which pops up if the user has not already provided credentials and permission for the application to use the cloud storage. Before my program goes and does its thing, I want to make sure I'm already authenticated, hence in the Main() loop of the program (Program.cs), I want to use the third party library to authenticate with the cloud storage and block my actual code (//myCode) executing until it is done. 'Unfortunately' the library is asynchronous, and I've spent the best part of today trying to get the behavior I've just described - my question is effectively a "make async function synchronous", but the general answers I've seen around don't seem to work for me.
So I have something like this
static void Main(string[] args)
{
OAuth.LoginAuthAsync("clientID", "client_secret", ...)
//Don't want to get here until LoginAuthAsync is done
application.run(myForm); //myCode
}
But this will popup the web browser and run my code, which I want to happen only after the web OAuth.LoginAuthAsync has completed.
I'm no expert with the whole TPL libraries, but I've spent a while playing around with things I believe should work but don't. I've tried:
I've tried
Task.Run(async () =>
{
OAuth.LoginAuthAsync("123456", "asdasd", ...));
).Wait();
Which throws an error in the third party library
System.Threading.ThreadStateException: ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
at System.Windows.Forms.WebBrowserBase..ctor(String clsidString)
at System.Windows.Forms.WebBrowser..ctor()
So then I tried
Thread tx = new Thread(() => OAuth.LoginAuthAsync("123456","asdasd", ……..));
tx.SetApartmentState(ApartmentState.STA);
tx.Start();
tx.Join();
but that just pops up the window and it disappears instantly, and //myCode executes.
Any body have any ideas what I can do here. I tried moving the method inside of myForm _Load event (that's myForm invoked from the application.run), but I have the same problem.
Many Thanks
P.S. I don't want to use any further third party libraries.
You can block and wait for the code to complete using the Wait() method on the Task returned from OAuth.LoginAuthAsync. This works in a console app but may cause a deadlock in a GUI/ASP app.
static void Main(string[] args)
{
OAuth.LoginAuthAsync("clientID", "client_secret", ...).Wait();
//Don't want to get here until LoginAuthAsync is done
application.run(myForm); //myCode
}
For GUI apps it is best to make the relevant method async and then await the call to OAuth.LoginAuthAsync however Main can't be async. If you move the method inside the myForm_Load method you should be able to do await the call:
public async void myForm_Load(object o, EventArgs e)
{
await OAuth.LoginAuthAsync("clientID", "client_secret", ...);
}
In my opinion that is the better solution.

Kill thread-based logging instance ungracefully?

Application logging is done using plain and boring log files via a custom rolling flat file logging library. To lower the amount of write accesses to the hard disk, logging events get queued for either when a) a maximum queue item limit is reached or b) a certain amount of time has passed. For the time interval aspect, the logging library runs a thread which flushes the queue periodically.
Now, the logging instance is statically accessible, singleton and application wide (used in many other libraries) and sometimes it happens (altough it shouldn't) that a developer forgets to dispose the flushing thread with the result that, even if the application is 'closed', the thread keeps running and the application has to be killed via a task-manager, which is far from ideal.
So I'm wondering: Is there a possibility to automatically close the thread on application exit? I know about BackgroundWorker, Timer and Threadpool, but are those good solutions for that certain task? Or better stick with the 'classic' Thread?
Detecting that an application is about to exit is very specific to what kind of application you're running.
I don't know much about Aspx, but in WPF you could use the following code to hook up the Exit event of the System.Windows.Application class and close your thread gracefully in the event handler.
Also, you should always avoid killing a thread instead of shutting down gracefully, when it's possible, it can lead to inconsistencies because you have no way of controlling when it will really exit. Instead, you should periodically check for an exit condition, like in the code below.
public static class MyLogger
{
public static void Initialize()
{
if(IsWPFApplication())
Application.Current.Exit += Application_Exit;
//start flush thread and other initializations...
}
private static bool IsWPFApplication()
{
Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
return (dispatcher != null);
}
private static void Application_Exit(Object sender, EventArgs e)
{
Shutdown();
}
private static void Shutdown()
{
ExitRequested = true;
}
}
You can use System.Diagnostic.Process.GetCurrentProcess.Kill though if you are using dot net 4.0 I would recommend using tasks. Here is an excellent resource that I would recommend http://www.albahari.com/threading/.

How do I call a DLL which does a time consuming task?

In my WPF application, I have to communicate to a datastor over the serial port. I want to separate this communication into a class library for simplicity.
In my DLL, I will be issuing a command to the datastor and wait for 10 seconds to receive the response back. Once I get the response from the datastor, I compile the data to meaningful info and pass to the main application.
My question is how to make the main application to pause for a while to get the data from the external dll and then continue the processing with the data from the dll?
I use .net 4.0
Consider calling the DLL method in a new thread
Thread dllExecthread = new Thread(dllMethodToExecute);
and providing a callback from the main program to the dll which can be executed when complete (This prevents locking on the GUI).
edit: Or for simplicities sake if you just want the main program to wait for the DLL to finish execution subsequently call:
dllExecthread.Join();
Maybe you could go with TPL:
//this will call your method in background
var task = Task.Factory.StartNew(() => yourDll.YourMethodThatDoesCommunication());
//setup delegate to invoke when the background task completes
task.ContinueWith(t =>
{
//this will execute when the background task has completed
if (t.IsFaulted)
{
//somehow handle exception in t.Exception
return;
}
var result = t.Result;
//process result
});
Don't ever pause your main thread because it blocks the GUI. Instead you need to act on an event that the background communication fires. You could use the BackgroundWorker class - simply provide the result in RunWorkerCompleted.

C# Shutdown A Thread That Uses Application.Run()

I'm trying to use a C# DLL that I have access to the code of, but I can't actually change the code and build a custom version of it. The calling code is a C# WinForms project and the C# DLL also uses WinForms to handle Windows system events. The problem is that the DLL uses Application.Run() inside of it using a background thread, and there's built-in way to kill or stop that thread. Here is a snippet of the code:
public class DllClass
{
private Thread uithread = null;
private bool uithreadstarted = false;
public DllClass()
{
uithread = new Thread(new ThreadStart(RunDll));
uithread.IsBackground = true;
uithread.SetApartmentState(ApartmentState.STA);
uithread.Start();
do
{
Thread.Sleep(100);
} while (uithreadstarted == false);
}
private void RunDll()
{
//other init stuff here
uithreadstarted = true;
Application.Run();
}
}
Apparently the way I'm expected to kill it is by using Application.Exit(), but that also exits my own WinForms project, which is not what I want to happen. If I just close my application without calling Application.Exit(), the DLL continues running in the background. I want to be able to instantiate the DllClass object, use it, and then shut it down when I'm done. I came up with a method to get the Thread object of the thread that it's running in, but calling Thread.Abort() on it does not actually kill the thread. Is there any way to forcibly abort the Application.Run() call from outside of the DLL?
If you can find a window handle that was created by the DLL background thread (such as a form or hidden application window), you can post a WM_QUIT message to that handle and that should cause the DLL to exit the message loop cleanly.
you will need to get an instance of the form that is running in the other thread then call form.BeginInvoke and from there call Application.Exit
How about Application.ExitThread

Categories