views:

1218

answers:

3

We are required to use a 3rd party ActiveX control.

The only issue is, the layer in our software is a business layer and has no access to a window or form. It also runs on separate threads (and should work from any thread) that are not STA.

Rather than breaking our separation of UI from business logic, we used this workaround to make it work:

Thread thread = new Thread((ThreadStart)
delegate
{
_myActiveX = new MyActiveXType();
_myActiveX.CreateControl();

//more initialize work

Application.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();

Then anytime we need to reference the control, we call _myActiveX.BeginInvoke() or Invoke().

On disposing of this class (exiting our app), we dispose the control and abort the thread.

My question is, are there any problems with this? Is there a better way to handle this?

Is there a better built in way to work with an ActiveX control from within an unknown multi-threaded environment? We are trying to write our class in a way that wraps the control but will work from any thread.

UPDATE: As an answer suggested, we really would rather use the standard COM object and not use a control at all. Our issue with that was we would get the error "(Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)" upon the first method or property we call on the COM object. This is a pretty generic error that we don't get when using the ActiveX, any ideas?

UPDATE: Our ocx is "CX25.ocx", using tlbimp.exe we get CX25Lib.dll. Using aximp.exe, we get AxCX25Lib.dll and CX25Lib.dll. CX25Lib.dll does not work in either case. AxCX25Lib.dll works.

+1  A: 

If you are calling the ActiveX control from a business layer, that means that it must be able to be used without a UI, e.g. just by calling its public methods. Why not just create an interop RCW for the ActiveX control class and call its methods directly?

Christian Hayter
Are you speaking of running tlbimp on the .ocx control? We tried that and it would not work. We would get "Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))" any time we tried it from a standard COM object. The ActiveX control works for some reason.
Jonathan.Peppers
Have you tried `aximp.exe` instead of `tlbimp.exe`? It creates two assemblies: a normal RCW one and a WinForms proxy one. You may be able to use the RCW assembly on its own in code. Disclaimer - I haven't tried this, just guessing based on my `tlbimp.exe` experience.
Christian Hayter
See my edit above.
Jonathan.Peppers
Are the methods you want to call on the actual UI control class, or on a separate helper class? If they are on the UI control class, then I would expect it to throw a runtime error if it was instantiated outside an ActiveX control host. However, I would expect a separate helper class to be able to instantiated anywhere.
Christian Hayter
To me it looks like both classes have identical methods (except the AX has methods from System.Windows.Forms.Control). So I feel like we are not doing anything wrong. It almost seems like there is something going on within their ocx that is making .Net unable to use it from outside the AX host.
Jonathan.Peppers
Not what I meant, I'll re-phrase. Suppose the OCX exposes multiple classes, e.g. TheUIControlClass, AHelperClass, AHelperCollectionClass, etc. Does your calling code (a) actually need to instantiate an instance of TheUIControlClass to do its job, or (b) can it get away with just instantiating one of the helper classes? If the answer is (a), then you're out of luck because it will expect to be contained within a proper host like AxHost.
Christian Hayter
The ocx only exposes 1 class/interface (besides some internal stuff like Events, SinkHelper, etc.), and it would appear to me that it shouldn't require the AxHost to work, but for some reason it does. We do not want or need the UI control for our situation, but have no idea what is going on internally with the ocx--it was written by a 3rd party.
Jonathan.Peppers
OK. :-( Have you tried instantiating the AxHost in your business code directly without adding it to a Form.Controls collection?
Christian Hayter
That is what the above code does. It starts a new thread with it's own message loop--this is the only way I know to make it work, but it looks like a hack. My question was if this is the proper way to use an AxControl without a Form, or why I have to use a control in the first place?
Jonathan.Peppers
A: 

I'm assuming this is the proper way to go about this.

We've been using my code above in test environments for the past few weeks with no issues.

If anyone has to use an ActiveX without a form, I assume this is one way to do it.

Just make sure to call _yourActiveXControl.CreateControl() directly after your ActiveX object's constructor. This simplified many issues we had originally.

Jonathan.Peppers
A: 

My solution is to create a hidden winform that host the activex control

Benny
My solution seems much more lightweight. What do you gain by using an off-screen form?
Jonathan.Peppers
I have a third-party program which expose an activex control, no easy way to control the program, i turn to activex control. actually, i tried your solution, it seems it works too. so i will take your solution.
Benny