• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2503
  • Last Modified:

Injecting HTML to exisitng HTML using C++ and MSHTML

Hi,

I recently asked a question on how to embeed an html control in my C++ app.

http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_20534181.html

Now that I have succeeded in it, and also wrote some HTML code to it, I face a new problem.

I need to insert HTML content to the already exisitng content I have, there is away to do it using :

        // iweb was already obtained

     if (!ibody)
         iweb->get_body (&ibody);
     
     if (ibody)
     {
          ibody->insertAdjacentHTML (_bstr_t("afterBegin"), _bstr_t(str) );
          ibody->Release ();
     }


        or

     if (!iall)
         iweb->get_all (&iall);


     _variant_t vtag = 6;
     _variant_t vindex = 1;

     IDispatch  * iTag;

     if (iall)
     {
          iall->item (vtag, vindex, &iTag);
          if (iTag)
          {
               IHTMLTable  * irow;
               iTag->QueryInterface(IID_IHTMLTable,(void**)&irow);
                        //now use it
               iTag->Release ();
          }

          iall->Release ();
     }


this works well, but what if I need to insert at a specific location? the way I saw in the documantations says, I need to search for it and then use a specific COM interface per tag (e.g. <TR>, <TABLE>) and use specific methods availaible only to that tag, and that is way more code than I wanted.

I need a generic way to search for a specific location and insert raw HTML at that specific location. can anyone help me with a technique and a code snippet ?

thanks!                    
0
moshem
Asked:
moshem
  • 5
  • 4
  • 2
1 Solution
 
DanRollinsCommented:
When you say " at that specific location" what are you talking about... a piece of Javascript, the start of a TR entry?  exactly what?

I have not reid this approach, but it ought to work:
You can get the innerHTML of the body text,... right?  Just search it to locate the target location.  Then insert the desired new text, and then set the innerHTML with the modified text.

-- Dan
0
 
moshemAuthor Commented:
This might work, but it is as "expensive" as reloading the entire page, the idea was to 'insert'

I need to insert after a specific tag...
0
 
DanRollinsCommented:
The "expense" of the operation was not mentioned in the question :)  And IE can parse and redisplay a page in the blink of an eye...

If you can do just a little bit of parsing, you can locate that tag and ascertain its ID.  Given the ID, you can locate it in the document.all collection, and modify just it. If it does not have an ID, then you could try backing up to a larger container (for instance the TABLE tag, if the secret tag you are looking for, is say a TD tag) and if *it* has an ID, then you an locate it in the all collection, then get and update the innerHTML of that larger object.  Yes, this is hugely expensive.  Possibly a full millisecond.

How about telling us exactly what you are trying to do?  What text do you want to insert, where excatly do you want to insert it, and why are you attempting to do this?

I ask this because there are often many different ways to approach a problem and you might be looking down a complicated path when a simpler one is available.

-- Dan
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
moshemAuthor Commented:
Ok,

I am using IE to display data from my software, I am formating it with HTML and insert it on top (almost on top, there is a header).

so I an put any ID tag I want if it will help me to locate it later.

then I need to insert new HTML text so it will "push" the rest of the data down but the header remains. this is why I need to insert at specific location.

as for document.all collection, can you give a full example ? I need it to be a generic thing and not use interface specific to tag type.

thanks
0
 
DanRollinsCommented:
>>so I an put any ID tag I want if it will help me to locate it later.

Do you mean "so i CAN put an ID..." ?  
If you are generating the HTML yourself, then by all means, use an id value.  For instance, I have used a DIV tag to sort of 'reserve' a location to insert a 20-line text report.  For instance:

=-=-=-=-=-=-=-=-=-=-=-=-=-=- start of HTML file test.htm
<html><body>
(this is above the DIV)
<div ID="divRptInsertionHere">
<br>
A <B>report</B> will be inserted here.  Please wait...
<br>
</div>
(this is below the DIV)<br>
</body></html>
=-=-=-=-=-=-=-=-=-=-=-=-=-=- end


=-=-=-=-=-=-=-=-=-=-=-=-=-=- in your C++ program
// read in the info for access the DOM
// i usually put this in stdafx.h

#pragma warning(disable : 4146)
#pragma warning(disable : 4049)
#pragma warning(disable : 4192)
#import "c:\winnt\system32\mshtml.tlb"
#pragma warning(default: 4192)
#pragma warning(default: 4146)

....

Here is the code!

m_ctlBrowser.Navigate("c:\\temp\\test.htm", 0,0,0,0 );

... then after the page is loaded (DownloadComplete)...

MSHTML::IHTMLDocument2Ptr pDoc= m_ctlBrowser.GetDocument();
MSHTML::IHTMLElementCollectionPtr pAllElems= pDoc->all;

int nCnt= pAllElems->length; // eyeball check.  It WORKS!

MSHTML::IHTMLElementPtr pMyDiv= pAllElems->item("divRptInsertionHere");

