TWebBrowser

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

TWebBrowser

Postby pidgi2009 » Mon Mar 05, 2018 12:49 pm

2 questions.

Intro: I have a Form, with a TcppWebBrowser on it. I Navigate() to a known URL. I fill the edit boxes on the page with username and password, programmatically. I then simulate a click on a "Validate" button that leads me to another page. On that last page, I do have elements, some of which have an HyperLink. If I do click on the text, it leads to another page. But that is a text element, not a button.

this is an snippet from the .mht page as saved from Internet Explorer:
Code: Select all
<BUTTON =
name=3D"BtnConxn" class=3D"btn suggere clsAlignAnnule"  id=3D"BtnConxn" onclick=3D'javascript:WebForm_DoPostBackWithOptions(new
WebForm_PostBackOptions("BtnConxn", "", true, "", "", false, false))'
type=3D"submit" data-ctlracine=3D"true" value=3D"Connexion">Connexion</BUTTON>


Here is my code to simulate the click on the BtnConxn button defined above:
Code: Select all
               Variant vForms    = vDocument.OlePropertyGet("All");
               Variant vForm = vForms.OleFunction("NamedItem", WideString("BtnConxn").c_bstr());
           if (vForm.VUnknown == NULL)
      {
         ShowMessage("Problème avec l'authentification. (3)");
         WebBrowser->OnDocumentComplete = NULL;
         return;
      }
      vForm.OleFunction("click");


Now, I want to simulate a click on the hypertext link on the page, programmatically. I cannot find how...

Here is the definition of the link on the Web page:
Code: Select all
<DIV class=3D"lien_gros aligne_droite" id=3D"lien_accueil"><A href=3D"https://wwwsom_kind_of_a_secure_site.aspx">Accueil</A></DIV>


I tried with the
Code: Select all
vForm = vForms.OleFunction("NamedItem", WideString("lien_accueil").c_bstr());
vForm.OleFunction("click");


But that code has no effect. The vForm is the correct element, I can find it with the debugger, as it's "outertext" is correctly the text seen on screen. So the first line above is valid. But the "click" function has no effect.

Now the questions:
1- How can I simulate the HyperLink click?
2- Where could I find a listing of the valid functions I could use? I mean, OleFunction("click"), but what else?

Thank you for your help!
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby rlebeau » Tue Mar 06, 2018 1:40 pm

pidgi2009 wrote:Now, I want to simulate a click on the hypertext link on the page, programmatically. I cannot find how...


That is because you are not going deep enough into the DOM. You are trying to click on a <DIV> element, not on an <A> element. The <DIV> in question has an <A> child element inside of it. That is what you need to click on instead, eg:

Code: Select all
vDiv = vForms.OleFunction("NamedItem", WideString("lien_accueil").c_bstr());
vChildren = vDiv.OlePropertyGet("children");
vAnchor = vChildren.OleFunction("item", 0, 0);
vAnchor.OleFunction("click");


pidgi2009 wrote:1- How can I simulate the HyperLink click?


Click on the actual hyperlink, not on its parent element.

pidgi2009 wrote:2- Where could I find a listing of the valid functions I could use? I mean, OleFunction("click"), but what else?


T(Cpp)WebBrowser is a wrapper for Internet Explorer. IE's DOM interfaces are all documented on MSDN.

In fact, I strongly suggest you use the DOM interfaces directly for better performance, using Variant to go through IDispatch::Invoke() is just wasted overhead.

After loading a page, query the TCppWebBrowser::Document property for the IHTMLDocument2 interface, and go from there, eg:

Code: Select all
#include <mshtml.h>
#include <utilcls.h>

_DEF_SMARTPTR_IID(IHTMLDocument2, IID_IHTMLDocument2);
_DEF_SMARTPTR_IID(IHTMLElementCollection, IID_IHTMLElementCollection);
_DEF_SMARTPTR_IID(IHTMLElement, IID_IHTMLElement);
_DEF_SMARTPTR_IID(IHTMLAnchorElement, IID_IHTMLAnchorElement);

IHTMLDocument2Ptr doc;
IHTMLElementCollectionPtr coll;
IDispatchPtr disp;
IHTMLElementPtr div;
IHTMLAnchorElementPtr link;

