2016-12-19 9 views
2

Я пытаюсь удалить строку Javascript из Dom IE 11 с помощью BHO. (Internet Explorer Add-ON)IE Исследуйте 11 <C++ ATL COM Browser Helper Object (Add-on), чтобы заменить текст в DOM

Это настолько плохо документировано, что трудно увидеть лучший путь вперед.

Ive удалось написать BHO в C++ ATL/COM, и он отлично работает, но я не могу найти лучший способ фактически удалить/заменить текст из тела, а затем внести изменения обратно на страницу.

И, честно говоря, у меня нет времени, чтобы прочитать эту 1000-страничную версию COM-книги :-).

Это то, что я в настоящее время для OnDocumentComplete события:

void STDMETHODCALLTYPE CMyFooBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL) 
{ 
    BSTR bstrURL = pvarURL->bstrVal; 

    if (_wcsicmp(bstrURL, ABOUT_BLANK) == 0) 
    { 
     return; 
    } 

    HRESULT hr = S_OK; 

    // Query for the IWebBrowser2 interface. 
    CComQIPtr<IWebBrowser2> spTempWebBrowser = pDisp; 

    // Is this event associated with the top-level browser? 
    if (spTempWebBrowser && m_spWebBrowser && m_spWebBrowser.IsEqualObject(spTempWebBrowser)) 
    { 
     // Get the current document object from browser. 
     CComPtr<IDispatch> spDispDoc; 
     hr = m_spWebBrowser->get_Document(&spDispDoc); 

     if (SUCCEEDED(hr)) 
     { 
      // Verify that what we get is a pointer to a IHTMLDocument2 interface. 
      // To be sure, let's query for the IHTMLDocument2 interface (through smart pointers). 

      CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTML; 
      spHTML = spDispDoc; 

      // Extract the source of the document if its HTML. 
      if (spHTML) 
      { 
       // Get the BODY object. 
       CComPtr<IHTMLElement> m_pBody; 
       hr = spHTML->get_body(&m_pBody); 

       if (SUCCEEDED(hr)) 
       { 
        // Get the HTML text. 
        BSTR bstrHTMLText; 
        hr = m_pBody->get_outerHTML(&bstrHTMLText); 

        if (SUCCEEDED(hr)) 
        { 
         // bstrHTMLText now contains the <body> ...whatever... </body> of the html page. 

         // ******** HERE ******** 

         // What I want to do here is replace some text contained in bstrHTMLText 
         // i.e. Replace "ABC" with "DEF" if it exists in bstrHTMLText. 

         // Then replace the body of the original page with the edited bstrHTMLText. 

         // My actual goal is to remove one line of javascript. 

        } 
       } 
      } 
     } 
    } 
} 

Не стесняйтесь комментировать любые улучшения уже существующего кода.

+0

Вы должны получить более глубокое 'IHTMLElement', содержащий то, что вы хотите изменить. Добавьте к своему вопросу узел HTML, который был захвачен Dom Explorer, из инструмента разработчика «F12». – manuell

+0

Элементом будет . Его все() я хочу удалить. –

+0

Вы имеете в виду привязную бирку? – manuell

ответ

1

Это оленья кожа следить за нормальным (должны делать) способ сделать это.

Если лучшие ответы не поступают, тогда я думаю, что это лучший ответ, и я буду отмечать его как таковую.

Я хотел бы услышать любые комментарии или обновления, чтобы улучшить или показать мне рабочий пример, который лучше.

Это для IE 11 и составлен с использованием C++ ATL/COM в Visual Studio 2015.

Я попытался итерируя DOM и изменяя ее, и о любых других очень плохо документированы вариациях.

Не существует проблемы с чтением html i.e. get_innerText get_innerHTML get_outerHTML в его различных формах, но put _ *** никогда не работает в основном. Зачем? никто, кажется, не может сказать и не дать мне рабочий пример.

Что я нашел, так это то, что get_body> get_innerHTML> put_innerHTML действительно работает.

Чтобы найти это, я просто написал функцию для поиска и замены внутри CComBSTR.

Это работает для меня, но я полагаю, вы могли бы взять то, что было возвращено в качестве внутреннего внутреннего HTML, и запустить на нем другой код манипуляции DOM (не встроенный материал), если ваши требования разные.

Главное преимущество этого способа делать вещи не зависит от c ** p недокументированного кода, который, похоже, работает в каком-то мистическом методе, когда MS хотела этого.


