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 に答える