doc = CppWebBrowser1->Document;
OleCheck(doc->get_all(&coll));
OleCheck(coll->item(TVariant(L"lien_accueil"), TVariant(0), &disp));
div = disp; disp.Unbind();
OleCheck(div->get_children(&disp));
coll = disp; disp.Unbind();
OleCheck(coll->item(TVariant(0), TVariant(0), &disp));
link = disp;
OleCheck(link->click());


Or:

Code: Select all
#include <MSHTML.hpp>
#include <utilcls.h>

_di_IHTMLDocument2 doc;
_di_IHTMLElementCollection coll;
_di_IDispatch disp;
_di_IHTMLElement div;
_di_IHTMLAnchorElement link;

doc = CppWebBrowser1->Document;
OleCheck(doc->get_all(&coll));
OleCheck(coll->item(TVariant(L"lien_accueil"), TVariant(0), &disp));
div = disp; disp.Release();
OleCheck(div->get_children(&disp));
coll = disp; disp.Release();
OleCheck(coll->item(TVariant(0), TVariant(0), &disp));
link = disp;
OleCheck(link->click());
Last edited by rlebeau on Wed Mar 07, 2018 4:14 pm, edited 3 times in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1528
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: TWebBrowser

Postby pidgi2009 » Wed Mar 07, 2018 2:33 pm

Thank you very much for the very detailed help!
I will study it in greater depth. Until now, the code doesn't compile... my version of Tokyo tells me that _di_IHTMLElementCollection and the other _di_xxxxx are not recognized.
I tried to include <MSHTML.hpp> (instead of, or in addition to, or before or after), to no avail... the errors are different but it still does not compile. But I am interrested in applying the solution you suggest.
I will work a bit on it, then I will post my results here. Maybe it could help somebody...
Thank you again!

Pierre
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby rlebeau » Wed Mar 07, 2018 4:12 pm

pidgi2009 wrote:Until now, the code doesn't compile... my version of Tokyo tells me that _di_IHTMLElementCollection and the other _di_xxxxx are not recognized.


The actual interfaces themselves are declared in mshtml.h, which is why I added that #include in my example. I forgot that it doesn't declare any smart wrappers for them, though. I have updated my previous example to fix that.

pidgi2009 wrote:I tried to include <MSHTML.hpp> (instead of, or in addition to, or before or after)


That would work too, but defines DelphiInterface wrappers instead of TComInterface wrappers. Either way would work, though.

pidgi2009 wrote:to no avail... the errors are different but it still does not compile.


What kind of errors are you actually getting?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1528
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: TWebBrowser

Postby pidgi2009 » Thu Mar 08, 2018 9:26 am

many error messages like:
(Sorry, French speaking...)
[bcc32 Erreur] mshtmhst.h(191): E2015 Ambiguïté entre 'IHTMLWindow2' et 'Mshtml::IHTMLWindow2'
[bcc32 Erreur] mshtmhst.h(215): E2015 Ambiguïté entre 'IHTMLWindow2' et 'Mshtml::IHTMLWindow2'
[bcc32 Erreur] MotDePasses.cpp(474): E2285 Impossible de trouver une correspondance pour 'Variant::OlePropertySet(const char *,undefined)'
[bcc32 Erreur] MotDePasses.cpp(484): E2316 'c_bstr' n'est pas un membre de 'UnicodeString'
[bcc32 Erreur] MotDePasses.cpp(484): E2285 Impossible de trouver une correspondance pour 'Variant::OlePropertySet(const char *,undefined)'
[bcc32 Erreur] MotDePasses.cpp(656): E2316 'get_all' n'est pas un membre de 'IHTMLDocument2'
[bcc32 Erreur] MotDePasses.cpp(657): E2357 Référence initialisée avec 'IDispatch * *', nécessite lvalue de type '_di_IDispatch'
[bcc32 Erreur] MotDePasses.cpp(657): E2342 Mauvaise correspondance de type dans le paramètre '__item_result' ('_di_IDispatch &' désiré, 'IDispatch * *' obtenu)
[bcc32 Erreur] MotDePasses.cpp(660): E2316 'get_children' n'est pas un membre de 'IHTMLElement'
[bcc32 Erreur] MotDePasses.cpp(663): E2357 Référence initialisée avec 'IDispatch * *', nécessite lvalue de type '_di_IDispatch'
[bcc32 Erreur] MotDePasses.cpp(663): E2342 Mauvaise correspondance de type dans le paramètre '__item_result' ('_di_IDispatch &' désiré, 'IDispatch * *' obtenu)
[bcc32 Erreur] MotDePasses.cpp(665): E2316 'click' n'est pas un membre de 'IHTMLAnchorElement'
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby pidgi2009 » Thu Mar 08, 2018 9:41 am

