简体   繁体   中英

.NET implementation of C++ interface, exposing to COM

I'm sure the answer to my issue is a combination of many threads already present on this forum. Maybe you can help me put the pieces together.

So my challenge is, I have some C++ code that implements an interface that looks like this:

interface ItsSupplier : IDispatch {
    [propget, id(1), helpstring("property name") HRESULT Name([out, retval] BSTR* pVal);
}

The DLL which implements this interface, is a usable plugin in a third party software. I want to make a plugin written in .NET. Since the software using the plugins is not .NET, I asume that the DLL have to be a COM object.

Here is how I go about it in .NET.

[Guid("xxxx")]
public interface ItsSupplier {
    [DispId(1)]
    [return: MarshalAs(UnmanagedType.Bstr)]
    string Name { get; }
}

[Guid("xxxx"),
ClassInterface(ClassInterfaceType.AutoDispatch),
ComSourceInterfaces(typeof(ItsSupplier))]
    public class SupplierClass : ItsSupplier
    {
        public string { get { return "someName"; } }
    }
}

Under project settings, I have checked "Register for COM interorp".

After build I run "regasm testDll.dll"

My questions are ...

Is it the right way to define the ItsSupplier interface myself? I mean, this is a interface which the third party software expects, so will it have to be referenced somwhere else?

Am I doing it right, when it comes to the COM interop part?

I hope I'm explaining this right :)

Cheers /Thomas

---------------- EDIT AFTER RESPONSE FROM HANS ------------------------

When i build the tlb file and view the original and my version in Oleview, this is what I get.

Here is what the original interface plugin looks like in Oleview:

[
  odl,
  uuid(370B4079-40BB-47C9-B797-33B3B5422685),
  helpstring("ItsSupplier Interface"),
  dual,
  oleautomation
]
interface ItsSupplier : IDispatch {

Here is what mine looks like:

[
  odl,
  uuid(370B4079-40BB-47C9-B797-33B3B5422685),
  version(1.0),
  dual,
  oleautomation,
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "COMDLL.ItsSupplier")    

]
interface COMDLL_ItsSupplier : IDispatch {

The "COMDLL" Is the name of my visual studio project. Do you think that matters?

/Thomas

No, lots of subtle mistakes that will get you into trouble. First off, the c++ interface declares a dual interface, supporting both early binding and late binding through IDispatch. You have to use the [InterfaceType] attribute in .NET to get the same:

[ComVisible(true)]
[Guid("xxxx")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ItsSupplier {
    [DispId(1)]
    string Name { get; }
}

Be sure to use the exact same guid, it wasn't visible in your snippet. The [MarshalAs] attribute is unnecessary, the string already marshals as a BSTR.

Next is the class. You do not want to expose the class implementation. That forces the client code to also beware of System.Object, the base class of all .NET classes. It will appear in the type library. Using [ComSourceInterfaces] is incorrect, that should only be applied to dispinterfaces for events.

[ComVisible(true)]
[Guid("xxxx")]
[ClassInterface(ClassInterfaceType.None)]
public class SupplierClass : ItsSupplier
{
    public string Name {
        get { return "someName"; }
    }
}

Again use the exact same guid as used in the IDL file. Next is registration. Using the "Register for COM interop" option is fine but then do not run Regasm.exe again. You'll mess up the registration with that. If you do prefer to register by hand then always use the /codebase option so the assembly doesn't have to be installed in the GAC.

The ultimate check that you got everything right is to create the type library with Tlbexp.exe and view it with Oleview.exe, File + View Typelib. It should be an exact match with your IDL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM