我想在.net控件上调用 GetClientSite 。为此,我试图将控件(例如Windows.Forms.Form)转换为 IOleObject ,返回null。
我该怎么做才能获得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();
}
}
答案 0 :(得分: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."
。
答案 1 :(得分: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
由于
答案 2 :(得分:1)
Here is another method,使用Marshal.CreateAggregatedObject
访问私有COM接口。