18.04.2015 Views

ArcGIS Engine Developer Guide

ArcGIS Engine Developer Guide

ArcGIS Engine Developer Guide

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

VISUAL C++<br />

Event circular reference issues<br />

After a sink has performed an advise on the source, there is typically a COM<br />

circular reference. This occurs because the source has an interface pointer to a<br />

sink to fire events, and this keeps the sink alive. Similarly, a sink object has a<br />

pointer back to the source so it can perform the unadvise at a later point. This<br />

keeps the source alive. Therefore, these two objects will never be released and<br />

may cause substantial memory leaks. There are a number of ways to tackle this<br />

issue:<br />

• Ensure the advise and unadvise are made on a method or Windows message<br />

that is guaranteed to happen in pairs and is independent of an object’s life<br />

cycle. For example, in a coclass that is also receiving Windows messages, use<br />

the Windows messages OnCreate (WM_CREATE) and OnDestroy<br />

(WM_DESTROY) to advise and unadvise.<br />

• If an ATL dialog box class needs to listen to events, one approach is to make<br />

the dialog box a private COM class and implement the events interface directly<br />

on the dialog box. ATL allows this without much extra coding. This<br />

approach is illustrated below. The dialog box class creates a CustomizeDialog<br />

coclass and listens to ICustomizeDialogEvents. The OnInitDialog and OnDestroy<br />

methods (corresponding to Windows messages) are used to advise and<br />

unadvise on CustomizeDialog.<br />

class C<strong>Engine</strong>ControlsDlg :<br />

public CAxDialogImpl,<br />

public CComObjectRoot, // Make Dialog Class a COM Object as well.<br />

public ICustomizeDialogEvents // Implement this interface directly on<br />

this object.<br />

C<strong>Engine</strong>ControlsDlg() : m_dwCustDlgCookie(0) {} // Initialize cookie for<br />

event listening.<br />

// ... Event handlers and other standard dialog code has been removed ...<br />

BEGIN_COM_MAP(C<strong>Engine</strong>ControlsDlg)<br />

COM_INTERFACE_ENTRY(ICustomizeDialogEvents) // Make sure QI works for<br />

this event interface.<br />

END_COM_MAP()<br />

// ICustomizeDialogEvents implementation to receive events on this<br />

dialog box.<br />

STDMETHOD(OnStartDialog)();<br />

STDMETHOD(OnCloseDialog)();<br />

ICustomizeDialogPtr m_ipCustomizeDialog; // The source of events<br />

DWORD m_dwCustDlgCookie; // Cookie for<br />

CustomizeDialogEvents.<br />

}<br />

The dialog box needs to be created like a noncreatable COM object, rather<br />

than on the stack as a local variable. This allocates the object on the heap and<br />

allows it to be released through the COM reference counting mechanism.<br />

Chapter 4 • <strong>Developer</strong> environments • 139

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!