Using CHtmlView with dynamic content

I am writing a MFC Documnet-View application which will use a view class derived from CHTMLView. The HTML I wish to view will be generated dynamically at run-time. For performance purposes, I do not wish to write the HTML to a file and then reference that file as a URL. Also, since the HTML is generated dynamically, I can see no way to convert the HTML into a resource and use the LoadFromResource method. Creating a resource at runtime seems like it might work if it's possible to do this. Anyway, I'm open to any suggestions.
frogerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

DanRollinsCommented:
There are several ways to feed html text directly into a CHtmlView.

Here's the easiest way:
#include <mshtml.h>
#include <atlbase.h>

CString gsHtmlPage="This is some body text <b>from memory</b>!";

void CSdiHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
     CHtmlView::OnDocumentComplete(lpszURL);

    HRESULT hr;
    IHTMLDocument2*  spDoc= (IHTMLDocument2*)GetHtmlDocument();
    IHTMLElement*    pElem= NULL;

    hr= spDoc->get_body( &pElem ); // prolly ought to do some error checking
    CComBSTR bstrHtml= gsHtmlPage;
    hr= pElem->put_innerHTML( bstrHtml );  // set the body text
}
=-=-=-=-=-=-=-=-=-
First navigate to some page (eg, about:blank) then the above code kicks in.  

=-=-=-=-=-=-=-=-=-
Here's another way:

To display a very short page, you can use the
 about:
protocol.  For instance:

Navigate("about:"<html><body>This page was loaded from <b>memory!</b></body></html>", 0,0,0 );

=-=-=-=-=-=-=-=-=-
There is another way that is more complicated, involving creating a stream from a meory block:

// include <HTML><BODY> with this technique
CString gsHtmlPage="<HTML><BODY>This is some body text <b>from memory</b>!</body></html>";

void CSdiHtmlView::OnDocumentComplete(LPCTSTR lpszURL)
{
    static BOOL fDoneOnce= FALSE; // reentrancy kludge
    if ( fDoneOnce ) {
        fDoneOnce= FALSE;
        return;
    }
    fDoneOnce= TRUE;

    IPersistStreamInit* pPersistStreamInit= NULL;

    DWORD nPgLen= gsHtmlPage.GetLength();
    HRESULT hr;
    HGLOBAL hMemPage=  GlobalAlloc( GPTR, nPgLen+1 );
    LPSTR   pMemPage=  (LPSTR)GlobalLock( hMemPage );
    memcpy( pMemPage, (LPCSTR)gsHtmlPage, nPgLen+1 );
    GlobalUnlock( hMemPage );

    LPSTREAM pStm;
    hr= CreateStreamOnHGlobal( hMemPage, TRUE, &pStm );
    if( SUCCEEDED(hr) ) {
        LPDISPATCH pHtmlDoc= GetHtmlDocument();
        if ( pHtmlDoc ) {
            hr= pHtmlDoc->QueryInterface( IID_IPersistStreamInit, (void**)&pPersistStreamInit );
            hr= pPersistStreamInit->InitNew();  // Initialize it with the storage we created
            hr= pPersistStreamInit->Load( pStm );
        }
    }
    if( pPersistStreamInit ) {
        pPersistStreamInit->Release();
    }
    GlobalFree( hMemPage );
}
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
One thing that you will find is that all of these techniques feed in one HTML page, but there is no clear way to have that page contain IMGs (JPG, GIF, BMP, etc) or other URL-referenced data.  These are actually separate downloads and I don't know how to intercept and handle the requests for them from memory alone.  

So, you can do without images, or you can pull images from some files or you can get them from your EXE's resources.  There is some useful info about displaying html and images that are in a resource file here:

http://www.experts-exchange.com/jsp/qShow.jsp?qid=12037601

-- Dan

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ShaunWildeCommented:
> , I can see no way to convert the HTML into a resource
> and use the LoadFromResource method.
> Creating a resource at runtime seems like it might work
> if it's possible to do this. Anyway, I'm open

add them to your resources as external files under the "HTML" group.

to access them use res: protocol res://yourpath/your.dll\main.htm

however you are limited to a single directory type structure for your pages

> These are actually separate downloads and I don't know
> how to intercept and handle the requests for them from
> memory alone.  

you can use an asynchronous pluggable protocol handler (see IInternetProtocol and IInternetProtocolRoot) for these and use your own protocol to pull them from sources other than the web - I use mine to pull info from databases similar to the mk: protocol used by MS in the MSDN - unfortunately they have their limitations eg if trying to handle downloads for 3rd party objects running in explorer eg flash


your will ses that MS explorer appears to use pluggable protocol handlers for all of the protocols
DanRollinsCommented:
Hi ShawnWilde,
I have been trying to find a pluggable protocol example for some time -- the etcprot sample is gone from MSDN.  If you have more info on pluggable protocols, I'm sure that froger could benefit (if he is still around...)

>> Creating a resource at runtime seems like it might work if it's possible to do this...

On NT, it is possible to add and modify resources.  But it is not possible with Win9x (short of building the resource file --- Exe or DLL -- from scratch at runtime)

-- Dan

Fundamentals of JavaScript

Learn the fundamentals of the popular programming language JavaScript so that you can explore the realm of web development.

ShaunWildeCommented:
this is the only C++ one I know of (other than etcprot)

http://codeguru.earthweb.com/atl/asyncpp.shtml

the rest are in delphi

> the etcprot sample is gone from MSDN

they pulled it a long time ago with the supposed intention of updating it - they never got round to it - so why they didn't leave it alone is anyones guess

Implementing one is quite easy if you follow the sample above and also implemet some of the suggestions - you can chose whatever data source you like.

When I had a similar situation to yours I created a singleton object within the DLL (therefore only process singleton rather than machine singleton) to which I added my data AddData([in]BSTR bstrName,[in]VARIANT data)
my data was in a safearray that was contained in the variant.

my singleton kept a map of names/data and a request came for a file it was gathered from the singleton object and delivered to IE - using this method I delivered HTML pages and GIFs and BMPs that were created on the fly (eg runtime)
DanRollinsCommented:
hi froger,
Do you have any additional questions?  DO any comments need clarification?

-- Dan
frogerAuthor Commented:
Dan's response was thorough, complete and provided me with multiple options for solving my programming problem. Good job dan!!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.