Creating a COM object

G

Guest

Hi,

What is the right way to create an OCX COM component. The component is
already registerred, but can't create an instance. I am using the reference
to the interop module created.
If I use javascript or vbscript it works.

I will appreciate any help.

I do the following (C#):
Attempt # 1:

using System;
using MTMicrImage; // reference to the component

public class oMirImage : MTMicrImage.MicrImage // derives from interface
{
// create an instance of the base to use it in the implementation
private MTMicrImage.MicrImageClass obase = new
MTMicrImage.MicrImageClass();

public oMicrImage()
{
}

#region methods
// All methods go here
# endregion

#region properties
// All properties go here
#endregion
}

Whn compiling I get an error saying "MTMicrImage.MicrImageClass " is not
accessible due to its protection level
Same happend if the class inherits from the base clalss and the inteface as
follows:
..
..
public class oMirImage : MTMicrImage.MTMicrImageClass,
MTMicrImage.MicrImage // derives from interface


Attempt # 2

using System;
using MTMicrImage; // reference to the component
using System.Reflections;

public class oMirImage : MTMicrImage.MicrImage // derives from interface
{
private MTMicrImage.MicrImageClass obase; // his works of not "new"
is specified, but has null value.

public oMicrImage()
{
}

private object createInstance()
{

object obj = null;
try
{
obj =
Activator.CreateCOMObjectFrom"c:\\Interop.file.dll",
"InstanceMane");
}
catch (Exception e)
{

}
return obj;
}

#region methods
// All methods go here
# endregion

#region properties
// All properties go here
#endregion
}

Same problem as above.

Want something weird! Read below:
If I use vb scripting or javascript it works:
//using javascript
var oMicrImage = WScript.CreateObject("MTMicrImage.MicrImage")

Thjis works, it creates the object just right.

Thank you for your time.

Carlos Lozano
 
B

Bob Powell [MVP]

If you add a reference to the COM object an interop class will be created in
your solution. You can then access all the functionality of the COM object
as though it were a C# class.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
 
G

Guest

Hi Bob,

Thank you for your time.

Yes, setting the reference creates the interop class. I can see the
interfaces, classes and everything in the assembly, but can't create an
instance. Do not know why.

The code to expose the base code is:

using System;
using InteropClass;

public Class myClass : InteropClass.Interface
{
private InteropClass.OCXClass baseClass = new
InteropClass.OCXClass();

public myClass()
{
}

#region All properties and methods created from the interface
 
G

Guest

I was just thinking about the problem.

The instance I can create in javascript is by calling the OCX directly, not
the interop assembly. I am thinking there may be the problem. Poblably the
interop didn't get all the information from the OCX when created.

Is there a way to create an instance by calling the OCX directly from C#
(not using the interop). ie. Can I call it within an unmanaged section?

Thank you,
 
W

Willy Denoyette [MVP]

"baseClass" is declared as private, which makes it unreachacle from other
classes, are you sure you access baseClass from the declaring class?

....
private InteropClass.OCXClass baseClass ...

Willy.
 
G

Guest

Hi Willy,

Thank you Willy.

Yes, that is correct the private class object will serve to get all the base
class methods and properties.
I do not need access to the base class from outside. I will use them in the
implementation of the interface within the wrapper class.

In fact that is not the problem. The problem is to create an instance of the
base class.
using :
private Interop.OCXClass myclass = new Interop.OCXClass();

gives the error stated before.

I could also derive from the class and the interface to call the OCXClass as
the base implementation, but will still get the error message.

somthing like:
public Class myClass : InteropClass.OCXClass, InteropClass.Interface
{
public myClass()
{
}

public string Method()
{
return base.Method();
}

#region All properties and methods created from the interface
 
W

Willy Denoyette [MVP]

Are you sure the compiler complains about this statement....
private Interop.OCXClass myclass = new Interop.OCXClass();

How is the class declared in the interop assembly when you look at it using
Ildasm.exe?

Willy.
 
G

Guest

I have copied part of the class declaration for your review.
In fact the declaration of the constructor seems to be the problem as below.

.method assembly specialname rtspecialname
instance void .ctor() runtime managed internalcall
{
}

it is "internalcall" which makes it inaccesible.

I tired changing it to:
//.method assembly specialname rtspecialname
.method public specialname rtspecialname
instance void .ctor() runtime managed internalcall
{
}

and:
//.method assembly specialname rtspecialname
.method public specialname rtspecialname
instance void .ctor() runtime managed
{
}

but give different kind of problems, so I went back to the original interop
file.

In the object browser the clas constructor shows to be public.

In addition, as mentioned before I can create an instance of the class using
javascript. The only difference is javascript creates it directly from the
OCX file, c# uses the interop assembly. I think the problem is in the interop
assembly.

I also tried creating it manually.
used:
1) tlbimp // imported the OCX file into the interop file.
2) ildasm // Created IL code
3) ilasm // recompiled as dll.

