sub add_modify_onclick()
i=window.external.set_property(property_name.value, property_value.value)
if i <> 0 then
MsgBox "Successfully inserted property '" & property_name.value & "'" ,
0 , ""
property_name.value=""
property_value.value=""
else
MsgBox "Property '" & property_name.value & "' could not be inserted",
0 , ""
end if
end sub
Figure 11 Property Report
<html>
<head>
<style>
body
{
margin-left: 50;
background-repeat: repeat-y;
}
th
{
font-style: italic;
}
</style>
<script language="vbscript">
sub main_onclick()
window.navigate "form1.htm"
end sub
</script>
</head>
<body background="background.jpg">
<div style="font-size: 18pt; font-style: italic">
Property Management System
</div>
<div style="font-size: 14pt">
Property Report
</div>
<br>
<script language="vbscript">
pc=window.external.get_propertycount()
'document.write "<b><i>Number of properties: " & pc & "</i></b><br><br>"
if pc > 0 then
document.write "<table border=1 width=100%>"
document.write "<tr>"
document.write "<th width=25 align=right>Property</td>"
document.write "<th width=* align=left>Value</td>"
document.write "</tr>"
for i=0 to pc-1
window.external.enum_property i, n, v
document.write "<tr><td width=25>" & n & "</td>"
document.write "<td width=*>" & v & "</td></tr>"
next
document.write "</table>"
else
document.write "No properties to report<br>"
end if
</script>
<br>
<input type="button" name="main" value="Back to Main">
</body>
</html>
Figure 12 Sinking Events
void html_document::operator=(IHTMLDocument2* i_newdoc)
{
// assign a new COM HTML document
release();
if (i_newdoc)
{
i_htmldoc2=i_newdoc;
// connect up document events
com_util::establish_connection_point(i_htmldoc2,
DIID_HTMLDocumentEvents,
&xHTMLDocumentEvents,
cookie);
// retrive window for the docuement, and assign
// to new C++ html window object
IHTMLWindow2* i_window2;
if (SUCCEEDED(i_newdoc->get_parentWindow(&i_window2)))
{
window=create_new_window();
if (window)
{
*window=i_window2;
}
}
}
}
Figure 13 Ahtml_document.Invoke
STDMETHODIMP html_document::XHTMLDocumentEvents::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
// route DISPIDs to methods on outer object
switch (dispidMember)
{
case DISPID_HTMLDOCUMENTEVENTS_ONHELP:
{
return This()->onhelp();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONCLICK:
{
return This()->onclick();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK:
{
return This()->ondblclick();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN:
{
return This()->onkeydown();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONKEYUP:
{
return This()->onkeyup();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS:
{
return This()->onkeypress();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN:
{
return This()->onmousedown();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE:
{
return This()->onmousemove();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP:
{
return This()->onmouseup();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT:
{
return This()->onmouseout();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER:
{
return This()->onmouseover();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONREADYSTATECHANGE:
{
return This()->onreadystatechange();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONBEFOREUPDATE:
{
return This()->onbeforeupdate();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONAFTERUPDATE:
{
return This()->onafterupdate();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONROWEXIT:
{
return This()->onrowexit();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONROWENTER:
{
return This()->onrowenter();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART:
{
return This()->ondragstart();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONSELECTSTART:
{
return This()->onselectstart();
}
break;
case DISPID_HTMLDOCUMENTEVENTS_ONERRORUPDATE:
{
return This()->onerrorupdate();
}
break;
}
return E_NOTIMPL;
}
Figure 14 my_document::onmouseover
STDMETHODIMP my_document::onmouseout()
{
// cause status text change in frame
CMainFrame* mf=dynamic_cast<CMainFrame*>(get_browser_control()->get_frame());
if (mf)
{
mf->set_status_text("");
}
return S_OK;
}
STDMETHODIMP my_document::onmouseover()
{
html_eventobj eo;
html_element se;
// get the event object from the associated window
window->get_event(eo);
// get the source HTML element object
eo.get_srcElement(se);
string tagname;
string id;
// get tagname and id
se.get_tagName(tagname);
se.get_id(id);
// cause status text change in frame
CMainFrame* mf=dynamic_cast<CMainFrame*>(get_browser_control()->get_frame());
if (mf)
{
string text=string("OnMouseOver; Tag: '")+tagname+"' ";
text+=string("Id: '")+id+"'";
mf->set_status_text(text.c_str());
}
return S_OK;
}
Figure 15 Resolving Method Calls in my_application
//------------------------------------------------------
#include "stdafx.h"
//------------------------------------------------------
#include "my_app.h"
//------------------------------------------------------
#include "com_util.h"
//------------------------------------------------------
using namespace com_utility;
//------------------------------------------------------
my_application::my_application()
{
// register strings and dispids
id_map["SET_PROPERTY"] =id_set_property;
id_map["GET_PROPERTY"] =id_get_property;
id_map["DELETE_PROPERTY"] =id_delete_property;
id_map["GET_PROPERTYCOUNT"] =id_get_propertycount;
id_map["ENUM_PROPERTY"] =id_enum_property;
method_map[id_set_property] =set_property;
method_map[id_get_property] =get_property;
method_map[id_delete_property] =delete_property;
method_map[id_get_propertycount] =get_propertycount;
method_map[id_enum_property] =enum_property;
}
my_application::~my_application()
{
// clear out any stored properties
for (string2variant_map::iterator i=propertymap.begin();
i!=propertymap.end();
i++)
{
VariantClear(&(*i).second);
}
}
//-------------------------------------------------------
STDMETHODIMP my_application::GetIDsOfNames(REFIID riid,
LPOLESTR* names,
UINT count,
LCID lcid,
DISPID* dispids)
{
// lookup dispids
HRESULT ret=S_OK;
for (int i=0;i<count;i++)
{
string str;
com_util::olestr2string(names[i],str);
strupr((char*)(str.c_str()));
string2dispid_map::iterator it=id_map.find(str);
if (it!=id_map.end())
{
dispids[i]=(*it).second;
}
else
{
dispids[i]=DISPID_UNKNOWN;
ret =DISP_E_UNKNOWNNAME;
}
}
return ret;
}
STDMETHODIMP my_application::Invoke(DISPID dispidMember,
REFIID riid,
LCID cid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
// call the appropriate method for the dispid
HRESULT ret=DISP_E_MEMBERNOTFOUND;
dispid2method_map::iterator it=method_map.find(dispidMember);
if (it!=method_map.end())
{
ret=(this->*(*it).second)(lcid,wFlags,pdispparams,pvarResult,
pexcepinfo,puArgErr);
}
return ret;
}
//---------------------------------------------------------
HRESULT my_application::set_property(LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
if (wFlags & DISPATCH_METHOD)
{
if (pdispparams->cArgs!=2)
{
return DISP_E_BADPARAMCOUNT;
}
// force to string
VARIANT varg;
VariantInit(&varg);
HRESULT hr=VariantChangeType(&varg,
&pdispparams->rgvarg[1],
0,
VT_BSTR);
if (FAILED(hr))
{
*puArgErr=1;
return hr;
}
string str;
com_util::bstr2string(varg.bstrVal,str);
if (!str.length())
{
if (!pexcepinfo)
{
return E_INVALIDARG;
}
// raise exception
memset(pexcepinfo,0,sizeof(EXCEPINFO));
pexcepinfo->wCode =1000;
pexcepinfo->bstrSource =SysAllocString(L"WebBrowser Demo");
pexcepinfo->bstrDescription
=SysAllocString(L"Index can not be empty string");
return DISP_E_EXCEPTION;
}
VARIANT copy;
VariantInit(©);
VariantCopy(©,&pdispparams->rgvarg[0]);
// store in the map
propertymap[str]=copy;
if (pvarResult)
{
V_VT(pvarResult) =VT_BOOL;
V_BOOL(pvarResult)=TRUE;
}
return S_OK;
}
return DISP_E_MEMBERNOTFOUND;
}