Thread in SxS C# COM DLL makes calling application unresponsive - c#

I have written a Side-By-Side COM DLL in C#.
I am using this DLL in VB6.
The COM DLL contains a thread.
As soon as I start this thread, the calling application (in my case VB6) blocks (meaning I can not do anything in it anymore).
I am starting the thread like this:
private Thread _startMasterThread;
public void Init()
{
if (_startMasterThread == null)
{
_startMasterThread = new Thread(new ThreadStart(pMasterThread));
_startMasterThread.Priority = ThreadPriority.Highest;
_startMasterThread.Start();
}
}
private void pMasterThread()
{
while (!_bAbortAll)
{
//do something
}
}
ThreadStart comes from this:
namespace System.Threading
{
[ComVisible(true)]
public delegate void ThreadStart();
}
Is it normal that the calling application becomes unresponsive?
I thought that since it is a different thread, it would not do this.

It looks like you create a STA thread and then neglect to serve the message pump. Callers will block because nobody responds to their messages. Hence, the UI (a caller) freezes (block).
Some old, but highly relevant articles:
Understanding and Using COM Threading Models
Single-Threaded Apartments
Apartments and Pumping in the CLR
After you read these, and understand the issue, the solution(s) will be obvious. Switch to an MTA or run a message pump in your thread.

Related

Console Application with Message Pump

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.

Releasing a named mutex created in WPF Application.OnStartUp(): Which thread owns it?

