How to cast a control to IOleObject
我想在.net控件上调用GetClientSite。为此,我试图将控件(例如Windows.Forms.Form)转换为返回null的IOleObject。
如何获取IOleObject?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 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(); } } |
创建另一个具有相同名称和guid的界面不会使其在托管级别上成为"相同的界面"。
此行
1 | IOleObject obj = (IOleObject) this; |
表示托管的.net强制转换,与COM无关。此强制转换只能与winforms程序集中完全相同的接口一起使用,该接口是不公开的。
您可以尝试通过InterfaceMapping结构使用反射来获取方法(但请注意,这是不推荐的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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[] { }); |
现在,首先,您获得一个package在
第二,我已经尝试过了,该技术有效,但是在您的特定情况下,在Windows窗体上调用的此方法会引发异常-
这是另一种使用
我正在使用此方法:
1 | IOleClientSite pClientSite = (IOleClientSite)Site.GetService(new AntiMoniker().GetType()); |
例如,
定义
1 2 3 | [ComImport(), Guid("00000305-0000-0000-C000-000000000046")] class AntiMoniker { } |
它将在.NET Framework 2.0 / IE8 / WinXP SP3上运行
谢谢