Как привести COM-объекты разных типов к одному классу или интерфейсу? - PullRequest
0 голосов
/ 20 февраля 2020

Это устаревший продукт, интерфейс которого написан на c ++, а его ядро ​​- на VB и доступно как com-объекты. Они хотят, чтобы мы переписали интерфейс в c# и оставили ядро ​​без изменений. Сейчас я работаю над частью, которая использует объекты, реализованные в VB. Эти объекты на самом деле представляют собой набор различных классов с одинаковыми именами и объявлениями, которые реализованы в разных библиотеках, например:

'first dll
<Microsoft.VisualBasic.ComClass(), System.Runtime.InteropServices.ProgId("CoreA.clsFoo")> 
Public Class clsFoo
    Public Function DoSomething() As Byte
        'do something
    End Function
End Class

...

'second dll
<Microsoft.VisualBasic.ComClass(), System.Runtime.InteropServices.ProgId("CoreB.clsFoo")> 
Public Class clsFoo
    Public Function DoSomething() As Byte
        'do something
    End Function
End Class

Теперь, на стороне c ++, на основе опции, будет создан один из этих классов и хранится в переменной типа CoreA.clsFoo!

HRESULT hresult;
CLSID clsid;
CoreA::clsFoo* ptrFoo;

if (someCondition)
{
    hresult=CLSIDFromProgID(OLESTR("CoreA.clsFoo"),&clsid);
    hresult=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(CoreA::clsFoo),(LPVOID *) &ptrFoo);
}
else
{
    hresult=CLSIDFromProgID(OLESTR("CoreB.clsFoo"),&clsid);
    hresult=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(CoreB::clsFoo),(LPVOID *) &ptrFoo);
}
if( FAILED(hresult) ) 
{
    _com_issue_error(hresult);
}

Теперь у меня проблема с переводом этого фрагмента кода в c#, где все мои попытки приводят к какому-то неправильному приведению типа.

Что я сделал до сих пор
Сначала я добавил ссылки на обе библиотеки и создал экземпляр различных классов. Но только когда я попытался привести CoreB.clsFoo к тому же CoreA.clsFoo, я понял, что это совершенно не связанные классы (да, тупой я ...). Затем я попытался перевести приведенный выше код C ++, который стал примерно таким:

[DllImport("ole32.dll")]
static extern int CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] string lpszProgID, out Guid pclsid);
[DllImport("ole32.Dll")]
static public extern uint CoCreateInstance(ref Guid clsid,
   [MarshalAs(UnmanagedType.IUnknown)] object inner,
   uint context,
   ref Guid uuid,
   [MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject);
static readonly uint CLSCTX_INPROC_SERVER = 1;

private readonly object foo;

internal CoreA.clsFoo GetFoo()
{
    return (CoreA.clsFoo)this.foo;
}

internal CreateFoo(bool someCondition)
{
    if (someCondition)
    {
        int hresult = CLSIDFromProgID("CoreA.clsFoo", out Guid clsid);
        Guid uuid = typeof(CoreA.clsFoo._clsFoo).GUID;
        uint hresult2 = CoCreateInstance(ref clsid, null, CLSCTX_INPROC_SERVER, ref uuid, out foo);
    }
    else
    {
        int hresult = CLSIDFromProgID("CoreB. clsFoo", out Guid clsid);
        Guid uuid = typeof(CoreB.clsFoo._clsFoo).GUID;
        uint hresult2 = CoCreateInstance(ref clsid, null, CLSCTX_INPROC_SERVER, ref uuid, out foo);
    }
}

Но этот также получает недопустимое исключение приведения, на этот раз от __ComObject до CoreA.clsFoo.

* 1021. * Правильный способ справиться с этим
Я думаю, что лучший способ исправить это - изменить объявление этих классов в VB. Но по некоторым причинам они хотят, чтобы мы использовали те же самые сборки VB DLL, что и предыдущий продукт. Другой вариант - написать новый класс в c# с тем же набором функций, что и CoreX.clsFoo s, и вызвать метод c для различных экземпляров объектов, основанный на someCondition. Но я действительно стараюсь избегать этого, поскольку существует несколько десятков таких библиотек, а упомянутый выше метод DoSomthing() фактически представляет 2.305e93 различных методов!

Итак, есть ли способ выполнить какое-то наивное наведение типов в * 1035? * так же, как то, что делается в C ++?

...