Thank you,

Carlos

here is the whole definition of the class. I removed the methods and
properties.

.class public auto ansi import MicrImageClass
extends [mscorlib]System.Object
implements MTMicrImage._MicrImage,
MTMicrImage.MicrImage,
MTMicrImage.__MicrImage_Event
{
.custom instance void
[mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01
00 24 39 45 38 45 42 41 41 38 2D 35 37 33 43 // ..$9E8EBAA8-573C

2D 34 35 44 32 2D 41 36 34 43 2D 44 44 39 33 34 //
-45D2-A64C-DD934

38 39 37 34 34 44 45 00 00 ) //
89744DE..
.custom instance void
[mscorlib]System.Runtime.InteropServices.ComSourceInterfacesAttribute::.ctor(string)
= ( 01 00 19 4D 54 4D 69 63 72 49 6D 61 67 65 2E 5F // ...MTMicrImage._

5F 4D 69 63 72 49 6D 61 67 65 00 00 00
00 ) // _MicrImage....
.custom instance void
[mscorlib]System.Runtime.InteropServices.TypeLibTypeAttribute::.ctor(int16) =
( 01 00 20 00 00 00 ) // .. ...
.custom instance void
[mscorlib]System.Runtime.InteropServices.ClassInterfaceAttribute::.ctor(int16) = ( 01 00 00 00 00 00 )
.method assembly specialname rtspecialname
instance void .ctor() runtime managed internalcall
{
} // end of method MicrImageClass::.ctor

// methods go here

} // end of class MicrImageClass
 
W

Willy Denoyette [MVP]

Inline

Willy.

Carlos Lozano said:
I have copied part of the class declaration for your review.
In fact the declaration of the constructor seems to be the problem as
below.

.method assembly specialname rtspecialname
instance void .ctor() runtime managed internalcall
{
}

it is "internalcall" which makes it inaccesible.
No, its not! Don't mess with this, "internalcall" means that the CLR is
called to contruct the RCW.
The problem is ".method assembly" ... , this means that the class is not
meant to be created from outside the Control code, if this class is authored
using VB6, it means that the class 'instancing' attribute is set to
PublicNotCreatable (the default when using the Class wizard in a VB Control
project), which translates into assembly (or internal in C#).
I tired changing it to:
//.method assembly specialname rtspecialname
.method public specialname rtspecialname
instance void .ctor() runtime managed internalcall
{
}

and:
//.method assembly specialname rtspecialname
.method public specialname rtspecialname
instance void .ctor() runtime managed
{
}

but give different kind of problems, so I went back to the original
interop
file.

Not supprisingly.
In the object browser the clas constructor shows to be public.

In addition, as mentioned before I can create an instance of the class
using
javascript. The only difference is javascript creates it directly from the
OCX file, c# uses the interop assembly. I think the problem is in the
interop
assembly.
No the problem is that you are trying to create a non creatable object. Take
a look at your ocx file using oleview.exe , you will notice that the class
interface you are trying to create from C# is marked "noncreatable". So I
guess you are mixing things up and you do create a different class using vbs
or Jscript.

I also tried creating it manually.
used:
1) tlbimp // imported the OCX file into the interop file.
2) ildasm // Created IL code
3) ilasm // recompiled as dll.

OCX are activeX controls, you should use aximp instead of tlbimp.
 
G

Guest

Hi Willy.

I really appreciate you have taken the time to helping me with this. I just
found an alternate "hybrid" solution (part in VB6, part c#), but will be
looking into your last suggestion as I prefer a 100% c# solution.

Description:
I found the OCX was developed using VB6 (using the object viewer in VB6).
As it was not possible to create the instance in .NET (I tried C#.NET,
VB.NET), I decided to create it using VB6.

The hybrid solution is as follows:
1) Creating a a DLL module using a VB6 class to create the instance as an
object
2) Passing the object instance to the C# class and cast it with the class
derived from the interop interface.

It seems to be working okay.

Thank you,

Carlos Lozano
 
W

Willy Denoyette [MVP]

I would like to see how you managed to create an instance of a non-creatable
class from another DLL, this is simply not possible, so I guess you are
creating another class. Would you mind to post the oleview output of the OCX
assembly.

Willy.
 
G

Guest

Hi Willy,

Here is the code per your request.
I just used the same command as in vbscript.

I created an empty class and added the following function.
Public Function CreateInstance(ByVal sComponentID As String) As Object
Set CreateInstance = CreateObject(sComponentID)
End Function

