mfc activex control in c# windows service

A

andy.g.ward

I keep getting this when trying to create an MFC activex control in a
c# windows service - anyone got any ideas what the missing module could
be???

Exception thrown : System.IO.FileNotFoundException: The specified
module could not be found.
at System.Windows.Forms.UnsafeNativeMethods.CoCreateInstance(Guid&
clsid, Object punkOuter, Int32 context, Guid& iid)
at System.Windows.Forms.AxHost.CreateWithoutLicense()
at System.Windows.Forms.AxHost.CreateWithLicense(String license)
at System.Windows.Forms.AxHost.CreateInstance()
at System.Windows.Forms.AxHost.GetOcxCreate()
at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)
at System.Windows.Forms.AxHost.CreateHandle()
at System.Windows.Forms.Control.CreateControl(Boolean
fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl()
at MyService.MyService.Process() in s:\myservice\service1.cs:line 93

For more information, see Help and Support Center at
http://go.microsoft.com/fwlink/events.asp.


I have tried MANY different ways to use an MFC ActiveX control in my c#
windows service but I consistently come up against the above error
message. There can't be any missing modules since the ocx I am trying
to create is in the same directory as the #c service exe.

Many thanks for any help,
Andy
 
D

Dmitriy Lapshin [C# / .NET MVP]

Hi Andy,

1. Why do you use the AxHost class in a windows service? I am pretty sure
creating an interop assembly and instantiating the COM component instance
through the constructor exposed by its interop class is much more correct
solution.

2. The location of the OCX on disk is irrelevant. Given the OCX is properly
registered, it's location is stored in the registry so the system is able to
locate and load the .OCX file. If the OCX is not registered, no 'special'
location would allow the system to instantiate it with CoCreateInstance.

3. Can your OCX operate in non-visual mode? Windows services don't have any
GUI, they are even not allowed to interact with the desktop by default.
 
A

andy.g.ward

Hi Dmitriy,
Thanks for your answers. I wanted to use an activeX so that I could
indirectly use a set of MFC dlls created for another application. The
ActiveX control links with these other dlls libraries and allows me to
use them. I thought it would be the easiest way to use these dlls from
a c# windows service...

You say I should create an interop assembly and instantiate the COM
component instance through the constructor exposed by its interop
class. Do you have any comments on how I can do this considering the
above requirement?

I thought I would have to alter the MFC dlls to be able to use them
directly in c#. I don't want to do this. I simply want to use the
functionality in thes dll's in a c# windows service.

Again, many thanks,
Andy
 
D

Dmitriy Lapshin [C# / .NET MVP]

Andy,

My experience with MFC dates back to, I guess, something around 1999, so I
can miss some important points. Still, here goes.

If these DLLs are regular Win32 DLLs with declared exports, you can use
these DLLs as you would use Windows API dlls - through the DllImport
attribute.
Just make sure to specify correct calling convention - not sure this is
WINAPI for MFC dlls.

If you however want to use classes, going the MFC-based COM object is much
better as you cannot import C++ classes from a DLL in .NET.
In this case, make sure the COM is registered with regsvr32.exe, then, from
your C# project, go to the "Add Reference" dialog, switch to the "COM" tab
and choose your COM object from the list (or browse to the OCX). The IDE
will generate an interop assembly for you. You can also do the same with
command-line tlbimp.exe, if you want more control on namespaces and import
options.

Now that you have referenced the COM object and its interop asssembly has
been added to the list of references, launch Object Browser and examine the
namespace from the interop assembly.
You should see a class named something like MyObjectClass having a
parameterless constructor. This is the class you need to instantiate to
create an instance of your COM object. The class should have the same
interface your COM object has, so I think once you have an instance, the
rest should be simple.
 
W

Willy Denoyette [MVP]

Dmitriy Lapshin said:
Andy,

My experience with MFC dates back to, I guess, something around 1999, so I
can miss some important points. Still, here goes.

If these DLLs are regular Win32 DLLs with declared exports, you can use
these DLLs as you would use Windows API dlls - through the DllImport
attribute.
Just make sure to specify correct calling convention - not sure this is
WINAPI for MFC dlls.

If you however want to use classes, going the MFC-based COM object is much
better as you cannot import C++ classes from a DLL in .NET.
In this case, make sure the COM is registered with regsvr32.exe, then,
from your C# project, go to the "Add Reference" dialog, switch to the
"COM" tab and choose your COM object from the list (or browse to the OCX).
The IDE will generate an interop assembly for you. You can also do the
same with command-line tlbimp.exe, if you want more control on namespaces
and import options.

Now that you have referenced the COM object and its interop asssembly has
been added to the list of references, launch Object Browser and examine
the namespace from the interop assembly.
You should see a class named something like MyObjectClass having a
parameterless constructor. This is the class you need to instantiate to
create an instance of your COM object. The class should have the same
interface your COM object has, so I think once you have an instance, the
rest should be simple.

Dmitriy,Andy

ActiveX controls can ONLY be hosted in a Windows Forms application and IE
(itself an ActiveX host), and only if they derive from
System.Windows.Forms.AxHost.

To achieve this you have to create a wrapper control using aximp.exe
file.dll or file.ocx. This wrapper control contains an instance of the
underlying ActiveX control. It knows how to communicate with the ActiveX
control, but it appears as a Windows Forms control. This generated control
hosts the ActiveX control and exposes its properties, methods, and events as
those of the generated control.

But here it comes, ActiveX controls (just like Windows.Forms) are not
designed to be used hosted in windows services, they need a STA to live in
and a thread that pumps messages. Unless they are based on a light weight
windowless control, they assume to run in a interactive user session, which
services by default do not.

So I my suggestion is - don't do this, it's a recipt for failure.

Willy.
 
A

andy.g.ward

Dmitriy / Willy,

Thanks for all your help - I've decided to go the DLLImport route after
all, seems the easiest way!

Cheers,
Andy
 
D

Dmitriy Lapshin [C# / .NET MVP]

Willy,

Thanks for your valuable comments and I do gree with you in general.
However, what I had in mind was instantiating an OCX control like a
non-visual COM object - in this case it didn't require AxHost, nor would it
require an interactive session. For example, Microsoft Script Control, while
can be hosted as an OCX on a form, can also be used as a regular COM object
from a, say, console application. In both scenarios an STA thread *will* be
required - but is there any problem with creating STA threads from a Windows
Service? (as far as I understand, a thread can have a message pump
regardless of desktop availability).

--
Sincerely,
Dmitriy Lapshin [C# / .NET MVP]
Bring the power of unit testing to the VS .NET IDE today!
http://www.x-unity.net/teststudio.aspx
 
W

Willy Denoyette [MVP]

Dmitriy Lapshin said:
Willy,

Thanks for your valuable comments and I do gree with you in general.
However, what I had in mind was instantiating an OCX control like a
non-visual COM object - in this case it didn't require AxHost, nor would
it
require an interactive session. For example, Microsoft Script Control,
while
can be hosted as an OCX on a form, can also be used as a regular COM
object
from a, say, console application. In both scenarios an STA thread *will*
be
required - but is there any problem with creating STA threads from a
Windows
Service? (as far as I understand, a thread can have a message pump
regardless of desktop availability).

ActiveX controls need to be hosted in an OLE control container (ActiveX
control container) to be fully functional.
So while it's possible to host a control like msscript.ocx in a non-activeX
control container like a windows form, you won't be able to receive
notifications from the control (in the form of events). For the Msscript
control this might not be to much an issue if you don't care that script
engine error messages might get lost when hosted in a non OLE control
container, but for a regular ActiveX control it's simply a basic
requirement.
I would suggest you check "MFC ActiveX Controls" in MSDN for more info on
the subject.

Note that v2 will include both an ActiveX container and Active Document
container control, so it will be possible to host ActiveX controls in
regular Windows Forms applications.

Sure windows services can have threads running in an STA, but it's not a
good idea to host ActiveX controls in windows services, as most ActiveX
controls need their container to run in the default Winsta0 (the visible
desktop winstation).

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top