Реализация IDispatch в C#
Я пишу некоторый тестовый код для эмуляции неуправляемого кода, вызывающего мою реализацию C# позднего связывания COM-объекта. У меня есть интерфейс, который объявлен как тип IDispatch, как показано ниже.
[Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface TestInterface
{
int Test();
}
[ClassInterface(ClassInterfaceType.AutoDual)]
public class TestImpl : TestInterface
{
...
}
Когда я использую код ниже для вызова IDispatch GetIDsOfNames
функция
..
//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;
Где IDispatch определяется как:
//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);
}
InvalidCastException выбрасывается. Можно ли привести интерфейс aC# в IDispatch?
2 ответа
Вам необходимо зарегистрировать сборку с помощью regasm, а также пометить классы, к которым вы хотите получить доступ из COM, с помощью атрибута [ComVisible]. Вам также может понадобиться сгенерировать и зарегистрировать библиотеку типов, используя tlbexp (для генерации) и tregsvr для ее регистрации.
Также (с точки зрения Win32) "disp = (IDispatch) obj" отличается от "disp = obj as IDispatch" - использование оператора "as" фактически вызывает метод QueryInterface для объекта, чтобы получить указатель на запрошенный интерфейс вместо того, чтобы пытаться привести объект к интерфейсу.
Наконец, использование "динамического" типа C# будет, вероятно, ближе к тому, что другие парни делают для доступа к вашему классу.
Вы должны просто иметь возможность использовать отражение в типе COM, чтобы получить список методов.
Type comType = Type.GetTypeFromProgID("ProgID.Test");
MethodInfo[] methods = comType.GetMethods();