Step 4: Adding a Custom Event to The ActiveX Control

This step demonstrates how to add a custom event (PointerPosition) to the ActiveX control. Each time the user moves the mouse pointer, the member function handleEvent of the view interactor will fire this event and send it to the container. This event has three parameters:

  • A BSTR parameter, which represents the name of the object underneath the mouse, if any.

  • OLE_XPOS_PIXELS and OLE_YPOS_PIXELS parameters, which represent the position of the mouse relative to the IlvManagerView.

You are going to:

Define the new custom event.

  1. In the ClassView tab of the Project Workspace window, click the DemoATLLib to expand its content and then click the _IDemoATLCtrlEvents interface with the right mouse button.

  2. Choose Add > Add Function from the menu that appears.

  3. In the dialog box, enter the following values: HRESULT as the Return Type, PointerPosition as the Method Name, and BSTR name, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y as the parameters.

Compile the file DemoATL.idl or rebuild your project.

Implement a connection point interface.

  1. In the ClassView tab of the Project Workspace window, click the class CDemoATLCtrl with the right mouse button.

  2. Choose Add > Add Connection Point from the menu that appears.

  3. In the Implement connection points, select the _IDemoATLCtrlEvents interface and click OK.

Check the parameter of the CONNECTION_POINT_ENTRY macro.

  1. Open DemoATLCtrl.h and replace the 2 occurrences of __uuidof(_IDemoATLCtrlEvents)

    by

    DIID__IDemoATLCtrlEvents

  2. In the ClassView tab of the Project Workspace window, click the class Cproxy_IDemoATLCtrlEvents<T> with the right mouse button.

  3. Choose Go To Definition from the menu that appears.

    The _DemoATLCtrlEvents_CP.h file gets open.

  4. Replace

    &__uuidof(_IDemoATLCtrlEvents)

    by

    &DIID__IDemoATLCtrlEvents

Modify the constructor of the class DemoCtrl.

Modify this constructor so that it accepts a reference to the class CDemoATLCtrl as its second parameter. Add a forward declaration for the class CDemoATLCtrl to the file DemoCtrl.h and include the files stdafx.h and DemoATLCtrl.h into the file DemoCtrl.cpp.

Note

You must include these files before the Views header files because, although both Views and the ATL force the definition of the STRICT macro, ATL does not check whether the macro is already defined.

Modify the member function CDemoATLCtrl::onCreate.

In the member function CDemoATLCtrl::OnCreate (file DemoATLCtrl.h), add *this as the second parameter to the call to the DemoCtrl constructor.

Define the class TrackInteractor.

In the file DemoCtrl.cpp, define a new class TrackInteractor deriving from IlvViewManagerInteractor:

class TrackInteractor : public IlvManagerViewInteractor

{

public:

TrackInteractor(IlvManager* m, IlvView* v, CDemoATLCtrl& ATLCtrl)

: IlvManagerViewInteractor(m, v), m_ATLCtrl(ATLCtrl)

{

}

~TrackInteractor() {}

        IlBoolean handleEvent(IlvEvent& event)

{

IlBoolean consumed = ilFalse;

if (event.getType() == IlvPointerMoved) {

consumed = IlTrue;

IlvGraphic* obj =

getManager()->lastContains(IlvPoint(event.x(), event.y()),

getView());

CComBSTR bstrName("");

if (obj) {

const char* name = getManager()->getObjectName(obj);

bstrName = name;

}

m_ATLCtrl.Fire_PointerPosition(bstrName.Detach(),

OLE_XPOS_PIXELS(event.x()),

OLE_XPOS_PIXELS(event.y()));

}

if (!getManager()->dispatchToObjects(event, getView())) {

consumed |= getManager()->shortCut(event, getView());

} else {

consumed = IlTrue;

}

return consumed;

}

private:

CDemoATLCtrl& m_ATLCtrl;

};

Implement the Fire_PointerPosition function.

  1. In the ClassView tab of the Project Workspace window, click the class Cproxy_IDemoATLCtrlEvents<T> with the right mouse button.

  2. Add the Fire_PointerPosition public function to the Cproxy_IDemoATLCtrlEvents class.

HRESULT Fire_PointerPosition(BSTR name, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y)

{

CComVariant varResult;

T* pT = static_cast<T*>(this);

int nConnectionIndex;

CComVariant* pvars = new CComVariant[3];

int nConnections = m_vec.GetSize();

 

for (nConnectionIndex = 0; nConnectionIndex < nConnections;

                                       nConnectionIndex++)

{

pT->Lock();

CComPtr<IUnknown> sp =

m_vec.GetAt(nConnectionIndex);

pT->Unlock();

IDispatch* pDispatch =

reinterpret_cast<IDispatch*>(sp.p);

if (pDispatch != NULL)

{

VariantClear(&varResult);

pvars[2] = name;

pvars[1] = x;

pvars[0] = y;

DISPPARAMS disp = { pvars, NULL, 3, 0 };

pDispatch->Invoke(0x1, IID_NULL,

                           LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp,

                           &varResult, NULL, NULL);

}

}

delete[] pvars;

return varResult.scode;

}

Add the private m_Inter variable to the DemoCtrl class.

The m_Inter variable must be of the type TrackInteractor*.

To add this variable you can use the wizard as explained in Step 3: Adding Custom Properties to the ActiveX Control. Do not forget to include a forward declaration for the TrackInteractor class in the DemoCtrl.h file.

Initialize the m_Inter to the DemoCtrl constructor and attach it to the view through the manager.

DemoCtrl::DemoCtrl(HWND hWnd, CDemoATLCtrl& ATLCtrl)

: Ctrl(_Display, reinterpret_cast<IlvSystemView>(hWnd)), m_Inter(0)

{

m_Inter = new TrackInteractor(getManager(), getManagerView(), ATLCtrl);

getManager()->setInteractor(m_Inter, getManagerView());

}

Modify the destructor to delete the interactor stored in m_Inter.

DemoCtrl::~DemoCtrl()

{

if (m_Inter) {

getManager()->setInteractor(0, getManagerView());

delete m_Inter;

m_Inter = 0;

}

 

}

Test the properties.

To test the properties, you can use Internet Explorer. With Internet Explorer, you can modify the file DemoATLCtrl.html to use the VBScript language.

The function DemoATLCtrl_PointerPosition is called each time a PointerPosition event is fired. It displays the coordinates of the object which the mouse is over, if any, and its name, if defined:

<HTML>

<HEAD>

<TITLE>ATL 3.0 test page for object DemoATLCtrl</TITLE>

</HEAD>

 

<SCRIPT LANGUAGE = "javascript">

 

<!--

function load(value)

{

DemoATLCtrl.FileName = value;

}

 

-->

</SCRIPT>

 

<SCRIPT LANGUAGE = "VBScript">

 

<!--

Sub DemoATLCtrl_PointerPosition(name, x, y)

text1.innerText = name & " (" & x & ", " & y & ")"

End Sub

 

-->

</SCRIPT>

 

<BODY>

 

<SELECT NAME=Files onchange = "load(value)" >

<OPTION Selected Value="data/browse.ilv">World

<OPTION Value="europe.ilv"> Europe

<OPTION Value="africa.ilv"> Africa

</SELECT>

 

<P>

<OBJECT WIDTH=400 HEIGHT=400 ID="DemoATLCtrl" CLASSID="CLSID:3B10417D-3E6C-

11D3-B74F-00C04F68A89D"></OBJECT>

<P>

 

<INPUT id=text1 name=text1>

</P>

 

</BODY>

 

</HTML>

 

Note

Since the class id is generated, the class id in your file may be different from the one in this example.