char szTheReport[]=
     "<Font color=red>"
     "<H1>Here is the report!</H1>"
     "</Font><pre>"
     "Age Height Name\r\n"
     "  7    1.1 Jones\r\n"
     " 67   3.21 Smith\r\n"
     "--- ------ -----\r\n"
     "</pre>";

pMyDiv->PutinnerHTML( szTheReport );

=-=-=-=-=-=-=-=-
In the above code, I use m_ctlBrowser.GetDocument() to get the IDispatch becasue I have taken the simple path of using MFC and instantiating a webbrowser control in a dialog box (it takes about 10 seconds to do that).  But all that m_ctlBrowser.GetDocument() does is return the IDispatch of the control.  Based upon your previous question, I think you are doing this the hard way (Raw Win32) but you will be able to just use the

   iweb

pointer from your previous work.

The above code has been tested and does work.  It is also 'generic' in that you do not need to use a DIV tag.  You can use a <TABLE> or a <TD> or a <P></P> or virtually eany element.

-- Dan
0
 
henk53Commented:
I hit the same problem earlier. My conclusion is simple.
put_innerHTML doesn't work. Well, atleast not as documented. You can only
use it to write certain tags, mostly tags that have to do with rendering.
E.g. you can query the IHTMLElement interface from a <head> element, but you
can't use its put_innerHTML method for any tag that's valid within head.

You can fool the system however by writing for example:
x.put_innnerHTML(place,"<br><base...>);  Where x is the IHTMLElement interface
of <HEAD>.

Put MSHTML or the webbrowser in design mode and send the savesas command to
verify that this DOES work. Ofcourse you don't want the <br> there.

The -solution- is to query the IHTMLDOM... interfaces introduced with IE5. Use
the old createElement, query its IHTMLDOMNode interface and insert this by
calling AppendNode from another IHTMLDOMNode interface queried from the node
where you want to insert.

Some example code. I used this to insert a new base element into a document (when one doesn't exist).
The code works equally well with any other type of element.

IHTMLElement* pHead;
CString eTag,BaseUrl;
HRESULT hr;

// [... walk document and retrieve head element]
// [... set BaseUrl to some value]

IHTMLDOMNode* pDOMNode = NULL;

if (SUCCEEDED(hr = pHead->QueryInterface( IID_IHTMLDOMNode, (LPVOID*)&pDOMNode ))) {              

     ASSERT(pDOMNode);

     IHTMLElement* NewBase = NULL;          // A new HTML <base> element
     IHTMLDOMNode* RefDomNode = NULL;     // reference to new element inserted

     // create the new base element with href set to the URL of the document
     eTag.Format("<base href=\"%s\">",(LPCTSTR)BaseUrl);
     hr=pHTMLDocument2->createElement(eTag.AllocSysString(),&NewBase);

     // We need the IHTMLDOMNode interface of the  new <base> element to insert it
     // in the document under <head>
     IHTMLDOMNode* NewDomNode= NULL;
     if (SUCCEEDED(hr = NewBase->QueryInterface( IID_IHTMLDOMNode, (LPVOID*)&NewDomNode))) {
          hr = pDOMNode->appendChild(NewDomNode,&RefDomNode);
          if ( RefDomNode != NULL)
               RefDomNode->Release();
          NewDomNode->Release();                                                  
     }    

     // release the IHTMLElement interface to the new <base> element
     if ( NewBase != NULL)
          NewBase->Release();
     // release the IHTMLDOMNode interface of the <head> element
     pDOMNode->Release();

} // QI IHTMLDOMNode
0
 
DanRollinsCommented:
>put_innerHTML doesn't work. Well, atleast not as documented... <head> element...

There is no need to make this harder than necessary.  I guarantee that you can use
 
    pElem->PutinnerHTML( s );

to replace <DIV>, or <TD>, or <P> with any sort of HTML, even complicated HTML such as a nested table, etc.

-- Dan
0
 
moshemAuthor Commented:
guys, I'll try it soon and let you know, thanks
0
 
henk53Commented:
>I guarantee that you can use pElem->PutinnerHTML( s );
>to replace <DIV>, or <TD>, or <P> with any sort of HTML,

Of course, but PutinnerHTML does not scale up to any tag outside <body>. IHTMLDOMNode works totally universal on every tag in the entire document.

Maybe today it's only the <body> tag you're working in, but tomorrow that might change. When using the DOM interfaces, you are simply prepared.

Also, I don't think it's that more difficult. If you throw away some checks and releases in my example code, you'll see that the basic code is just <create node> <add node>.

0
 
moshemAuthor Commented:
DanRollins

your code works (after porting to Win32) but it will only work once!

for example :

<DIV id=here></DIV>

I can insert into this tag all the text I want, but what happens next time I need to insert something in the same place but keep what I have inserted before.

I don't want to contcat the new and old insertion, the idea was to make it as efficent as possible.

thanks
0
 
moshemAuthor Commented:
Ok , I got it I used insertAdjacentHTML instead

thanks
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 5
  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now