Это тестовая html-страница. Im пытается удалить «alert (« Hello »)», то есть , выполненный, когда страница заканчивает загрузку.

<!doctype html> 

    <head> 
    <title>Site</title> 

    <meta http-equiv="cache-control" content="max-age=0" /> 
    <meta http-equiv="cache-control" content="no-cache" /> 
    <meta http-equiv="expires" content="0" /> 
    <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" /> 
    <meta http-equiv="pragma" content="no-cache" /> 

    </head> 

    <body> 

    <div>If a dialog with hello appears then the BHO failed</div> 


    <script type="text/javascript"> 

     window.onload = function(){ 
     window.document.body.onload = foo; 
     }; 

     function foo() 
     { 
      alert("hello"); 
     } 

    </script> 

    </body> 
<html> 

// FooBHO.h : Declaration of the CFooBHO 

#pragma once 
#include "resource.h"  // main symbols 

#include "FooIEAddOn_i.h" 

#include <shlguid.h>  // IID_IWebBrowser2, DIID_DWebBrowserEvents2, etc. 

#include <exdispid.h>  // DISPID_DOCUMENTCOMPLETE, etc. 

#include <mshtml.h>   // DOM interfaces 

#include <string> 

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) 
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." 
#endif 

#define DISPID_DOCUMENTRELOAD 282 

using namespace ATL; 

using namespace std; 

// CFooBHO 
class ATL_NO_VTABLE CFooBHO : public CComObjectRootEx<CComSingleThreadModel>, 
             public CComCoClass<CFooBHO, &CLSID_FooBHO>, 
             public IObjectWithSiteImpl<CFooBHO>, 
             public IDispatchImpl<IFooBHO, &IID_IFooBHO, &LIBID_FooIEAddOnLib, /*wMajor =*/ 1, /*wMinor =*/ 0>, 
             public IDispEventImpl<1, CFooBHO, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1> 
{ 
    public: 

     CFooBHO() 
     { 
     } 

     // The STDMETHOD macro is an ATL convention that marks the method as virtual and ensures that it has the right calling convention for the public 
     // COM interface.It helps to demarcate COM interfaces from other public methods that may exist on the class.The STDMETHODIMP macro is likewise used 
     // when implementing the member method. 

     STDMETHOD(SetSite)(IUnknown *pUnkSite); 

     DECLARE_REGISTRY_RESOURCEID(IDR_FooBHO) 

     DECLARE_NOT_AGGREGATABLE(CFooBHO) 

     BEGIN_COM_MAP(CFooBHO) 
      COM_INTERFACE_ENTRY(IFooBHO) 
      COM_INTERFACE_ENTRY(IDispatch) 
      COM_INTERFACE_ENTRY(IObjectWithSite) 
     END_COM_MAP() 

     DECLARE_PROTECT_FINAL_CONSTRUCT() 

     BEGIN_SINK_MAP(CFooBHO) 
      SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete) 
     END_SINK_MAP() 

     void STDMETHODCALLTYPE OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL); 

     HRESULT FinalConstruct() 
     { 
      return S_OK; 
     } 

     void FinalRelease() 
     { 
     } 

    private: 

     CComPtr<IWebBrowser2> m_spWebBrowser; 

     BOOL m_fAdvised; 

     static const wchar_t* ABOUT_BLANK; 

     void CFooBHO::ReplaceInCComBSTR(CComBSTR &strInput, const wstring &strOld, const wstring &strNew); 
}; 

OBJECT_ENTRY_AUTO(__uuidof(FooBHO), CFooBHO) 

// FooBHO.cpp : Implementation of CFooBHO 

#include "stdafx.h" 
#include "FooBHO.h" 
#include "Strsafe.h" 

const wchar_t* CFooBHO::ABOUT_BLANK = L"about:blank"; 

// The SetSite() method is where the BHO is initialized and where you would perform all the tasks that happen only 
// once. When you navigate to a URL with Internet Explorer, you should wait for a couple of events to make sure the 
// required document has been completely downloaded and then initialized. Only at this point can you safely access 
// its content through the exposed object model, if any. 

