问题
Currently I want to automate the running IE. I have successfully attached the running IE using below code (I assume there is only one IE within one tab)
#include "atl/atlbase.h"
#include <exdisp.h>
#include <mshtml.h>
CComQIPtr<IWebBrowser2> pCurIE;
void __fastcall TForm4::Button3Click(TObject *Sender)
{
bool SuccessToHook = false;
CComPtr<IShellWindows> m_spSHWinds;
if (FAILED(m_spSHWinds.CoCreateInstance( __uuidof( ShellWindows)))){
return ;
}
LONG nCount;
m_spSHWinds->get_Count( &nCount);
ShowMessage(nCount);
for (int i = 0; i < nCount; i++) {
CComPtr<IDispatch> pDisp;
m_spSHWinds->Item( CComVariant(i), &pDisp);
CComQIPtr<IWebBrowser2> pIE(pDisp);
if (pIE == NULL){
continue ;
}
CComPtr<IDispatch> pDispDoc;
pIE->get_Document(&pDispDoc);
CComQIPtr<IHTMLDocument2> pHtmlDoc(pDispDoc);
if (pHtmlDoc){
pCurIE = pIE;
SuccessToHook = true;
break ;
}
}
ShowMessage(SuccessToHook ? "Success to hook." : "Failed to hook." );
}
Now I can control the current running IE like navigating and read the current state. But as I want to show messages when the events like onDocumentComplete Event are fired. I have no idea how to listen the event following my current code. A simple sample code with BCB will be very appreciated as there are some samples with VC++ but my project is on C++ XE2.
Thanks @Remy Lebeau and this link, I finally solve my problem. I leave my code here and hope it maybe helpful for someone else.
A class derived from TEventDispatcher
#include <exdisp.h>
#include <exdispid.h>
#include <mshtml.h>
#include <mshtmdid.h>
#include <utilcls.h>
//---------------------------------------------------------------------------
class TForm4;
class EventHandler:public TEventDispatcher<EventHandler,&DIID_DWebBrowserEvents2>{
private:
bool connected;
TForm4 *theform;
IUnknown* server;
protected:
HRESULT InvokeEvent(DISPID id, TVariant *params){
switch(id){
case DISPID_DOCUMENTCOMPLETE:
ShowMessage("On Document Complete");
break;
default:
break;
}
}
public:
EventHandler(){
connected = false; //not connected;
theform = false; //backptr to form is null
}
~EventHandler(){
if (connected)
Disconnect();
}
void Connect(TForm4 *form, IUnknown* srv){
server = srv;
theform = form; //back pointer to form to do stuff with it.
server->AddRef(); //addref the server
ConnectEvents(server);
}
void Disconnect(){
DisconnectEvents(server); //disconnect the events
server->Release();
}
};
Start to listen
void __fastcall TForm4::Button5Click(TObject *Sender)
{
Event = new EventHandler();
Event->Connect(this, pCurIE);
}
Stop listening
void __fastcall TForm4::Button6Click(TObject *Sender)
{
Event->Disconnect();
}
回答1:
You have to write a class in your code that implements the DWebBrowserEvents2
interface. Then you can query the browser for its IConnectionPointContainer
interface, call the IConnectionPointContainer::FindConnectionPoint()
method to find the IConnectionPoint
that cooresponds to DWebBrowserEvents2
, and call the IConnectionPoint::Advise()
method passing it an instance of your class. Don't forget to call IConnectionPoint::Unadvise()
when you are done using the events.
To help you with that, you can derive your class from the VCL's TEventDispatcher
class in utilcls.h. Its ConnectEvents()
and DisconnectEvents()
methods handle the IConnectionPoint
stuff for you. You would then just override the abstract InvokeEvent()
method (each of the browser's events have their own DISPID
values).
来源:https://stackoverflow.com/questions/11642964/how-do-i-listen-the-event-of-running-ie-with-iwebbrowser2-in-c-xe2