iframe中元素的getElementById

我当前的代码适用于iframe之外的元素。 我应该如何使用getElementById在iframe中获取元素? 我的最终目标是在

...

标记内写入文本。 我没有使用webBrowser控件 – 这是针对iexplore的外部实例

HTML示例

在此处输入图像描述

代码示例

 foreach (InternetExplorer ie in new ShellWindowsClass()) { if (ie.LocationURL.ToString().IndexOf("intranet_site_url") != -1) { IWebBrowserApp wb = (IWebBrowserApp)ie; while (wb.Busy) { Thread.Sleep(100); } HTMLDocument document = ((HTMLDocument)wb.Document); // FETCH BY ID IHTMLElement element; HTMLInputElementClass hitem; element = document.getElementById("tinymce"); hitem = (HTMLInputElementClass)element; hitem.value = first_name; // FETCH BY ID in IFRAME IHTMLFramesCollection2 hframes = document.frames; for (int i = 0; i < hframes.length; i++) { object ref_index = i; IHTMLWindow2 currentFrame = (IHTMLWindow2)hframes.item(ref ref_index); if (currentFrame != null) { MessageBox.Show(currentFrame.name); // what to do from here? } else MessageBox.Show("Null"); } } } 

– 更新想法在下面调整我的想法的机会?

 if (currentFrame != null) { MessageBox.Show(currentFrame.name); HTMLDocument document_sub = ((HTMLDocument)currentFrame.document); IHTMLElement element_sub; HTMLInputElementClass hitem_sub; element_sub = (document_sub.getElementById("tinymce")); hitem_sub = (HTMLInputElementClass)element_sub; try { hitem_sub.value = first_name; // the above will produce... // InvalidCastException: Unable to cast COM object of type 'mshtml.HTMLBodyCLass' to class type 'mshtml.HTMLInputElementClass' } catch { } } 

试试这个:

 Windows.Forms.HtmlWindow frame = WebBrowser1.Document.GetElementById("decrpt_ifr").Document.Window.Frames["decrpt_ifr"]; HtmlElement body = frame.Document.GetElementById("tinymce"); body.InnerHtml = "Hello, World!"; 

获取框架并将其视为不同的文档(因为它是),然后它尝试从其id获取元素。 祝好运。

编辑:这应该利用dynamic数据类型和InternetExplorer接口:

 private void Form1_Load(object sender, EventArgs e) { foreach (InternetExplorer ie in new ShellWindows()) { if (ie.LocationURL.ToString().IndexOf("tinymce") != -1) { IWebBrowserApp wb = (IWebBrowserApp)ie; wb.Document.Frames.Item[0].document.body.InnerHtml = "

Hello, World at

" + DateTime.Now.ToString(); } } }

这个答案的灵感来自我最近使用eval将脚本注入到Internet Explorer的进程外实例中的一些研究 。

我们的想法是绕过MSHTML DOM互操作接口,并使用动态JavaScript来获取感兴趣的DOM对象。 有一些含义:

  • 在即将到来的IE11中不推荐使用execScript方法。
  • 非托管IDispatchEx :: InvokeEx必须用于访问HTML窗口对象内部的动态JavaScript对象(如果是进程内 WebBrowser控件,标准Type.Invoke , HtmlDocument.InvokeScript或动态调用工作就好了这个技术)。

要解决问题本身,使用下面说明的方法获取所需的body元素应该很容易

 var tinymceBody = DispExInvoker.Invoke(ie.Document.parentWindow, "eval", "document.getElementById('decrpt_ifr').contentWindow.document.getElementById('tinymce')"); 

这是一个在jsfiddle.net的子框架上下文中执行alert(document.URL)jsfiddle.net ,它通过自动执行InternetExplorer.Applicationjsfiddle.net外实例:

 private async void Form1_Load(object sender, EventArgs ev) { SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorer(); ie.Visible = true; var documentCompleteTcs = new TaskCompletionSource(); ie.DocumentComplete += delegate { if (documentCompleteTcs.Task.IsCompleted) return; documentCompleteTcs.SetResult(true); }; ie.Navigate("http://jsfiddle.net/"); await documentCompleteTcs.Task; // inject __execScript code into the top window var execScriptCode = "(window.__execScript = function(exp) { return eval(exp); }, window.self)"; var window = DispExInvoker.Invoke(ie.Document.parentWindow, "eval", execScriptCode); // inject __execScript into a child iframe var iframe = DispExInvoker.Invoke(window, "__execScript", String.Format("document.all.tags('iframe')[0].contentWindow.eval('{0}')", execScriptCode)); // invoke 'alert(document.URL)' in the context of the child frame DispExInvoker.Invoke(iframe, "__execScript", "alert(document.URL)"); } ///  /// Managed wrapper for calling IDispatchEx::Invoke /// https://stackoverflow.com/a/18349546/1768303 ///  public class DispExInvoker { // check is the object supports IsDispatchEx public static bool IsDispatchEx(object target) { return target is IDispatchEx; } // invoke a method on the target IDispatchEx object public static object Invoke(object target, string method, params object[] args) { var dispEx = target as IDispatchEx; if (dispEx == null) throw new InvalidComObjectException(); var dp = new System.Runtime.InteropServices.ComTypes.DISPPARAMS(); try { // repack arguments if (args.Length > 0) { // should be using stackalloc for DISPPARAMS arguments, but don't want enforce "/unsafe" int size = SIZE_OF_VARIANT * args.Length; dp.rgvarg = Marshal.AllocCoTaskMem(size); ZeroMemory(dp.rgvarg, size); // zero'ing is equal to VariantInit dp.cArgs = args.Length; for (var i = 0; i < dp.cArgs; i++) Marshal.GetNativeVariantForObject(args[i], dp.rgvarg + SIZE_OF_VARIANT * (args.Length - i - 1)); } int dispid; dispEx.GetDispID(method, fdexNameCaseSensitive, out dispid); var ei = new System.Runtime.InteropServices.ComTypes.EXCEPINFO(); var result = Type.Missing; dispEx.InvokeEx(dispid, 0, DISPATCH_METHOD, ref dp, ref result, ref ei, null); return result; } finally { if (dp.rgvarg != IntPtr.Zero) { for (var i = 0; i < dp.cArgs; i++) VariantClear(dp.rgvarg + SIZE_OF_VARIANT * i); Marshal.FreeCoTaskMem(dp.rgvarg); } } } // interop declarations [DllImport("oleaut32.dll", PreserveSig = false)] static extern void VariantClear(IntPtr pvarg); [DllImport("Kernel32.dll", EntryPoint = "RtlZeroMemory", SetLastError = false)] static extern void ZeroMemory(IntPtr dest, int size); const uint fdexNameCaseSensitive = 0x00000001; const ushort DISPATCH_METHOD = 1; const int SIZE_OF_VARIANT = 16; // IDispatchEx interface [ComImport()] [Guid("A6EF9860-C720-11D0-9337-00A0C90DCAA9")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IDispatchEx { // IDispatch int GetTypeInfoCount(); [return: MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.ITypeInfo GetTypeInfo([In, MarshalAs(UnmanagedType.U4)] int iTInfo, [In, MarshalAs(UnmanagedType.U4)] int lcid); void GetIDsOfNames([In] ref Guid riid, [In, MarshalAs(UnmanagedType.LPArray)] string[] rgszNames, [In, MarshalAs(UnmanagedType.U4)] int cNames, [In, MarshalAs(UnmanagedType.U4)] int lcid, [Out, MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); void Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); // IDispatchEx void GetDispID([MarshalAs(UnmanagedType.BStr)] string bstrName, uint grfdex, [Out] out int pid); void InvokeEx(int id, uint lcid, ushort wFlags, [In] ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pdp, [In, Out] ref object pvarRes, [In, Out] ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pei, System.IServiceProvider pspCaller); void DeleteMemberByName([MarshalAs(UnmanagedType.BStr)] string bstrName, uint grfdex); void DeleteMemberByDispID(int id); void GetMemberProperties(int id, uint grfdexFetch, [Out] out uint pgrfdex); void GetMemberName(int id, [Out, MarshalAs(UnmanagedType.BStr)] out string pbstrName); [PreserveSig] [return: MarshalAs(UnmanagedType.I4)] int GetNextDispID(uint grfdex, int id, [In, Out] ref int pid); void GetNameSpaceParent([Out, MarshalAs(UnmanagedType.IUnknown)] out object ppunk); } } 

另一种方法是获取该iframe的URL并将其加载到您的浏览器中。

对我来说,接受的解决方案是"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"错误。