2009-10-27 4 views
1

윈도우에서로드 된 페이지의 HTML을 COM 호출을 통해 전송하는 IE BHO 플러그인이 있습니다. 그것은 매우 큰 페이지 (예를 들면 「http://sitemap.zillow.com/uncompressed/ForSale_Hood_MedPri_1.xml」)을 발견하지만IHTMLDocument2-> documentElement-> outerHTML이 DOM에서 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); 
} 

는, 상기 DOM에서 HTML을 생성 3 분.

원시 HTML/XML에 액세스 할 수있는 방법이 있습니까?

IE에서 '페이지 소스보기'를 수행하면 거의 즉시 팝업되므로 내부적으로 IE는 필자가 원하는대로 할 수있는 API를 사용해야합니다.

감사합니다.
쉐인.

답변

2

MSHTML의 이전 버전에서 outerHTML은 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; 
} 
+0

Amnon에게 감사드립니다. 나는 그것을 시험해보고이 질문을 결과로 업데이트 할 것입니다. – Shane

+0

아래의 질문에 대해 : IPersistStream은 원본을 원래 인코딩으로 저장합니다.따라서 문서의 인코딩에 따라 단일 바이트, 2 바이트 또는 문자 당 가변 바이트 수 (utf-8)가 될 수 있습니다. – Amnon

+0

아, 네. IHTMLDocument2 포인터에서 Charset을 얻는다면 '유니 코드'가 일반적으로 UTF16을 나타냄을 알 수 있습니다. 따라서 IE에서이 점을 고수하기를 바랍니다. 그리고 다른 모든 것이 UTF8과 호환된다는 가정이 잘못되어 끊어지지 않기를 바랍니다. – Shane

1

네, IPersistStream에 대해 QI를 수행하고 CreateStreamOnHGlobal에 의해 생성 된 메모리 스트림에 저장하십시오. 문서 다운로드가 완료되어야합니다 (준비 상태를 완료해야 함).

+0

아, Sheng Jiang 포인터에 감사드립니다. 작업 코드가있을 때이 질문을 업데이트하겠습니다. – Shane

+0

나는 시도했다 : \t CComPtr pDispatch; \t MSHTML :: IHTMLDocumentPtr pDocument = NULL; \t hr = m_spWebBrowser-> get_Document (& pDispatch); \t hr = pDispatch-> QueryInterface (IID_IHTMLDocument, (void **) & pDocument); \t IPersistStreamInitPtr persistStream = pDocument; \t IStreamPtr stream = NULL; \t hr = CreateStreamOnHGlobal (NULL, TRUE, & stream); \t hr = persistStream-> Save (stream, FALSE); 하지만 '저장'을 실행하는 데 동일한 3 분이 걸렸습니다. 따라서 IE에서 '페이지 소스보기'를 수행하면 거의 즉시 창을 팝업하므로 DOM과 상호 작용하는 것으로 추측됩니다. – Shane

+0

이상합니다. 반환하는 데이터는 원래 데이터입니다. IE의 캐시 http://support.microsoft.com/kb/172607에서 파일을 파헤칠 수 있는지 확인하십시오. –

0

감사 암논은, 다음의 코드는 대부분 나를 위해 노력하고 있습니다.

// 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; 
} 

지금 남아있는 유일한 문제는 일부는 다른 시간에 대부분의 시간, 및 더블 바이트 문자 나에게 단일 바이트 문자를 반환 이유를 파악하는 방법이다. 어떤 아이디어?

도움 주셔서 감사합니다.

관련 문제