IHTMLDocument2-> documentElement-> outerHTML слишком медленно воссоздает HTML из DOM, есть ли более быстрый способ? - PullRequest
1 голос
/ 28 октября 2009

У меня есть плагин IE BHO, который отправляет через COM-вызов HTML-код страницы, которая была загружена в окне.

// Note all error handling removed for readability :)
STDMETHODIMP CPlugin::get_HTML(long lMaxSize, BSTR *pbstrHTML)
{
    CComPtr<IDispatch> pDispatch;
    MSHTML::IHTMLDocument2Ptr pDocument2 = NULL;
    MSHTML::IHTMLDocument3Ptr pDocument3 = NULL;
    hr = m_spWebBrowser->get_Document(&pDispatch);
    hr = pDispatch->QueryInterface(IID_IHTMLDocument3, (void**)&pDocument3);
    MSHTML::IHTMLElementPtr pRoot = pDocument3->documentElement;
    wstring strHTML = pRoot->outerHTML;
    CComBSTR bstrHTML = strOutput.c_str();
    bstrHTML.CopyTo(pbstrHTML);
}

Однако, когда он встречает очень большую страницу (например, "http://sitemap.zillow.com/uncompressed/ForSale_Hood_MedPri_1.xml"),, создание HTML из DOM занимает 3 минуты.

Есть ли способ получить доступ к необработанному HTML / XML?

Когда вы делаете «просмотр источника страницы» в IE, он появляется почти сразу, поэтому внутренне IE должен использовать какой-то API, который может делать то, что я хочу.

Спасибо
Шейн.

Ответы [ 3 ]

2 голосов
/ 04 ноября 2009

Кажется, что в старых версиях MSHTML externalHTML имел производительность O (n ^ 2). Однако в более новых версиях (IE8) эта проблема исчезла. Если у вас есть выбор, используйте IE8 или новее.

В противном случае использование IPersistStream :: Save является опцией. Но CreateStreamOnHGlobal не поможет вам, так как его реализация также O (n ^ 2). Для этого вам придется использовать собственный IStream.

Включена реализация IStream, которая была создана для этой цели и поддерживает быструю запись:

#include <atlbase.h>
#include <atlcom.h>
#include <vector>

// an implementation of a write-only IStream.
// needed because the CreateStreamOnHGlobal implementation doesn't handle
// resizes well (N writes seem to take O(N^2) time)
class MyStream :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<MyStream>,
    public IStreamImpl 
{
public: 

    std::vector<char> buf;

BEGIN_COM_MAP(MyStream)
    COM_INTERFACE_ENTRY(IStream)
END_COM_MAP()

    STDMETHOD(Write) (const void * pv, ULONG cb, ULONG *pcbWritten);
};
/*

Usage:

    CComPtr<IStream> stream;
    hr = MyStream::CreateInstance(&stream);
    // streamObj will be valid as long as IStream smart pointer lives
    MyStream *streamObj = (MyStream*)stream.p;
 */


STDMETHODIMP MyStream::Write(const void * pv, ULONG cb, ULONG *pcbWritten) 
{
    buf.insert(buf.end(), (char*)pv, (char*)pv+cb);
    return S_OK;
}
1 голос
/ 28 октября 2009

Да, вы можете QI для IPersistStream и сохранить в поток памяти, созданный CreateStreamOnHGlobal Обратите внимание, что документ должен быть загружен (состояние готовности должно быть завершено).

0 голосов
/ 14 ноября 2009

Спасибо, Амнон, следующий код в основном работает для меня.

// an implementation of a write-only IStream.
// needed because the CreateStreamOnHGlobal implementation doesn't handle
// resizes well (N writes seem to take O(N^2) time)
class MyStream :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<MyStream>,
    public IStream
{
public: 

    std::vector<char> buf;

BEGIN_COM_MAP(MyStream)
    COM_INTERFACE_ENTRY(IStream)
END_COM_MAP()

    STDMETHOD(Write) (const void * pv, ULONG cb, ULONG *pcbWritten);

    // Implement IStream abstract functions
    STDMETHOD(Read) (void *pv, ULONG cb, ULONG *pcbRead) { return S_OK; };
    STDMETHOD(Seek) (LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition) { return S_OK; };
    STDMETHOD(SetSize) (ULARGE_INTEGER libNewSize) { return S_OK; };
    STDMETHOD(CopyTo) (IStream *pstm,ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead,ULARGE_INTEGER *pcbWritten) { return S_OK; };
    STDMETHOD(Commit) (DWORD grfCommitFlags) { return S_OK; };
    STDMETHOD(Revert) () { return S_OK; };
    STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return S_OK; };
    STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return S_OK; };
    STDMETHOD(Stat) (__RPC__out STATSTG *pstatstg,DWORD grfStatFlag) { return S_OK; };
    STDMETHOD(Clone) (__RPC__deref_out_opt IStream **ppstm) { return S_OK; };
};

STDMETHODIMP MyStream::Write(const void * pv, ULONG cb, ULONG *pcbWritten) 
{
    buf.insert(buf.end(), (char*)pv, (char*)pv+cb);
    return S_OK;
}

// Retrieves the HTML of the current page
STDMETHODIMP CPlugin::get_HTML(long lMaxSize, BSTR *pbstrHTML)
{
    HRESULT hr = S_OK;
    try
    {
        CComPtr<IDispatch> pDispatch;
        MSHTML::IHTMLDocumentPtr pDocument = NULL;

        CComPtr<IStream> mystream;
        hr = MyStream::CreateInstance(&mystream);
        // streamObj will be valid as long as IStream smart pointer lives
        MyStream *streamObj = (MyStream*)mystream.p;

        hr = m_spWebBrowser->get_Document(&pDispatch);

        hr = pDispatch->QueryInterface(IID_IHTMLDocument, (void**)&pDocument);
        IPersistStreamInitPtr persistStream = pDocument;

        hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
        hr = persistStream->Save(mystream, FALSE);
    }
    catch(...)
    {
        TRACE_FN("Got exception somewhere");
    }
    return hr;
}

Теперь осталась только одна проблема - как понять, почему некоторые из них возвращают мне однобайтовые символы в большинстве случаев, а двухбайтовые - в другие. Есть идеи?

Спасибо за помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...