STDMETHODIMP CFooBHO::SetSite(IUnknown* pUnkSite) 
{ 
    if (pUnkSite != NULL) 
    { 
     // Cache the pointer to IWebBrowser2. 
     HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser); 

     if (SUCCEEDED(hr)) 
     { 
      // Register to sink events from DWebBrowserEvents2. 
      hr = DispEventAdvise(m_spWebBrowser); 
      if (SUCCEEDED(hr)) 
      { 
       m_fAdvised = TRUE; 
      } 
     } 
    } 
    else 
    { 
     // Unregister event sink. 
     if (m_fAdvised) 
     { 
      DispEventUnadvise(m_spWebBrowser); 
      m_fAdvised = FALSE; 
     } 

     // Release cached pointers and other resources here. 
     m_spWebBrowser.Release(); 
    } 

    // Call base class implementation. 
    return IObjectWithSiteImpl<CFooBHO>::SetSite(pUnkSite); 
} 

void STDMETHODCALLTYPE CFooBHO::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL) 
{ 
    BSTR bstrURL = pvarURL->bstrVal; 

    // Test for any specific URL here. 
    // Currently we are ignoring ABOUT:BLANK but allowing everything else. 

    if (_wcsicmp(bstrURL, ABOUT_BLANK) == 0) 
    { 
     return; 
    } 

    HRESULT hr = S_OK; 

    // Query for the IWebBrowser2 interface. 
    CComQIPtr<IWebBrowser2> spTempWebBrowser = pDisp; 

    // Is this event associated with the top-level browser? 
    if (spTempWebBrowser && m_spWebBrowser && m_spWebBrowser.IsEqualObject(spTempWebBrowser)) 
    { 
     // Get the current document object from browser. 
     CComPtr<IDispatch> spDispDoc; 

     if (SUCCEEDED(m_spWebBrowser->get_Document(&spDispDoc))) 
     { 
      // Verify that what we get is a pointer to a IHTMLDocument2 interface. 
      // To be sure, let's query for the IHTMLDocument2 interface (through smart pointers). 

      CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTMLDocument2 = spDispDoc; 

      // Extract the source of the document if its HTML. 
      if (spHTMLDocument2) 
      { 
       // Get the BODY object. 
       CComPtr<IHTMLElement> spBody; 

       if (SUCCEEDED(spHTMLDocument2->get_body(&spBody))) 
       { 
        // Get the Body HTML text. 
        CComBSTR bstrBodyHTMLText; 

        if (SUCCEEDED(spBody->get_innerHTML(&bstrBodyHTMLText))) 
        { 
         ReplaceInCComBSTR(bstrBodyHTMLText, L"alert(\"hello\");", L""); 

         spBody->put_innerHTML(bstrBodyHTMLText); 
        } 
       } 
      } 
     } 
    } 
} 

void CFooBHO::ReplaceInCComBSTR(CComBSTR &bstrInput, const wstring &strOld, const wstring &strNew) 
{ 
    wstring strOutput(bstrInput); 

    size_t iPos = 0; 
    size_t iLpos = 0; 

    while ((iPos = strOutput.find(strOld, iLpos)) != string::npos) 
    { 
     strOutput.replace(iPos, strOld.length(), strNew); 
     iLpos = iPos + 1; 
    } 

    ::SysFreeString(bstrInput.m_str); 

    // Find and replace is complete; now update the CComBSTR. 
    bstrInput.m_str = ::SysAllocString(strOutput.c_str()); 
} 
0

Вот еще один способ сделать это в JavaScript.

var oCollection = document.getElementsByTagName("script"); 
var nColCount = oCollection.length; 
var nIndex; 
for (nIndex = 0; nIndex < nColCount; ++nIndex) { 
    var oScript = oCollection[ nIndex ]; 
    var strScriptText = oScript.innerHTML; 
    if (strScriptText.indexOf("alert(\"hello\");") != -1) { 
     var strNewText = strScriptText.replace("alert(\"hello\");", ""); 
     var oNewScript = document.createElement("script"); 
     oNewScript.type = "text\/javascript"; 
     oNewScript.text = strNewText; 
     document.getElementsByTagName("head")[0].appendChild(oNewScript); 
     console.log ("DONE!"); 
    } 
} 

Вы можете выполнить, что JS с IHTMLWindow2::execScript

Вы должны хранить код, указанный выше в CComBSTR. Остерегайтесь побега.

Пример:

CComBSTR bstrScript = L"var strWithOneDoubleQuote = \"\\\"\";"; // -:) 
+0

Плохо попробуйте. Новые API, похоже, применимы только к EDGE + из того, что я могу собрать. –

+0

'ITHMLWindow2 :: execScript' отлично работает в IE11. Если вы знаете, как это сделать в JS, вы можете использовать свой BHO, чтобы просто выполнить свой JS-код. – manuell

+0

У меня есть «Mostly got this to work, но Im stuggling, чтобы найти правильный метод для изменения dom. –