Это устаревший продукт, интерфейс которого написан на 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 ++?