Implementing IDispatch in c#

2019-04-08 08:20发布

问题:

I'm writing some test code to emulate unmanaged code calling my c# implementation of a late binding COM object. I have an interface that is declared as an IDispatch type as below.

 [Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
 [InterfaceType(ComInterfaceType.InterfaceIsDual)]
 public interface TestInterface
 {
     int Test();
 }

 [ClassInterface(ClassInterfaceType.AutoDual)]
 public class TestImpl : TestInterface 
 {
 ...
 }

When I use the code below to call IDispatch's GetIDsOfNames function

  ..
  //code provided by Hans Passant
  Object so = Activator.CreateInstance(Type.GetTypeFromProgID("ProgID.Test"));
  string[] rgsNames = new string[1];
  int[] rgDispId = new int[1];
  rgsNames[0] = "Test";

  //the next line throws an exception
  IDispatch disp = (IDispatch)so;

Where IDispatch is defined as:

 //code provided by Hans Passant
 [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")]
 private interface IDispatch {
     int GetTypeInfoCount();
     [return: MarshalAs(UnmanagedType.Interface)]
     ITypeInfo GetTypeInfo([In, MarshalAs(UnmanagedType.U4)] int iTInfo, [In, MarshalAs(UnmanagedType.U4)] int lcid);
     void GetIDsOfNames([In] ref Guid riid, [In, MarshalAs(UnmanagedType.LPArray)] string[] rgszNames, [In, MarshalAs(UnmanagedType.U4)] int cNames, [In, MarshalAs(UnmanagedType.U4)] int lcid, [Out, MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
  }

An InvalidCastException is thrown. Is it possible to cast a c# interface into IDispatch?

回答1:

You need to register you assembly with regasm, and you need to mark the classes you want to access from COM with the [ComVisible] attribute. You may also need to generate and register a type-library using tlbexp (to generate) and tregsvr to register it.

Also (from a Win32 perspective) "disp = (IDispatch) obj" is not the same as "disp = obj as IDispatch" - using the 'as' operator actually calls the QueryInterface method on the object to get the pointer to the requested interface, instead of trying to cast an object to to the interface.

Lastly using c#'s 'dynamic' type will probably be closer to what the other guys are doing to access your class.



回答2:

You should just be able to use reflection on the COM type to get the list of methods.

Type comType = Type.GetTypeFromProgID("ProgID.Test");
MethodInfo[] methods = comType.GetMethods();


标签: c# com idispatch