I create a mutex within the OnStartup Method of a WPF app. The mutex is not used anywhere else in the program, its only purpose is to prevent certain programs from running concurrently. How can I release this mutex when the application closes?
According to the documentation, mutex.ReleaseMutex() must be called from the same thread that created the mutex. However this presents a problem, since I do not control the thread that calls OnStartup().
Suppose my OnStartup method looks like this:
public partial class App : Application
{
private Mutex mutex;
private bool hasHandle = false;
protected override void OnStartup(StartupEventArgs e)
{
bool createdNew;
mutex = new Mutex(false, #"Global\XYZ", out createdNew);
try
{
hasHandle = mutex.WaitOne(5000, false);
if (!hasHandle)
{/*do stuff*/};
}
catch (AbandonedMutexException)
{
hasHandle = true;
// do stuff
}
base.OnStartup(e);
}
private void releaseMutex()
{
if (mutex!=null)
{
if (hasHandle) mutex.ReleaseMutex();
mutex.Dispose();
}
}
}
Is it save to call releaseMutex() ...
in the OnExit() method?
protected override void OnExit(){releaseMutex();}
in the ProcessExit event handler?
AppDomain.CurrentDomain.ProcessExit += (sender,e)=> releaseMutex();
in a finalizer?
~App(){releaseMutex();}
in the unhandled exception event handler?
AppDomain.CurrentDomain.UnhandledException += (sender,e)=> releaseMutex();
It seems like the OnExit method has the best chance to be in the same thread, but even that seems a sketchy assumption. Is there a way to ignore the same-thread requirement? Or should I create and store a separate thread in conjunction with my mutex?
I personally wouldn't bother releasing it at all, especially since you handle AbandonedMutexException.
If a mutex is not used to synchronize threads of the same process there is no need to explicitly release it. When a process terminates OS automatically closes all handles created by the process, such as files, sockets, mutexes, semaphores and event handles .
If you still prefer to release it consider using Application.OnExit() since it is called from the main thread, just like the Startup().
According to my research, every GUI WPF application has a UI thread which can be accessed via Application.Current.Dispatcher (see for example this answer). This UI thread should always remain active for the lifetime of the application.
You can use Dispatcher.CheckAccess to see whether you are running in the UI thread, and if you are not you can use Dispatcher.Invoke to execute an action in the context of the UI thread.
The description of Application.Run implies that Application.OnStartup is always run on the UI thread, but it should not be harmful to check and, if necessary, use the UI thread dispatcher to invoke the action that creates the mutex.
It seems a reasonable guess that Application.OnExit is also always run on the UI thread, but since this does not appear to be documented, you should check and, if necessary, use the UI thread dispatcher to invoke the action that releases the mutex.
As Alexm correctly points out, you do not in fact need to explicitly release the mutex provided that the application is running in its own process (which will usually be the case) but you do need to ensure that the thread the mutex is created on will remain active until you are ready to free it. I believe using the UI thread is the simplest way to ensure this.

C# STAThread COMException

I have an external component (C++), which I want to call from my C# code.
The code is something like this:
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace dgTEST
{
class Program
{
[STAThread]
static void Main(string[] args)
{
ExtComponentCaller extCompCaller = new ExtComponentCaller();
result = extCompCaller.Call(input);
Thread t = new Thread(new ThreadStart(() =>
{
try
{
result = extCompCaller.Call(input);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}));
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
}
}
So the problem is that, at the first call it's working well, the external component called, I got back result.
But when I try to call it in an other thread, I got an exception:
System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' ... .
I'm sure this exception throwed, because of the STAThread. Because if I remove the [STAThread] attribute from the Main function, the same occurs with the first call of the external component, which was worked fine.
How can I call this external component from an other thread to get rid of this exception?
UPDATE-------------
Other crazy thing occurs now. When I start the program from Visual Studio with F5, the problem occurs in the first call as well, but when I execute directly the binary .exe file, it's working (from the other thread it isn't :( ).
If I switch the build from Debug to Release and starting it from Visual Studio with F5, the first call working again.
Why does it happen?
Thanks for you help in advance!
Best Regards,
Zoli
Threading is never a small detail. If code isn't explicitly documented to support threading then the 99% odds are that it doesn't support it.
And clearly this component doesn't support threading. Creating another STA thread is not the magic solution, it is still a different thread. The InvalidCastException tells you that it also is missing the proxy/stub support that's required to marshal calls from a worker thread, like the one that you are trying to create. Required to make thread-safe calls to code that isn't thread-safe. Albeit that you did break the contract for an [STAThread], it must pump a message loop. It is the message loop that allows making calls from a worker thread to a component that isn't thread safe. You get a message loop from Application.Run().
This is where the buck stops. It isn't thread-safe, period. Even if fix your main thread or ask the vendor or author to supply you with the proxy/stub, you still haven't accomplished what you set out to do, it won't actually run on that worker thread you created. So it must look like this:
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(() =>
{
ExtComponentCaller extCompCaller = new ExtComponentCaller();
result = extCompCaller.Call(input);
}));
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
Which creates the object on the same thread that you make the calls from so it is thread-safe. There's still the problem that this worker thread doesn't pump a message loop, COM components tend to rely on that. You'll find out whether that's a problem or not from deadlock or events that don't run. If it already worked okay in your test program when you called it from the main thread then you are probably okay with not pumping.

How to handle COM events from a console application?

I'm using a COM object from a third party library that generates periodic events. When I use the library from a Winforms app, having the object as a class member and creating it in the main form thread, everything works. However, if I create the object from another thread, I don't receive any event.
My guess is that I need to have some kind of event loop in the same thread used to create the object.
I need to use this object from a console application. I guess I could use Application.DoEvents, but I'd rather not include the Winforms namespace in a console App.
How can I solve this problem?
Update 3 (2011-06-15): The vendor has answered at last. In short, they say there is some difference between the message pump created by Application.Run and the one created by Thread.Join, but they don't know what that difference is.
I agree with them; any light shed on this matter would be very appreciated.
Update:
From Richard comment to mdm answer:
if there other component is single threaded and instantiated from an MTA then Windows will create the worker thread + window + message pump and do the necessary marshalling.
Trying to follow his advice, I'm doing the following:
Update 2:
I'm changed the code following João Angelo answer.
using System;
namespace ConsoleApplication2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
MyComObjectWrapper wrapper = new MyComObjectWrapper();
}
}
class MyComObjectWrapper
{
MyComObject m_Object;
AutoResetEvent m_Event;
public MyComObjectWrapper()
{
m_Event = new System.Threading.AutoResetEvent(false);
System.Threading.Thread t = new System.Threading.Thread(() => CreateObject());
t.SetApartmentState (System.Threading.ApartmentState.STA);
t.Start();
Wait();
}
void ObjectEvt(/*...*/)
{
// ...
}
void Wait()
{
m_Event.WaitOne();
}
void CreateObject()
{
m_Object = new MyComObject();
m_Object.OnEvent += ObjectEvt;
System.Threading.Thread.CurrentThread.Join();
}
}
}
I have also tried the following instead:
public MyComObjectWrapper()
{
CreateObject();
}
If you're using STA, then you're going to need a message loop one way or another. If you don't otherwise need a message loop, MTA is perhaps the simplest way to go, and is also the best for for a console-style application.
One thing to be aware of is that with MTA, it doesn't matter which thread created the object; all objects created by an MTA thread belong equally to all MTA threads. (Or, in COM speak, a process has exactly one Multi-Threaded Apartment, in which all MTA threads live.) What this means is that if you're taking the MTA approach, there's no need to create a separate thread at all - just create the object from the main thread. But you also need to be aware that incoming events will be delivered on a 'random' thread, so you'll have to take separate steps to communicate back to the main thread.
using System;
using System.Threading;
class Program
{
static MyComObject m_Object;
static AutoResetEvent m_Event;
[MTAThread]
static void Main(string[] args)
{
m_Event = new AutoResetEvent(false);
m_Object = new MyComObject();
m_Object.OnEvent += ObjectEvt;
Console.WriteLine("Main thread waiting...");
m_Event.WaitOne();
Console.WriteLine("Main thread got event, exiting.");
// This exits after just one event; add loop or other logic to exit properly when appropriate.
}
void ObjectEvt(/*...*/)
{
Console.WriteLine("Received event, doing work...");
// ... note that this could be on any random COM thread.
Console.WriteLine("Done work, signalling event to notify main thread...");
m_Event.Set();
}
}
Couple of comments on the previous version of the code you had: you had calls to Wait() in both CreateObject and in the MycomObjectWrapper constructor; seems you should only have one - if you have two of them, only one of them will get released when m_Event.Set() is called, and the other will still be waiting. Also, suggest adding in some debugging code so you know how far you are getting. That way you can at least tell if you are getting the event from COM, and separately, whether you are successfully communicating that back to the main thread. If the objects are marked neutral or both in the registry, then there should be no problem creating them from a MTA.
As already stated in other answers STA COM components require a message loop to be run in order for calls happening in other threads be correctly marshaled to the STA thread that owns the component.
In Windows Forms you get the message loop for free, but in a console application you must do it explicitly by calling Thread.CurrentThread.Join on the thread that owns the COM component and that is probably also the main thread for the application. This thread must be STA.
From the MSDN entry of Thread.Join you can see that this is what you want:
Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage pumping.
If you don't want to do anything else in the main console thread you just wait indefinitely, otherwise you can do other stuff while periodically calling Thread.CurrentThread.Join to pump messages.
Side-note: This assumes you're dealing with a STA COM component.
A simplified example:
class Program
{
[STAThread]
static void Main(string[] args)
{
var myComObj = new MyComObject();
myComObj.OnEvent += ObjectEvt;
Thread.CurrentThread.Join(); // Waits forever
}
static void ObjectEvt(object sender, EventArgs e) { }
}
In this example the console application will be in a never ending loop that should do nothing more then respond to events from the COM component. If this does not work you should try to get support from the COM component vendor.
IIRC, COM events require an event loop to work, something that pumps messages and calls the Win32 GetMessage function.
Winforms does this for you, or you can emulate it with Win32 calls. This question/answer has a good example you can build on.
I think the following should work:
[STAThread]
Main(...)
{
var comObject = new YourComObject();
comObject.Event += EventHandler;
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
void EventHandler(...)
{
// Handle the event
}
Have you defined the thread apartment model?
[STAThread]
static void Main(string[] args)
{
// Create the thread that will manage the COM component
Thread th = new Thread(...);
// Before starting the thread
th.SetApartmentState (ApartmentState.STA);
}
In the thread, just wait for an Event to signal its termination. While the thread is waiting on the event, I think that it should process messages on the thread loop.
Could you try this:
static class Program
{
MyComObject m_Object;
[STAThread]
static void Main()
{
m_Object = new MyComObject();
m_Object.OnEvent += ObjectEvt;
System.Windows.Forms.Application.Run();
}
void ObjectEvt(/*...*/)
{
// ...
}
}

Making COM calls from single thread hangs the thread

I have an application that does some excel automation through an automation add in.
This add-in is multithreaded, and all the threads manage to make calls to the excel COM objects. Because excel can sometimes return a "is busy" exception when making multiple calls, i have wrapped all my calls in a "retry" function. However i feel this is inneficient.
I am now trying to make all the calls to excel objects on the same thread, so that all calls are "serialized" by me, therefore reducing the risk of excel returning a "is busy" exception.
However when this thread tries to access an excel object, the application hangs. I have tried setting the thread to STA or MTA to no avail.
The code i use to launch everything from a single thread is as follows:
The "offending" part should be in "DoPass",maybe the way i am invoking the Delegate is somehow wrong.
public static class ExcelConnector
{
public static Thread _thread;
private static int ticket;
public static Dictionary<Delegate, int> actionsToRun = new Dictionary<Delegate, int>();
public static Dictionary<int, object> results = new Dictionary<int, object>();
static ExcelConnector()
{
LaunchProcess();
}
public static int AddMethodToRun(Delegate method)
{
lock (actionsToRun)
{
ticket++;
actionsToRun.Add(method, ticket);
}
return ticket;
}
public static bool GetTicketResult(int ticket, out object result)
{
result = null;
if (!results.ContainsKey(ticket))
return false;
else
{
result = results[ticket];
lock (results)
{
results.Remove(ticket);
}
return true;
}
}
public static void LaunchProcess()
{
_thread = new Thread(new ThreadStart(delegate
{
while (true)
{
DoPass();
}
}));
// _thread.SetApartmentState(ApartmentState.STA);
// _thread.IsBackground = true;
_thread.Start();
}
public static void DoPass()
{
try
{
Logger.WriteLine("DoPass enter");
Dictionary<Delegate, int> copy;
lock (actionsToRun)
{
copy = new Dictionary<Delegate, int>(actionsToRun);
}
//run
foreach (var pair in copy)
{
object res = pair.Key.Method.Invoke(
pair.Key.Target, null);
lock (results)
{
results[pair.Value] = res;
}
lock (actionsToRun)
{
actionsToRun.Remove(pair.Key);
}
Thread.Sleep(100);
}
}
catch (Exception e)
{
Logger.WriteError(e);
//mute
}
}
}
EDIT: the error can be reproduced in a simple test (the readline is just there to give time to the ExcelConnector thread to work):
var excelApp = new Application();
excelApp = new Application();
excelApp.Visible = true;
excelApp.DisplayAlerts = false;
System.Action act = delegate
{
string s = excelApp.Caption;
Console.WriteLine(s);
};
ExcelConnector.AddMethodToRun(act);
Console.ReadLine();
Unfortunately there is no point in what you are doing, this is already being done. The Office interop is based on out-of-process COM. Like many COM interfaces, the Excel interfaces are marked as apartment threaded in the registry. Which is an expensive way of saying they don't support threads.
COM automatically takes care of components that don't support threading, it automatically marshals calls made on a worker thread to the thread that created the COM object. Which should be a thread that's STA, like the main thread of any program that has a user interface. It will create an STA thread automatically if necessary. One side effect of this marshaling is that the calls made by the worker threads are automatically serialized. After all, the STA thread can only dispatch one call at a time.
Another side-effect is that deadlock is not uncommon. Which will happen when the STA thread stays busy and doesn't pump the message loop. The marshaling is done by COM plumbing code that relies on the message loop to dispatch the calls. This condition is pretty easy to debug, you'd use Debug + Break All, Debug + Windows + Threads and check what the STA (or Main) thread is busy with.
Also beware that attempting this kind of threading is probably 90% of the reason you get this interop exception in the first place. Trying to get code that's fundamentally thread-unsafe to do more than one thing at the same time just doesn't work well. You'd avoid the "is busy" exception from Excel by interlocking your own code, marking an operation that puts Excel in that 'busy' state so you back-off other threads. Painful to do of course.
You have to initialize COM in each thread you wish to use your COM library. From the documentation of CoInitializeEx "CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library.".
Instead of trying to implement your own threading perhaps you should check .NET's Task Parallel Library. Check this question on using COM objects from TPL. Essentially, you just create Task objects and submit them to an StaTaskScheduler for execution. The scheduler manages the creation and disposal of threads, raising exceptions etc.
I'm not really knowledgeable about C#, but my guess is that you still have to initialize COM in some way when starting a new thread in order to have a message box which can be used to signal your thread when the operation completed.
It's usually not necessary to initialize COM in .NET -- unless you've done some native things such as P/Invoking. Using IDispatch does not require explicit initialization of COM.
I think you're just dead locking somewhere. Fire up your debugger, when it hangs, break in, and type Monitor.TryEnter(...) for each of the object that you can lock (actionsToRun, results and others).
BTW, you should really consider restructuring your application to not use Excel concurrently -- even if you do some kind of "serialization". Even if you get it work, it will come back and bite you forever. It's officially discouraged, and I speak from experience.

Categories