Its a long way to get them all:
+ first you need a handler (as IDispatch better IDispatchEx)
#include <dispex.h>
class iDummy : public IDispatchEx
{
public: virtual HRESULT __stdcall QueryInterface(REFIID riid,void **ppv)
{
if(IID_IUnknown ==riid) return *(IUnknown **)ppv=this,AddRef();S_OK;
if(IID_IDispatch ==riid) return *(IDispatch **)ppv=this,AddRef();S_OK;
if(IID_IDispatchEx==riid) return *(IDispatchEx**)ppv=this,AddRef();S_OK;
return E_NOINTERFACE;
}
virtual ULONG __stdcall AddRef(){ return InterlockedIncrement(&_ref); }
virtual ULONG __stdcall Release(){ if(InterlockedDecrement(&_ref)) return _ref; delete this; return 0; }
public: virtual HRESULT __stdcall GetTypeInfoCount(UINT *pctinfo)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetIDsOfNames(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId)
{ unsigned int i; for(i=0;(i<cNames) && (S_OK==GetDispID(rgszNames[i],0,rgDispId+i));i++); return i<cNames?DISP_E_MEMBERNOTFOUND:S_OK; }
virtual HRESULT __stdcall Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)
{ return InvokeEx(dispIdMember,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,0); }
public: virtual HRESULT __stdcall GetDispID(BSTR bstrName,DWORD grfdex,DISPID *pid)
{ TRACE(__TEXT("call: %s\r\n"),bstrName); return E_NOTIMPL; }
virtual HRESULT __stdcall InvokeEx(DISPID id,LCID lcid,WORD wFlags,DISPPARAMS *pdp,VARIANT *pvarRes,EXCEPINFO *pei,IServiceProvider *pspCaller)
{ if(0==id){ Beep(3000,100); }return E_NOTIMPL; }
virtual HRESULT __stdcall DeleteMemberByName(BSTR bstrName,DWORD grfdex)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall DeleteMemberByDispID(DISPID id)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetMemberProperties(DISPID id,DWORD grfdexFetch,DWORD *pgrfdex)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetMemberName(DISPID id,BSTR *pbstrName)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetNextDispID(DWORD grfdex,DISPID id,DISPID *pid)
{ return E_NOTIMPL; }
virtual HRESULT __stdcall GetNameSpaceParent(IUnknown **ppunk)
{ return E_NOTIMPL; }
public:
iDummy(){ _ref=1; }
private:
long _ref;
};
+ next you have to walk all the HTML elements, even if the load is ready (examine the ready state of the web browser control):
enum { childNodes, length, };
typedef void (*FNWALK)(IDispatch* node);
void WalkNode(IDispatch* node,BSTR* anames,FNWALK fn)
{
VARIANT ret1 = { VT_EMPTY, };
VARIANT ret2 = { VT_EMPTY, };
VARIANT ret3 = { VT_EMPTY, };
VARIANT ret4 = { VT_EMPTY, };
fn(node);
if(S_OK==InvokeName(node,anames[childNodes],ret1))
{
if(VT_DISPATCH==ret1.vt)
{
if(S_OK==InvokeName(ret1.pdispVal,anames[length],ret2))
{
if(VT_I4==ret2.vt)
{
wchar_t num[32];
ret3.vt = VT_I4;
for(ret3.lVal=0;ret3.lVal<ret2.lVal;ret3.lVal++)
{
_itow_s(ret3.lVal,num,sizeof(num)/sizeof(num[0]),16);
if(S_OK==InvokeName(ret1.pdispVal,num,ret4))
{
if(VT_DISPATCH==ret4.vt)
{
WalkNode(ret4.pdispVal,anames,fn);
}
VariantClear(&ret4);
}
}
}
VariantClear(&ret2);
}
}
VariantClear(&ret1);
}
}
void WalkDocument(IDispatch* doc,FNWALK fn)
{
BSTR anames[8];
anames[childNodes] = ::SysAllocString(L"childNodes");
anames[length] = ::SysAllocString(L"length");
WalkNode(doc,anames,fn);
for(int i=0;i<=length;i++) SysFreeString(anames[i]);
}
+ some helper functions needed as follows:
HRESULT InvokeName(IDispatch* node,BSTR name,VARIANT& ret)
{
HRESULT hr = E_FAIL;
if(node)
{
DISPID did = 0;
DISPPARAMS arg = { 0,0,0,0 };
if(S_OK==node->GetIDsOfNames(IID_NULL,&name,1,0,&did))
{
hr = node->Invoke(did,IID_NULL,0,DISPATCH_PROPERTYGET,&arg,&ret,0,0);
}
}
return hr;
}
HRESULT InvokeWithParams(IDispatch* node,BSTR name,VARIANT* aparam,const unsigned int nparam,VARIANT& ret)
{
HRESULT hr = E_FAIL;
if(node)
{
DISPID did = 0;
DISPPARAMS arg = { aparam,0,nparam,0 };
if(S_OK==node->GetIDsOfNames(IID_NULL,&name,1,0,&did))
{
hr = node->Invoke(did,IID_NULL,0,(0<nparam?DISPATCH_PROPERTYPUT:DISPATCH_PROPERTYGET),&arg,&ret,0,0);
}
}
return hr;
}
+ implement the walk function to replace the event handlers you want to replace:
void __fnWalk(IDispatch* node)
{
BSTR nodeName = L"nodeName";
VARIANT ret1 = { VT_EMPTY, };
VARIANT ret2 = { VT_EMPTY, };
VARIANT ret3 = { VT_EMPTY, };
if(S_OK==InvokeName(node,nodeName,ret1))
{
if(VT_BSTR==ret1.vt)
{
TRACE(__TEXT("name: %s\r\n"),ret1.bstrVal);
{
if(S_OK==InvokeName(node,L"OnClick",ret2))
{
if(VT_DISPATCH==ret2.vt)
{
VARIANT a[8];
unsigned int n = 0;
a[n].pdispVal = new iDummy;
a[n].vt = VT_DISPATCH;
++n;
if(S_OK==InvokeWithParams(node,L"OnClick",a,n,ret3))
{
VariantClear(&ret3);
}
while(0<n) VariantClear(a+(--n));
}
VariantClear(&ret2);
}
}
}
VariantClear(&ret1);
}
++__walkdone;
}
+ finally the code you can use all of this:
IDispatch* doc = m_web.get_Document();
if(doc)
{
__walkdone = 0;
WalkDocument(doc,__fnWalk);
doc->Release();
}
Functions are tested and work with a simple form.
Good luck.