compiled into a dll. Registered the DLL.

Then added a reference to the C# code and another class to derive from it as
below:

using MTMicrImage; // This is the reference to the OCX interop
using vbMicrImage; // reference to the VB6 DLL and created an interop assembly

namespace MTMicrImage
{
/// <summary>
/// Summary description for _oMicrImage.
/// </summary>
///

// Inherits from the VB6 Interop
internal class ovbMicrImage : vbMicrImage.vbMTMicrImageClass,
vbMicrImage.vbMTMicrImage
{
public ovbMicrImage()
{
}
}

// inherits all interfaces from the OCX interop
internal interface __oMicrImage : MTMicrImage.MicrImage,
MTMicrImage._MicrImage, MTMicrImage.__MicrImage,
MTMicrImage.__MicrImage_Event
{

}

// Inherits from above interface
public class _oMicrImage : MTMicrImage.__oMicrImage
{
// This line caused the accessibility problem
// private MTMicrImage.MicrImageClass obase = new
MicrImageClass();

// Created an instance of the VB6 interop class
private ovbMicrImage ovbMicrImage = new ovbMicrImage();
private bool lDataReceived = false;

public _oMicrImage()
{

// This is the ClsId registration
of the OCX file, not the
// interop.
string sComponent = "MTMicrImage.MicrImage";
try
{
// Passed the ClsId to the vb6 class and cast it to the OCX interop class
obase =
(MTMicrImage.MicrImageClass) ovbMicrImage.CreateInstance(sComponent);
}
catch (Exception e)
{
MessageBox.Show("Can not create instance of component " + sComponent +
"\n" + e.ToString());
}
}

// Implementation of all methods and
properties goes here
public string sStatus
{
get
{
return obase.sStatus;
}
set
{
obase.sStatus = value;
}
}

public void reset()
{
obase.reset();
}

// and so on....
// Removed the other implementations
}
}

This completes the wrapping.

Then I just create an instance of _oMicrImage in my main application.

What do you think?

Carlos Lozano
www.caxonline.net
 
W

Willy Denoyette [MVP]

Carlos,
I'm getting the impression that you are doing all this from the command line
instead of from within VS, please correct me if I'm wrong. The ActiveX DLL
is a VB6 ActiveX "usercontrol" type of dll (OCX) right?
When using the command line tools did you create the interop assembly using
aximp.exe or did you use tlbimp.exe. Note that you should use the former!
And don't forget that hosting OCX requires a valid control host, windows
forms are valid hosts, but console applications and services aren't!!!

Willy.
 
G

Guest

Willy,

I am using VS6 and VS.NET 2003.
Yes, the vb DLL is an ActiveX DLL with no Forms. The VB6 project has only
the mentioned class.
In this case I allowed VS.NET 2003 created both Interop assemblies
automatically when adding the references to the project. So, I am using the
default ones. I think it didn't use aximp as there are not any {Ax assembly
name}.dll files, just the {assembly name}.dll
Yes, I am not using console apps.

I will try your approach later. I just need to deliver the application ASAP.

Thank you,

Carlos Lozano
 
W

Willy Denoyette [MVP]

Sorry , but I'm at lost here, in VB6 you have ActiveX DLL and ActiveX
Control projects. The first is to build regular COM servers, the second is
to build OCX user controls.
I thought you were using the second in your application, but now you say
it's an ActiveX DLL !
I still assume your are talking about an OCX, so read on.
Both types are different as when we talk about creating the interop
assembly, the classes in an OCX are by default not "creatable", but the
ActiveX importer (AXIMP.EXE) changes the class .ctor from internal into
public when creating the IA, the tlbimporter (used when importing a COM DLL)
doesn't change the accessibility, so it translates to "internal", that means
the class cannot be created from .NET.
When importing using VS, you have to add an "OCX" to the toolbox, you should
not add a refererence to an OCX using Project-Add Reference to a COM object,
the latter will not create the right interop assembly!!!

Note that the scripting engine doesn't care about the non-creatable
attribute for a coClass, that's why VBScript has no problem creating such a
OCX control class.

Willy.
 
G

Guest

Hi Willy,

You just gave me the answer to the problem.

I was creating a reference to the original OCX file instead of adding it to
the toolbox. That confirms my thoughts about the interop was not created
right. So, VS used tlbimp instead of Aximp, because of my mistake.

The VB6 ActiveX DLL came into the game as a workaround to the problem to
create the instance of the original OCX file. VB6 compiled it into a DLL not
an OCX as it is not a control, but it is indeed an ActiveX.

I will try your approach this week.

I am amazed with your deep knowledge. How long have you been developing
solutions? Where are you located?

Thank you very much.

Carlos Lozano
www.caxonline.net
 

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