Народ, в MSDN черным по белому написано: COM callable wrapper всегда эмулирует интерфейсы IDispatch, IUnknown и еще несколько, типа ITypeInfo. Создаю в сборке экземпляр UserControl, из клиентского Win32-приложения получаю его через такой интерфейс:
Но потом, уже в Win32, результат почему-то не приводится к IDispatch (дает ошибку Ole error: "The specified cast is not valid"), та же фигня и с ITypeInfo. Притом, что сам метод GetOleControl завершается нормально.
Кто виноват и что делать?
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
The following code fragment demonstrates how to declare in managed source code an unmanaged interface implemented by a COM component. The System.Runtime.InteropServices.ComImportAttribute prevents the IMyStorage interface from being exported back for use by COM. (COM clients should use the existing COM component directly.) In this example, MarshalAsAttribute specifies serveral UnmanagedType members, which represent the types used by the original COM interface.
using System;
using System.Runtime.InteropServices;
namespace MyModule
{
// If you do not have a type library for an interface
// you can redeclare it using ComImportAttribute.
// This is how the interface would look in an idl file.
//[
//object,
//uuid("73EB4AF8-BE9C-4b49-B3A4-24F4FF657B26"),
//dual, helpstring("IMyStorage Interface"),
//pointer_default(unique)
//]
//interface IMyStorage : IDispatch
//{
// [id(1)]
// HRESULT GetItem([in] BSTR bstrName, [out, retval] IDispatch ** ppItem);
// [id(2)]
// HRESULT GetItems([in] BSTR bstrLocation, [out] SAFEARRAY(VARIANT)* pItems);
// [id(3)]
// HRESULT GetItemDescriptions([in] BSTR bstrLocation, [out] SAFEARRAY(VARIANT) ** ppItems);
// [id(4), propget]
// HRESULT get_IsEmpty([out, retval] BOOL * pfEmpty);
//};
// This is the managed declaration.
[ComImport]
[Guid("73EB4AF8-BE9C-4b49-B3A4-24F4FF657B26")]
public interface IMyStorage
{
[DispId(1)]
[return : MarshalAs( UnmanagedType.Interface )]
Object GetItem( [In, MarshalAs( UnmanagedType.BStr )] String bstrName );
[DispId(2)]
void GetItems( [In, MarshalAs( UnmanagedType.BStr )] String bstrLocation,
[Out, MarshalAs( UnmanagedType.SafeArray,
SafeArraySubType = VarEnum.VT_VARIANT )] out Object[] Items );
[DispId(3)]
void GetItemDescriptions( [In] String bstrLocation,
[In, Out, MarshalAs( UnmanagedType.SafeArray )] ref Object[] varDescriptions );
bool IsEmpty
{
[DispId(4)]
[return : MarshalAs( UnmanagedType.VariantBool )]
get;
}
}
}
Моя задача в том, чтобы передать наружу в виде какого-либо интерфейса объект, но так, чтобы он обязательно поддерживал IDispatch. Мне не нужно, чтобы IXView реализовывал IDispatch. Мне нужно, чтобы метод IXView передал наружу UserControl в виде к-либо интерфейса, но так, чтобы этот интерфейс можно было привести к IDispatch.
DШ>вдогонку DШ>смотри InterfaceType, в частности DШ>[InterfaceType(ComInterfaceType.InterfaceIsDual)]
Опять-таки, на какой интерфейс мне наклеить этот атрибут? Если я возвращаю object... Кстати, я уже пробовал и возвращать какой-то другой интерфейс, ставить на него дуальность — и все равно приведение не работает! Этого я уже вообще не понимаю:
[c#]
[ComVisible(true)]
[Guid("4542FE0B-AA92-4D62-9167-E36B07922E94")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IXFrame
{
}
.....
public IXFrame GetOleControl() //потом возвращаемый результат в Win32 привожу к IDispatch, облом
{
return (IXFrame)m_frame;
}
[c#]
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM> public IXFrame GetOleControl() //потом возвращаемый результат в Win32 привожу к IDispatch, облом SM> { SM> return (IXFrame)m_frame; SM> }
m_frame — наследник от UserControl — если да, то все должно работать, ибо
[ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch)]
public class UserControl : ContainerControl
у самого метода как я понимаю нужно выставить
[DispId(1)][return : MarshalAs( UnmanagedType.Interface )]...
хотя, не нужно было маршаллить .net windows forms controls наружу, не сталкивался