Как привести элемент к IOleObject - PullRequest
2 голосов
/ 01 августа 2009

Я хочу вызвать GetClientSite для элемента управления .net. Для этого я пытаюсь привести элемент управления (например, Windows.Forms.Form) к IOleObject , который возвращает ноль.

Что я должен сделать, чтобы получить IOleObject?

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows.Forms;

namespace Test001
{
    public class Form001 : Form
    {
        public Form001()
        {
            InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.Name = "Form001";
            this.Text = "Form001";
            this.Load += new System.EventHandler(this.Form001_Load);
            this.ResumeLayout(false);
        }

        private void Form001_Load(object sender, EventArgs e)
        {
            IOleObject obj = (IOleObject) this;
            //IOleClientSite site = obj.GetClientSite();
        }
    }

    [ComImport, Guid("00000112-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), SuppressUnmanagedCodeSecurity]
    public interface IOleObject
    {
        [PreserveSig]
        int SetClientSite([In, MarshalAs(UnmanagedType.Interface)] IOleClientSite pClientSite);
        IOleClientSite GetClientSite();
        [PreserveSig]
        int SetHostNames([In, MarshalAs(UnmanagedType.LPWStr)] string szContainerApp, [In, MarshalAs(UnmanagedType.LPWStr)] string szContainerObj);
        [PreserveSig]
        int Close(int dwSaveOption);
        [PreserveSig]
        int SetMoniker([In, MarshalAs(UnmanagedType.U4)] int dwWhichMoniker, [In, MarshalAs(UnmanagedType.Interface)] object pmk);
        [PreserveSig]
        int GetMoniker([In, MarshalAs(UnmanagedType.U4)] int dwAssign, [In, MarshalAs(UnmanagedType.U4)] int dwWhichMoniker, [MarshalAs(UnmanagedType.Interface)] out object moniker);
        [PreserveSig]
        int InitFromData([In, MarshalAs(UnmanagedType.Interface)] IDataObject pDataObject, int fCreation, [In, MarshalAs(UnmanagedType.U4)] int dwReserved);
        [PreserveSig]
        int GetClipboardData([In, MarshalAs(UnmanagedType.U4)] int dwReserved, out IDataObject data);
        [PreserveSig]
        int DoVerb(int iVerb, [In] IntPtr lpmsg, [In, MarshalAs(UnmanagedType.Interface)] IOleClientSite pActiveSite, int lindex, IntPtr hwndParent, [In] object lprcPosRect);
        [PreserveSig]
        int EnumVerbs(out object e);
        [PreserveSig]
        int OleUpdate();
        [PreserveSig]
        int IsUpToDate();
        [PreserveSig]
        int GetUserClassID([In, Out] ref Guid pClsid);
        [PreserveSig]
        int GetUserType([In, MarshalAs(UnmanagedType.U4)] int dwFormOfType, [MarshalAs(UnmanagedType.LPWStr)] out string userType);
        [PreserveSig]
        int SetExtent([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, [In] object pSizel);
        [PreserveSig]
        int GetExtent([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, [Out] object pSizel);
        [PreserveSig]
        int Advise(object pAdvSink, out int cookie);
        [PreserveSig]
        int Unadvise([In, MarshalAs(UnmanagedType.U4)] int dwConnection);
        [PreserveSig]
        int EnumAdvise(out object e);
        [PreserveSig]
        int GetMiscStatus([In, MarshalAs(UnmanagedType.U4)] int dwAspect, out int misc);
        [PreserveSig]
        int SetColorScheme([In] object pLogpal);
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000118-0000-0000-C000-000000000046")]
    public interface IOleClientSite
    {
        [PreserveSig]
        int SaveObject();
        [PreserveSig]
        int GetMoniker([In, MarshalAs(UnmanagedType.U4)] int dwAssign, [In, MarshalAs(UnmanagedType.U4)] int dwWhichMoniker, [MarshalAs(UnmanagedType.Interface)] out object moniker);
        [PreserveSig]
        int GetContainer(out object container);
        [PreserveSig]
        int ShowObject();
        [PreserveSig]
        int OnShowWindow(int fShow);
        [PreserveSig]
        int RequestNewObjectLayout();
    }
}

Ответы [ 3 ]

4 голосов
/ 01 августа 2009

Интерфейс IOleObject является вложенным интерфейсом внутри внутреннего класса UnsafeNativeMethods в сборке System.Windows.Forms. System.Windows.Forms.Control реализует его внутри и явно .

Создание другого интерфейса с тем же именем и guid не сделает его «тем же интерфейсом» на управляемом уровне.

Эта строка

IOleObject obj = (IOleObject) this;

представляет управляемое приведение .net и не имеет ничего общего с COM. Это приведение будет работать только с точно таким же интерфейсом из сборки winforms, который не является общедоступным.

Вы можете попробовать использовать отражение через структуру InterfaceMapping , чтобы получить метод (но учтите, что это не рекомендуется):

Type thisType = this.GetType();

Type oleInterface = thisType.GetInterface("IOleObject");

MethodInfo getSiteMethod = oleInterface.GetMethod("GetClientSite");

//InterfaceMapping is used to get more complex interface scenarios
InterfaceMapping map = thisType.GetInterfaceMap(oleInterface);

//at which index is the explicit implementation
int index = Array.IndexOf(map.InterfaceMethods, getSiteMethod);
MethodInfo actualExplicitMethod = map.TargetMethods[index];

//late-bound call (slow)
object o = actualExplicitMethod.Invoke(this, new object[] { });

Теперь, во-первых, вы получаете внутренний тип, обернутый в System.Object, который не может быть приведен к вашему интерфейсу, так как исходный интерфейс является внутренним, так что вы получите больше удовольствия от отражения, если вы собираетесь использовать этот объект.

Во-вторых, я попробовал, техника работает, но в вашем конкретном сценарии этот метод, вызываемый в форме Windows, вызывает исключение - "Top-level Windows Forms control cannot be exposed as an ActiveX control.".

1 голос
/ 04 ноября 2013

Вот другой метод , использующий Marshal.CreateAggregatedObject для доступа к частным интерфейсам COM.

1 голос
/ 14 апреля 2011

Я использую этот метод:

IOleClientSite pClientSite = (IOleClientSite)Site.GetService(new AntiMoniker().GetType());

Определить, например, AntiMoniker. На данный момент детали не требуются. Просто получите экземпляр System .__ ComObject.

[ComImport(), Guid("00000305-0000-0000-C000-000000000046")]
class AntiMoniker {
}

Это будет работать на .NET Framework 2.0 / IE8 / WinXP SP3

Спасибо

...