0

ILSpyを使用して取得したコードは次のとおりです。

public static object InvokeScript(this IHTMLDocument2 document, string scriptName, object[] args = null)
{
    object result = null;
    UnsafeNativeMethods.tagDISPPARAMS tagDISPPARAMS = new UnsafeNativeMethods.tagDISPPARAMS();
    tagDISPPARAMS.rgvarg = IntPtr.Zero;
    try
    {
        UnsafeNativeMethods.IDispatch dispatch = ((IHTMLDocument)document).Script as UnsafeNativeMethods.IDispatch;
        if (dispatch != null)
        {
            Guid empty = Guid.Empty;
            string[] rgszNames = new string[]
            {
                scriptName
            };
            int[] array = new int[]
            {
                -1
            };
            int iDsOfNames = dispatch.GetIDsOfNames(ref empty, rgszNames, 1, UnsafeNativeMethods.GetThreadLCID(), array);
            if (UnsafeNativeMethods.Succeeded(iDsOfNames) && array[0] != -1)
            {
                if (args != null)
                {
                    Array.Reverse(args);
                }
                tagDISPPARAMS.rgvarg = ((args == null) ? IntPtr.Zero : ArrayToVARIANTVector(args));
                tagDISPPARAMS.cArgs = ((args == null) ? 0 : args.Length);
                tagDISPPARAMS.rgdispidNamedArgs = IntPtr.Zero;
                tagDISPPARAMS.cNamedArgs = 0;
                object[] array2 = new object[1];
                if (dispatch.Invoke(array[0], ref empty, UnsafeNativeMethods.GetThreadLCID(), 1, tagDISPPARAMS, array2, new UnsafeNativeMethods.tagEXCEPINFO(), null) == 0)
                {
                    result = array2[0];
                }
            }
        }
    }
    catch (Exception ex)
    {
        if (IsSecurityOrCriticalException(ex))
        {
            throw;
        }
    }
    finally
    {
        if (tagDISPPARAMS.rgvarg != IntPtr.Zero)
        {
            FreeVARIANTVector(tagDISPPARAMS.rgvarg, args.Length);
        }
    }
    return result;
}

このメソッドから呼び出されている他のメソッドもいくつか取得しました。これが私がそれを呼ぶ方法です(注は拡張メソッドです):

var doc = Browser.Document.DomDocument as IHTMLDocument2;
doc.InvokeScript("alert", new object[] { "hi" });

しかし、行int iDsOfNames = dispatch.GetIDsOfNames(ref empty, rgszNames, 1, UnsafeNativeMethods.GetThreadLCID(), array);はをスローしAccessViolationExceptionます。よくわからないのはUnsafeNativeMethods.IDispatch dispatch = ((IHTMLDocument)document).Script as UnsafeNativeMethods.IDispatch;線です。実際のILSpyラインはですUnsafeNativeMethods.IDispatch dispatch = this.NativeHtmlDocument2.GetScript() as UnsafeNativeMethods.IDispatch;が、何らかの理由で私にはメソッドがありませんGetScript

私が間違っていることは何ですか?

編集

これが私のIDispatchです:

    [Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), SuppressUnmanagedCodeSecurity]
    [ComImport]
    internal interface IDispatch
    {
        [SecurityCritical]
        void GetTypeInfoCount(out uint pctinfo);
        [SecurityCritical]
        void GetTypeInfo(uint iTInfo, int lcid, out IntPtr info);
        [SecurityCritical]
        void GetIDsOfNames(ref Guid iid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)] string[] names, uint cNames, int lcid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4, SizeParamIndex = 2)] [Out] int[] rgDispId);
        [PreserveSig]
        int GetIDsOfNames([In] ref Guid riid, [MarshalAs(UnmanagedType.LPArray)] [In] string[] rgszNames, [MarshalAs(UnmanagedType.U4)] [In] int cNames, [MarshalAs(UnmanagedType.U4)] [In] int lcid, [MarshalAs(UnmanagedType.LPArray)] [Out] int[] rgDispId);
        [SecurityCritical]
        void Invoke(int dispIdMember, ref Guid riid, int lcid, System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, IntPtr pvarResult, IntPtr pExcepInfo, IntPtr puArgErr);
        [PreserveSig]
        int Invoke(int dispIdMember, [In] ref Guid riid, [MarshalAs(UnmanagedType.U4)] [In] int lcid, [MarshalAs(UnmanagedType.U4)] [In] int dwFlags, [In] [Out] tagDISPPARAMS pDispParams, [MarshalAs(UnmanagedType.LPArray)] [Out] object[] pVarResult, [In] [Out] tagEXCEPINFO pExcepInfo, [MarshalAs(UnmanagedType.LPArray)] [Out] IntPtr[] pArgErr);
    }
4

1 に答える 1

1

編集:GetIDsOfNamesのdispidパラメーターは呼び出し元が提供する配列であるため、[out]を使用することはできません(呼び出し先がCOMヒープに配列を割り当てることを意味します)。

の宣言を見ずに判断するのは難しいですが、dispid配列を固定したり、パラメーターにrefを追加したりせずにUnsafeNativeMethods.IDispatch呼び出すのは間違っています。GetIDsOfNamesアドレスを値で渡すことによって配列をマーシャリングした場合、ガベージコレクターは、GetIDsOfNames呼び出しがまだ実行されている間に配列を移動でき、ネイティブコードは戻り時にワイルドポインターに書き込みます。配列を参照として渡すと、コードはコンパイルされません。パラメーターにrefを追加する必要があります。

メソッドを使用System.Type.InvokeMemberして、スクリプトオブジェクトを介してグローバル変数または関数にアクセスできます。IDispatch::GetIDsOfNamesこのメソッドはとを呼び出しIDispatch::Invokeます。

于 2012-08-12T18:30:23.393 に答える