I am new to COM and need to add a Server COM object to my c# application so I can call its methods and implement events. The documentation I have says this requires a COM-aware language such as Visual C++. My app is written in C# so I'm not sure how this is going to work. Any direction would be appreciated.
I am writing an app that communicates with a serial hypercom terminal. The device came with a DLL (the com server interface) that I will need to figure out how to use in my c# application.
I added a reference to the DLL to my project, which shows up as a type library. In object explorer I get interfaces, and some classes etc.
Thanks,
Matt
You can add the COM object as a reference. .NET will create an interop assembly to work with the COM object, just like it was a .NET type.
CComObjectRoot can be used as a base class for all COM objects implemented with ATL. As such you don't have to worry to implement something similar in C#, the required methods (AddRef, Release, QueryInterface) will be generated by tlbexp for classes that are tagged with ClassInterface.
STDMETHODIMP is a define which serves to declare the most common methods that can be called from COM (#define STDMETHODIMP HRESULT STDMETHODCALLTYPE). Again if your class is tagged with ClassInterface you will not have to worry about.
Such construction is required in C++ when your class implements several interfaces. I think this is not required if you tell C# compiler that your C# object implement IDispatch, IFPESOlementationEvents. The appropriate code will be written automatically by the compiler.
Probably everything will not make much sense if you are new to COM and C#, I'll suggest to take a look at the various introduction that you may find on the web, like this.
Related
Let me elaborate, before someone is thundering down on me with "Never reuse a COM interface!!!"
We implemented an COM interface on a program which is discontinued. We now actually buy a similar piece of software from a third party (so I can't change that!)
The COM interface is still used by many (third party) programs. Now I have to integrate the new piece of software with these programs (which I can't change because they are third party).
So I think I need a proxy: This proxy will reuse the COM interface so none of the third party programs will be able to tell they're not talking to the discontinued software. Inside the COM object, I'll 'translate' the commands and forward them to the new piece of software.
I'm using C# to build my proxy and I've used the tlbimp.exe to generate a DLL from the type library of the old program.
I'm referencing this generated DLL in my COM project where I provide a implementation for the given interface.
Next, I register the output DLL from my project and use a old client to call the proxy.
It returns the error: Unable to cast object of type 'Lib.ApiClass' to type 'Lib.ApiClass'.
Why is that?
Should I use a different approach?
I have created an application which inherit the C++ Dll in .Net application with the help of the Link which used the Concept of Virtual Table.I was trying to find out the possibility for inhering C++ Dll in .Net. Above Link is very helpful for me.
Now, I want to inherit my C# class from JSAPI of Firebreath framework which is the supporting framework of Native C++. I am using the Dumpbin.exe to verify which functions are exported in my .Net application.
Please let me know if any solution.
To the best of my knowledge, there is no way to directly do what you want to do; however, you could possibly create something that extends JSAPI that can then wrap a managed object, though, using the reflection APIs to implement methods like HasMethod, HasProperty, GetProperty, SetProperty, and Invoke. Go look at NPObjectAPI in the firebreath source as kinda an example of what I mean. FireBreath has several such objects that make things that don't normally conform to JSAPI act like JSAPI objects.
Is it possible to force a COM Visible .NET assembly to instantiate as System.__ComObject, rather than it's .NET type? The reason I ask is, part of my app uses 3rd party COM objects, but some of those, when written in .NET, get instantiated as their .NET types and break the object handlers I've created. I have no control over methods used to create the COM objects. Currently I'm using the following to create the objects.
Type comType = Type.GetTypeFromCLSID(objectGUID);
comObject = Activator.CreateInstance(comType);
Thanks!
Actually, no.
The COM activation of managed objects is done in the same AppDomain as the caller. IMHO, This is a nasty issue with COM interop in .NET. There are several questions here on SO with all sorts of attempts at making this work. I can attest that I've tried most of these to no avail. Your COM API provider SHOULD be producing a PIA (Primary Interop Assembly) to ensure forward type compatibility. If they are not, you are going to have some nasty issues.
The only workaround I'm aware of as a client is to only use the 'object' type. Everything would need to go through reflection. Some things you still can't do. For example, you would not be able to implement an interface.
I havn't a clue why this works this way. It's caused me no end of problems producing a viable api for both unmanaged and managed code.
we're considering exposing some C# types to C++ clients via COM. What problems can we expect to hit over the life of the project? E.g. how will versioning be managed?
On versioning, it would seem from reading this that we should decorate our types to be exposed with [ClassInterface(ClassInterfaceType.None)] and use an explicit interface. That way I assume we fully control the interface that will be exposed to COM clients.
Thanks in advance.
Since you are using a C++ client you should definitely use explicit interfaces for early binding. Dispatch interfaces are useful when using scripting clients such as VBS but they are rarely useful for C++ clients.
The only way to version an interface is to create a new interface (possibly inheriting from the original interface). When using explicit interfaces you have full control over this process.
This means you should create an interface for every class that you intend to expose via COM. Don't forget to mark every interface and class with the ComVisible and Guid attributes. Also all your classes must have a default constructor.
You'll have to read about the GUID attribute (including this) to maintain binary compatibility and only rebuild the clients when necessary.
Also you might be interested in the ComVisible attribute that helps reduce registry pollution.
To get full control over COM interfaces, define them in MIDL. Build a type library with those interfaces in a C++ project, then import type library to C# and implement interfaces.
This approach is useful with complex interfaces where marshaling is not trivial.
Versions should be done COM-style, changing GUIDs and adding new or inheriting interfaces.
I've been told to write a dialog in C# which must be instantiated from an unmanaged c++ dll. We do this in other places in our code by simply adding a managed c++ class to the C++ project, then calling the C# dll from the managed c++ class. However I'm finding that doesn't work for me from where I have to do it. I think because the c++ dll is an MFCActiveX project. As soon as i set the clr on any file in this project, it will no longer register correctly. When i attempt to register it, i get three errors, then a message that it registered. However when i try to use it i get a 0x80040111 "ClassFactory cannot supply requested class" error.
If anyone has any idea what the problem is here i would greatly appreciate it. I either need to be able to accomplish this (preferred) or prove that it's not possible.
Thanks
I can't see how a MFCActiveX project would prevent you from creating the C# class in this way. Unless it simply does not allow for a managed class to be added.
If you can't get the managed C++ class trick to work, another option is to use COM. It's possible to register a factory of sorts in the C# project as a COM object. Say give it the following interface
[ComVisible(true)]
[Guid("babe87fc-1467-4913-a1d3-47eeedf1afb5")]
public interface IDialogFactory {
void Create();
}
You'd also have to create a backing class as well. But then you could register the managed assembly and use COM to access it.
You must now register it with "regasm" instead of "regsvr32".