But still working on it.

If I use
#include <mshtml.h>
instead of
#include <MSHTML.hpp>
with the code you provided, there is only one error that is left, it is:

[bcc32 Erreur] MotDePasses.cpp(669): E2316 'click' n'est pas un membre de 'IHTMLAnchorElement'

I am now in the process of investigating what are the methods I could use with that Element.
I'll be back... (low tone voice, dark glasses, big guns in both hands...)
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby pidgi2009 » Thu Mar 08, 2018 1:40 pm

OK, now it does compile. And... it works! My code connects correctly.
Many thanks, M. Lebeau!
here is the modified code:

Code: Select all
#include <vcl.h>
#include <mshtml.h>
#include <utilcls.h>
#include "SHDocVw.hpp"
#include <memory>

   _DEF_SMARTPTR_IID(IHTMLDocument2, IID_IHTMLDocument2);
   _DEF_SMARTPTR_IID(IHTMLElementCollection, IID_IHTMLElementCollection);
   _DEF_SMARTPTR_IID(IHTMLElement, IID_IHTMLElement);
   _DEF_SMARTPTR_IID(IHTMLAnchorElement, IID_IHTMLAnchorElement);

   IHTMLDocument2Ptr doc;
   IHTMLElementCollectionPtr coll;
   IDispatchPtr disp;
   IHTMLElementPtr div;
   IHTMLAnchorElementPtr link;

   doc = ccpWebBrowser->Document;
   OleCheck(doc->get_all(&coll));
   OleCheck(coll->item(TVariant(L"lien_accueil"), TVariant(0), &disp));
   div = disp;
   disp.Unbind();
   OleCheck(div->get_children(&disp));
   coll = disp;
   disp.Unbind();
   OleCheck(coll->item(TVariant(0), TVariant(0), &disp));
   link = disp;
   OleCheck( (static_cast<IHTMLElementPtr>(link))->click()) ;
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby rlebeau » Fri Mar 09, 2018 10:33 pm

pidgi2009 wrote:
Code: Select all
#include "SHDocVw.hpp"


That should be using angle brackets instead of quotations since the file is on the compiler's search path:

Code: Select all
#include <SHDocVw.hpp>


pidgi2009 wrote:[bcc32 Erreur] MotDePasses.cpp(669): E2316 'click' n'est pas un membre de 'IHTMLAnchorElement'


My bad. I forgot that IHTMLAnchorElement does not derive from IHTMLElement. click() is a method of IHTMLElement, and the anchor element implements both IHTMLElement and IHTMLAnchorElement, so you can query the IHTMLAnchorElement object for its IHTMLElement:

Code: Select all
IHTMLElementPtr elem = link;
OleCheck(elem->click());


pidgi2009 wrote:
Code: Select all
OleCheck( (static_cast<IHTMLElementPtr>(link))->click()) ;



AFAIK, you can't static_cast an IHTMLAnchorElementPtr to an IHTMLElementPtr, as they are unrelated types. I'm surprised the compiler accepts that cast at all.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1528
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: TWebBrowser

Postby pidgi2009 » Sat Mar 10, 2018 5:20 pm

Interresting...

If I do place, via the IDE, a TcppWebBrowser on a form, the IDE automatically puts:
#include "SHDocVw.hpp"
But if, instead I do add a TWebBrowser, then the following line is added:
#include <SHDocVw.hpp>

A subtle difference. Does it change anything? Don't seem to because if I then do change myself one line by the other, compiles the same, runs the same.

Should I go through my code and change the "" with <> ?
pidgi2009
BCBJ Veteran
BCBJ Veteran
 
Posts: 60
Joined: Sat Apr 25, 2009 11:44 am

Re: TWebBrowser

Postby rlebeau » Mon Mar 12, 2018 12:24 pm

pidgi2009 wrote:A subtle difference. Does it change anything?


Yes, it affects where the compiler looks for the specified file. Quotes are generally used for files that are relative to the project, and angle brackets are generally used for files that are relative to the compiler's installation. See What is the difference between #include <filename> and #include “filename”? for more details.

pidgi2009 wrote:Should I go through my code and change the "" with <> ?


I wouldn't bother changing IDE-generated code if it works.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1528
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: Majestic-12 [Bot] and 14 guests