6
votes

I'm struggling with running a function from an ActiveX DLL (compiled from VB6) in a background thread from a C# WinForms application.

Because the VB6 DLL project contains a lot of references to an old library called Sheridan Controls (threed32.ocx), which I'm helpfully informed "doesn't support multi threaded mode", I have to set the Threading Model option to Single Threaded (instead of Apartment Threaded) when compiling the DLL in VB6. So even though I set the ApartmentState property to STA on the C# Thread object from which I invoke the DLL, it still ends up clogging up the UI thread.

I'm not sure what my options are at this point. Refactoring out the Sheridan Controls from the DLL would be a tedious job. Another is just to accept defeat and let the UI hang while the DLL does its work.

I guess my main question is; does anyone know of a way I could (without too much hassle) run the single threaded ActiveX DLL in a separate process/service that could be invoked asynchronously from the main C# thread? Or is there any other option that I'm not aware of?

Solved: Based on the information from user @mnistic, I was able to find a solution. I had to rebuild the ActiveX DLL as an ActiveX EXE, which runs as an out-of-process component. To get it working I had to set "Start Mode" to "Standalone" in project properties. I also set the Instancing parameter on the VB6 class to SingleUse, to ensure that global state would not be shared across instances.

After updating the project reference, I was able to invoke the functions in the library in background threads from my C# application without causing GUI lag.

1
What kind of an ActiveX DLL is this? Is it a control that you're trying to embed within your GUI?mnistic
If you are up to no return value, or simple type return value, you could wrap ActiveX in in command line exe, then just 'Shell' your exe with CreateProcess set usynchroniuos = yes..Siyon DP
This is not fundamentally different from the way .NET controls behave. Except that if you assign their properties from a worker thread then you have some hope of getting an InvalidOperationException and learn to use Control.BeginInvoke(). For ActiveX controls this is entirely automagic. These controls were made 20 years ago for machines that were about 65 times slower than the one you use now. So they don't by nature "clog up" anything. Unless you make the traditional mistake of stuffing them with thousands of items.Hans Passant
Start a command line project in Visual Studio , reference your ActiveX DLL, run the function then return the value as process resultSiyon DP
The "proper" way of doing this used to be to create an "out of process" component and marshal the data across, but if all you need is this one double value out of it, then wrapping the dll and running with CreateProcess as suggested is good enough.mnistic

1 Answers

4
votes

When it comes to ActiveX, Microsoft differentiates between in-process and out-of-process components. Sometimes when people talk about ActiveX they are referring to in-process components, dll or ocx files that run in the same process as the client that's using them. Typically these components include GUI elements that VB6 made easy to embed within the client application. However, an in-process component must use the client's thread of execution, which in your case was causing the perceived lockup in main thread.

This is what out-of-process components are for. They execute in a separate thread -- separate process as a matter of fact. The drawback is that the communication needs to cross process boundaries, but in your case that's not a concern, and they are relatively easy to set up: https://msdn.microsoft.com/en-us/library/aa262334%28v=vs.60%29.aspx