How to pass one COM class instance as a parameter to another COM method in C#?

389 views Asked by At

I created a wrapper for 2 COM DLLs using TlbImp.exe. One has a class that the wrapper describes as

using System;
using System.Runtime.InteropServices;

namespace GNOTDRSIGNATURESERVERLib
{
    [CoClass(typeof(GNOTDRSignatureServerClass)),
        Guid("20CBF9E0-06BF-11D3-97B5-0080C878CFFA")]
    public interface GNOTDRSignatureServer
    {
    }
}

This object must be passed as a parameter

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace GN8000Lib
{
    [TypeLibType(2),
         ClassInterface(0), 
         ComSourceInterfaces("GN8000Lib._I8000Events\0"),
         Guid("DCAD84FE-43A8-11D3-B1A2-005004131886")]
    public class GN8000Class : I8000
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        public extern GN8000Class();

        [DispId(6)]
        [MethodImpl(MethodImplOptions.InternalCall)]
        void I8000.Initialize(
            [IUnknownConstant] [MarshalAs(UnmanagedType.IUnknown)] [In]
            object pSigServer = null);
    }
}

Then I call the method like this:

var gn8000 = new GN8000();
var signatureServer = new GNOTDRSignatureServer();
gn8000.Initialize(signatureServer);

I think that the object that is being passed isn't the right one. I feel like TlbImp.exe could link those DLLs and use GNOTDRSignatureServer instead of UnmanagedType.IUnknown, or that I could use System.Runtime.InteropServices.Marshal.GetComInterfaceForObject

What is wrong with my code?

1

There are 1 answers

1
Hans Passant On BEST ANSWER

The declarations look pretty ugly, I'll assume they were generated by some kind of reverse-engineering tool and you didn't write them yourself. In which case having an empty interface isn't that unusual. The equivalent in COM is a dispinterface, an interface that only supports late binding through IDispatch. This is fairly common, the COM server might have been designed to work with scripting languages, runtime environments that only support late binding. Same thing as ComInterfaceType.InterfaceIsIDispatch in .NET. The [DispId] is important for late binding, call by number instead of name.

Which then also makes the argument type easy to explain. Scripting languages use VARIANT as their variable type. Pretty similar to a variable you'd declare as object in C# code, it can store any value. Feature, not a bug.