The custom event we add to control.ocx will be called posEvent, and we will fire this event when the mouse button goes down, passing the location of the mouse button to the handling function. (posEvent stands for position event.)
Open ClassWizard and select the OLE Events tab. Make sure that the control class, CControlCtrl, is selected in the Class Name box and click Add Event, opening the Add Event box as shown in Figure 9.13.
Figure 9.13 We add a custom event to our control.
Type posEvent into the External Name box, as shown in Figure 9.13, and type x in the Parameter List box. A drop-down listbox appears on the right side of the Parameter List box; select OLE_XPOS_PIXELS as the x parameter's type. Now enter a new parameter (y) in the Parameter List box and select the OLE_YPOS_PIXELS type for it. The result appears in Figure 9.13. Close the Add Event box by clicking OK, adding the new posEvent event to the control. Click OK in ClassWizard.
ClassWizard has connected the posEvent event to a function to fire that event. FirePosEvent() is set up this way in CONTROLCTL.CPP:
// Event maps
//{{AFX_EVENT(CControlCtrl)
void FirePosEvent(OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y)
{FireEvent(eventidPosEvent,EVENT_PARAM(VTS_XPOS_PIXELS
VTS_YPOS_PIXELS), x, y);}
//}}AFX_EVENT
DECLARE_EVENT_MAP()
To fire this event, then, we need only call FirePosEvent(). We fire the new event each time the mouse button is pressed, so we call FirePosEvent() in the OnLButtonDown() function (from CONTROLCTL.CPP):
void CControlCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
COleControl::OnLButtonDown(nFlags, point);
m_counter++;
--> FirePosEvent(point.x, point.y);
}
Here, we fire a posEvent on event mouse click, and we pass the mouse position to this event. To test this event in the test container, we watch as the custom events are fired. Create control.ocx and insert a control of that type into the test container. Next, select Event Log in the test container's View menu, opening the event log as shown in Figure 9.14.
Figure 9.14 We see our custom event fired in control.ocx.
When you click the CONTROL button, the program fires a posEvent event, and the results appear in the event log, as shown in Figure 10.14. Also, the x and y mouse location inside the control (measured in pixels) is also passed to this event handler.
Now let's see this in VBScript. Let's add a textbox to our Web page so that we can display the current value of the control's Counter property:
-----------------------------------------------
| |
| |
| -------------- |
| | | -------------- |
| | OCX Control | | Counter = 8 | |
| | | -------------- |
| -------------- |
| |
| |
| |
| |
-----------------------------------------------
In the Web page itself, we connect control.ocx's posEvent event to the subroutine Ctrl1_posEvent(x, y) (our new control has the ID Ctrl1):
<HTML>
<HEAD>
<TITLE>Control Page</TITLE>
</HEAD>
<BODY LANGUAGE = VBScript ONLOAD = "Page_Initialize">
<CENTER>
<H1>Control Page</H1>
</CENTER>
<!- control.ocx>
<CENTER>
<OBJECT CLASSID="clsid:D96FBCC1-090A-101C-BAC7-040224009C02"
HEIGHT=80 WIDTH=100 ID=Ctrl1></OBJECT>
<INPUT TYPE = TEXT NAME = Textbox SIZE=20>
</CENTER>
<SCRIPT LANGUAGE = VBScript>
Sub Page_Initialize
Ctrl1.Beep()
Ctrl1.Counter = 5
End Sub
--> Sub Ctrl1_posEvent(x, y)
--> Textbox.Value = "Counter = " + CStr(Ctrl1.Counter)
--> End Sub
</SCRIPT>
</BODY>
</HTML>
Here, we increment the value in the control's Counter property by repeatedly clicking the control. The result appears in Figure 9.15.
Figure 9.15 Our new OCX control at work.
That's it—control.ocx is a complete success. The files CONTROL.H and CONTROL.CPP can found in Listing 9.4. CONTROLCTL.H and CONTROLCTL.CPP are in Listing 9.5, and CONTROL.ODL is in Listing 9.6.
Listing 9.4 CONTROL.H and CONTROL.CPP
// control.h : main header file for CONTROL.DLL
#if !defined( __AFXCTL_H__ )
#error include ‘afxctl.h' before including this file
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CControlApp : See control.cpp for implementation.
class CControlApp : public COleControlModule
{
public:
BOOL InitInstance();
int ExitInstance();
};
extern const GUID CDECL _tlid;
extern const WORD _wVerMajor;
extern const WORD _wVerMinor;
// control.cpp : Implementation of CControlApp and DLL registration.
#include "stdafx.h"
#include "control.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CControlApp NEAR theApp;
const GUID CDECL BASED_CODE _tlid =
{ 0x1dd8502f, 0x3ade, 0x11cf, { 0xb0, 0x1d, 0x92, 0x66,
0x8f, 0xc, 0xf4, 0x47 } };
const WORD _wVerMajor = 1;
const WORD _wVerMinor = 0;
////////////////////////////////////////////////////////////////////////////
// CControlApp::InitInstance - DLL initialization
BOOL CControlApp::InitInstance()
{
BOOL bInit = COleControlModule::InitInstance();
if (bInit)
{
// TODO: Add your own module initialization code here.
}
return bInit;
}
////////////////////////////////////////////////////////////////////////////
// CControlApp::ExitInstance - DLL termination
int CControlApp::ExitInstance()
{
// TODO: Add your own module termination code here.
return COleControlModule::ExitInstance();
}
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
Listing 9.5 CONTROLCTL.H and CONTROLCTL.CPP
// ControlCtl.h : Declaration of the CControlCtrl OLE control class.
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl : See ControlCtl.cpp for implementation.
class CControlCtrl : public COleControl
{
DECLARE_DYNCREATE(CControlCtrl)
// Constructor
public:
CControlCtrl();
// Overrides
// Drawing function
virtual void OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
// Persistence
virtual void DoPropExchange(CPropExchange* pPX);
// Reset control state
virtual void OnResetState();
// Implementation
protected:
~CControlCtrl();
DECLARE_OLECREATE_EX(CControlCtrl) // Class factory and guid
DECLARE_OLETYPELIB(CControlCtrl) // GetTypeInfo
DECLARE_PROPPAGEIDS(CControlCtrl) // Property page IDs
DECLARE_OLECTLTYPE(CControlCtrl) // Type name and misc status
// Subclassed control support
BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL IsSubclassedControl();
LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam);
LRESULT OnOcmDrawItem(WPARAM wParam, LPARAM lParam);
// Message maps
//{{AFX_MSG(CControlCtrl)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
// Dispatch maps
//{{AFX_DISPATCH(CControlCtrl)
short m_counter;
afx_msg void OnCounterChanged();
afx_msg void Beep();
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
afx_msg void AboutBox();
// Event maps
//{{AFX_EVENT(CControlCtrl)
void FirePosEvent(OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y)
{FireEvent(eventidPosEvent,EVENT_PARAM(VTS_XPOS_PIXELS
VTS_YPOS_PIXELS), x, y);}
//}}AFX_EVENT
DECLARE_EVENT_MAP()
// Dispatch and event IDs
public:
enum {
//{{AFX_DISP_ID(CControlCtrl)
dispidCounter = 1L,
dispidBeep = 2L,
eventidPosEvent = 1L,
//}}AFX_DISP_ID
};
};
// ControlCtl.cpp : Implementation of the CControlCtrl OLE control class.
#include "stdafx.h"
#include "control.h"
#include "ControlCtl.h"
#include "ControlPpg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CControlCtrl, COleControl)
/////////////////////////////////////////////////////////////////////////////
// Message map
BEGIN_MESSAGE_MAP(CControlCtrl, COleControl)
//{{AFX_MSG_MAP(CControlCtrl)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
ON_MESSAGE(OCM_DRAWITEM, OnOcmDrawItem)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Dispatch map
BEGIN_DISPATCH_MAP(CControlCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CControlCtrl)
DISP_PROPERTY_NOTIFY(CControlCtrl, "Counter", m_counter,
OnCounterChanged, VT_I2)
DISP_FUNCTION(CControlCtrl, "Beep", Beep, VT_EMPTY, VTS_NONE)
//}}AFX_DISPATCH_MAP
DISP_FUNCTION_ID(CControlCtrl, "AboutBox", DISPID_ABOUTBOX,
AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()
/////////////////////////////////////////////////////////////////////////////
// Event map
BEGIN_EVENT_MAP(CControlCtrl, COleControl)
//{{AFX_EVENT_MAP(CControlCtrl)
EVENT_CUSTOM("posEvent", FirePosEvent, VTS_XPOS_PIXELS VTS_YPOS_PIXELS)
//}}AFX_EVENT_MAP
END_EVENT_MAP()
/////////////////////////////////////////////////////////////////////////////
// Property pages
// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CControlCtrl, 1)
PROPPAGEID(CControlPropPage::guid)
END_PROPPAGEIDS(CControlCtrl)
/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CControlCtrl, "CONTROL.ControlCtrl.1",
0xd96fbcc1, 0x90a, 0x101c, 0xba, 0xc7, 0x4, 0x2, 0x24, 0, 0x9c, 0x2)
/////////////////////////////////////////////////////////////////////////////
// Type library ID and version
IMPLEMENT_OLETYPELIB(CControlCtrl, _tlid, _wVerMajor, _wVerMinor)
/////////////////////////////////////////////////////////////////////////////
// Interface IDs
const IID BASED_CODE IID_DControl =
{ 0x1dd85030, 0x3ade, 0x11cf, { 0xb0, 0x1d, 0x92, 0x66,
0x8f, 0xc, 0xf4, 0x47 } };
const IID BASED_CODE IID_DControlEvents =
{ 0x1dd85031, 0x3ade, 0x11cf, { 0xb0, 0x1d, 0x92, 0x66,
0x8f, 0xc, 0xf4, 0x47 } };
/////////////////////////////////////////////////////////////////////////////
// Control type information
static const DWORD BASED_CODE _dwControlOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;
IMPLEMENT_OLECTLTYPE(CControlCtrl, IDS_CONTROL, _dwControlOleMisc)
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::CControlCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CControlCtrl
BOOL CControlCtrl::CControlCtrlFactory::UpdateRegistry(BOOL bRegister)
{
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_CONTROL,
IDB_CONTROL,
FALSE, // Not insertable
_dwControlOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::CControlCtrl - Constructor
CControlCtrl::CControlCtrl()
{
InitializeIIDs(&IID_DControl, &IID_DControlEvents);
// TODO: Initialize your control's instance data here.
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::~CControlCtrl - Destructor
CControlCtrl::~CControlCtrl()
{
// TODO: Cleanup your control's instance data here.
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::OnDraw - Drawing function
void CControlCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
DoSuperclassPaint(pdc, rcBounds);
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::DoPropExchange - Persistence support
void CControlCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
PX_Short(pPX, _T("Counter"), m_counter, 0);
// TODO: Call PX_ functions for each persistent custom property.
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::OnResetState - Reset control to default state
void CControlCtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults in DoPropExchange
// TODO: Reset any other control state here.
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::AboutBox - Display an "About" box to the user
void CControlCtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_CONTROL);
dlgAbout.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
BOOL CControlCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = _T("BUTTON");
cs.style |= BS_PUSHBUTTON | BS_OWNERDRAW;
return COleControl::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::IsSubclassedControl - This is a subclassed control
BOOL CControlCtrl::IsSubclassedControl()
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl::OnOcmCommand - Handle command messages
LRESULT CControlCtrl::OnOcmCommand(WPARAM wParam, LPARAM lParam)
{
#ifdef _WIN32
WORD wNotifyCode = HIWORD(wParam);
#else
WORD wNotifyCode = HIWORD(lParam);
#endif
// TODO: Switch on wNotifyCode here.
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CControlCtrl message handlers
LRESULT CControlCtrl::OnOcmDrawItem(WPARAM wParam, LPARAM lParam)
{
CDC *pdc;
CBitmap bmpObj;
BITMAP bmp;
CPictureHolder picHolderObj;
CRect rect;
pdc = CDC::FromHandle(((LPDRAWITEMSTRUCT)lParam)->hDC);
bmpObj.LoadBitmap((((LPDRAWITEMSTRUCT)lParam)->itemState &
ODS_SELECTED) ? IDB_DOWNBITMAP : IDB_UPBITMAP);
bmpObj.GetObject(sizeof(BITMAP), &bmp);
rect.right = bmp.bmWidth;
rect.bottom = bmp.bmHeight;
picHolderObj.CreateFromBitmap((HBITMAP)bmpObj.m_hObject, NULL, FALSE);
picHolderObj.Render(pdc, ((LPDRAWITEMSTRUCT)lParam)->rcItem, rect);
return 1;
}
void CControlCtrl::OnCounterChanged()
{
// TODO: Add notification handler code
SetModifiedFlag();
}
void CControlCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
m_counter++;
FirePosEvent(point.x, point.y);
COleControl::OnLButtonDown(nFlags, point);
}
void CControlCtrl::Beep()
{
MessageBeep(MB_OK);
}
Listing 9.6 CONTROL.ODL
// control.odl : type library source for OLE Control project.
// This file will be processed by the Make Type Library (mktyplib) tool to
// produce the type library (control.tlb) that will become a resource in
// control.ocx.
#include <olectl.h>
[ uuid(1DD8502F-3ADE-11CF-B01D-92668F0CF447), version(1.0),
helpstring("control OLE Control module"), control ]
library CONTROLLib
{
importlib(STDOLE_TLB);
importlib(STDTYPE_TLB);
// Primary dispatch interface for CControlCtrl
[ uuid(1DD85030-3ADE-11CF-B01D-92668F0CF447),
helpstring("Dispatch interface for Control Control"), hidden ]
dispinterface _DControl
{
properties:
// NOTE - ClassWizard will maintain property info
// Use extreme caution when editing this section.
//{{AFX_ODL_PROP(CControlCtrl)
[id(1)] short Counter;
//}}AFX_ODL_PROP
methods:
// NOTE - ClassWizard will maintain method information
// Use extreme caution when editing this section.
//{{AFX_ODL_METHOD(CControlCtrl)
[id(2)] void Beep();
//}}AFX_ODL_METHOD
[id(DISPID_ABOUTBOX)] void AboutBox();
};
// Event dispatch interface for CControlCtrl
[ uuid(1DD85031-3ADE-11CF-B01D-92668F0CF447),
helpstring("Event interface for Control Control") ]
dispinterface _DControlEvents
{
properties:
// Event interface has no properties
methods:
// NOTE - ClassWizard will maintain event information
// Use extreme caution when editing this section.
//{{AFX_ODL_EVENT(CControlCtrl)
[id(1)] void posEvent(OLE_XPOS_PIXELS x,
OLE_YPOS_PIXELS y);
//}}AFX_ODL_EVENT
};
// Class information for CControlCtrl
[ uuid(D96FBCC1-090A-101C-BAC7-040224009C02),
helpstring("Control Control"), control ]
coclass Control
{
[default] dispinterface _DControl;
[default, source] dispinterface _DControlEvents;
};
//{{AFX_APPEND_ODL}}
};
That's it for our survey of custom controls, and that's it for our survey of VBScript. We've come far in this book: from the basics of Web pages to the basics of VBScript and beyond. We've discussed how to implement buttons and textboxes and forms and documents and many other types of controls and objects, including the creation of your own controls for use with VBScript. All that remains now is to put all this technology to work for yourself. Happy programming.