?
Solved

Injecting HTML to exisitng HTML using C++ and MSHTML

Posted on 2003-03-08
11
Medium Priority
?
2,405 Views
Last Modified: 2011-09-20
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
Comment
Question by:moshem
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
  • 2
11 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 8097101
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
 
LVL 1

Author Comment

by:moshem
ID: 8097222
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 8098940
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:moshem
ID: 8098980
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
 
LVL 49

Accepted Solution

by:
DanRollins earned 1400 total points
ID: 8099406
>>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
 

Expert Comment

by:henk53
ID: 8102968
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 8105770
>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
 
LVL 1

Author Comment

by:moshem
ID: 8106752
guys, I'll try it soon and let you know, thanks
0
 

Expert Comment

by:henk53
ID: 8106785
>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
 
LVL 1

Author Comment

by:moshem
ID: 8140168
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
 
LVL 1

Author Comment

by:moshem
ID: 8140211
Ok , I got it I used insertAdjacentHTML instead

thanks
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question