以下是我使用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);
}
答案 0 :(得分:1)
编辑:GetIDsOfNames中的dispid参数是一个调用者提供的数组,因此你不能使用[out](这意味着被调用者在COM堆上分配数组)。
很难说没有看到UnsafeNativeMethods.IDispatch
的声明,但是在没有固定dispid数组或在参数中添加ref的情况下调用GetIDsOfNames
是错误的。如果通过按值传递地址来封送数组,则垃圾收集器可以在GetIDsOfNames
调用仍在运行时移动数组,并且本机代码将在返回时写入野指针。如果将数组作为引用传递,则代码将无法编译 - 您需要在参数中添加ref。
您可以使用System.Type.InvokeMember
方法通过脚本对象访问全局变量或函数。此方法会为您调用IDispatch::GetIDsOfNames
和IDispatch::Invoke
。