2009-08-01 97 views
2

我想在.net控件上调用GetClientSite。为此,我试图将一个控件(在示例Windows.Forms.Form中)转换为IOleObject,它返回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

IOleObject接口处于System.Windows.Forms组件内部UnsafeNativeMethods类的内部的嵌套接口。 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不能是因为原始界面是内部的,因此只要打算使用该对象,就可以使用反射获得更多乐趣。

其次,我已经尝试过,该技术可行,但在您的特定情况下,此窗口窗体上调用的方法会引发异常 - "Top-level Windows Forms control cannot be exposed as an ActiveX control."

+0

感谢您的进一步信息,但这并没有帮助我一个可能的解决方案。实际上,在运行时获得内部接口有一个简单的方法,但这也无济于事。 \t this.GetType()。GetInterface(“IOleObject”); 可能有些事情需要处理QueryInterface。 – dereli 2009-08-01 18:18:14

1

我用这个方法:

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

定义AntiMoniker例如。目前,细节并不是必需的。只需获取System .__ ComObject的一个实例。

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

它会在.NET框架的工作2.0/IE8/WinXP的SP3

感谢