2013-08-27 2 views
4

Мой текущий код работает с элементами вне iframe. Как мне подойти к набору элементов в iframe с помощью getElementById? Моя конечная цель - написать текст в тегах <body id="tinymce"><p>...</p></body>. Я не с помощью элемента управления WebBrowser - это для внешнего экземпляра IexploregetElementById для элемента внутри iframe

HTML Sample

enter image description here

Пример кода

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 { } 
} 
+0

Является ли подкадром в другом источнике, чем исходный документ? Если это так, вы не можете просто достичь и захватить его объект документа из-за того, как было реализовано ограничение SameOriginPolicy. Вместо этого вы должны захватить подкадр с помощью интерфейса IOleContainer ... – EricLaw

+0

Нет, то же самое происхождение - это точно, как это показано выше в примере html. Я никогда не видел TinyMCE, представленного в разметке таким образом, и это не имеет смысла для меня, но я должен работать с ним. –

+0

@PatrickAlexson, возможно, было бы проще ввести некоторый JavaScript, чтобы получить нужный элемент DOM, например [this] (http://pastebin.com/iM5829MM) (первоначально из [здесь] (http://stackoverflow.com/ вопросы/18342200/как-ду-я-колл-Eval-в-е-с-с /)). Вы должны иметь возможность сделать то же самое в C#, используя 'dynamic'. – Noseratio

ответ

2

Попробуйте это:

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

, который получает кадр и рассматривает его в качестве другого документа (потому что это), а затем он пытается получить элемент из его идентификатора. Удачи.

Edit: Это должно сделать трюк воспользовавшись из 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 = "<p>Hello, World at </p> " + DateTime.Now.ToString(); 
     } 
    } 
} 
+0

Спасибо за помощь @hanlet, это похоже только для управления веб-браузером, да? Я говорю, потому что в моем случае им говорить с внешним экземпляром iexplore.exe с помощью 'Еогеасп (InternetExplorer т.е. в новом ShellWindowsClass()) { \t если (ie.LocationURL.ToString(). IndexOf ("intranet_site_url")! = -1) \t { \t \t // код в исходном сообщении начинается здесь \t} } ' так что, если я правильно понимаю, мне нужно обработать разметку в IFRAME как новый документ. Могу ли я использовать что-то вроде обновления, которое я только что сделал на исходном сообщении? –

+0

@PatrickAlexson извините, меня не было. Я сейчас посмотрю на это. –

+0

@PatrickAlexson проверить мои изменения. Это работало на веб-сайте TinyMCE, я настаиваю, что он должен работать на вашем локальном сайте. Я буду любить этот вопрос, потому что это то, что может пригодиться в будущем;) –

4

Этот ответ был вдохновлен some research я недавно сделал на использовании eval впрыснуть скрипт в амбулаторном из-proc экземпляра Internet Explorer.

Идея состоит в том, чтобы обойти интерфейсы интерполяции MSHTML DOM и использовать динамический JavaScript для получения интересующего объекта DOM. Имеются некоторые последствия:

Для решения самого вопроса, он должен быть достаточно легким, чтобы получить желаемый body элемент, используя подход, показанный ниже:

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

Вот пример, который выполняет alert(document.URL) в контексте ребенок кадр jsfiddle.net, за счет автоматизации экземпляра вне прок от InternetExplorer.Application:

private async void Form1_Load(object sender, EventArgs ev) 
{ 
    SHDocVw.InternetExplorer ie = new SHDocVw.InternetExplorer(); 
    ie.Visible = true; 

    var documentCompleteTcs = new TaskCompletionSource<bool>(); 
    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)"); 
} 

/// <summary> 
/// Managed wrapper for calling IDispatchEx::Invoke 
/// https://stackoverflow.com/a/18349546/1768303 
/// </summary> 
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); 
    } 
} 
+1

http: // stackoverflow.com/questions/27566985/browser-execscript-stop-working-after-update-windows Вы сделали мужественное усилие, чтобы предоставить средства для доступа к «eval», к сожалению, однако, microsoft уничтожил практически любые внепроцессные средства для запустите * any * функцию (а не только «eval» или «execScript») под окном (объект IHTMLWindow [X]). Я буду более чем счастлив, если кто-то проведет некоторые тесты и докажет, что я ошибаюсь в этом заявлении (кто знает, что Microsoft может свернуть патч, чтобы как-то исправить эту ситуацию ...). – xDisruptor

0

Также можно было бы получить URL-адрес этого iframe и загрузить его в ваш браузер.

Для меня принятое решение дает "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" ошибка.

Смежные вопросы