2

我想在 .net 控件上调用GetClientSite 。为此,我试图将一个控件(例如 Windows.Forms.Form)强制转换为返回 null的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();
    }
}
4

3 回答 3

4

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."

于 2009-08-01T15:41:41.007 回答
1

我正在使用这种方法:

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

谢谢

于 2011-04-14T02:35:25.833 回答
1

这是另一种方法Marshal.CreateAggregatedObject用于访问私有 COM 接口。

于 2013-11-03T20:51:31.260 回答