Download the demo application - 46 Kb
Introduction
This article shows you how can use an ATL-control with MFC. I've
received a lot of e-mail with the question how you can use the
FileMonitor-control with MFC. The example I'm using is a simple MFC-dialog
based program that notifies the user when there are files created,
modified or deleted in the temporary-file directory.
Step 1: Create a MFC-dialog program.
- Create a new project. Select MFC(exe) program in the AppWizard.
Accept all the defaults. It's not necessary to select automation.
Step 2: Add a sink-object.
To receive events from an ATL-control you have to create an ATL-object
that links with the control. This object is called a sink-object.
- Select Insert / Insert New ATL Object.
- Click 'Yes' on the following question:
- Select a single object
- Use FileMonitorSink as Short Name of the object. Don't change the
other fields.
Accept the default in the Attributes tab.
Step 3: Change the OBJECT-map.
Step 4: Import the type-library of FileMonitor
By importing the type-library (the .tlb file), the content of the
type-library is converted to C++ classes, mostly describing the
interfaces. This makes it easy for us to use the interfaces of the
FileMonitor-control.
For more information on #import see your MSDN library. If you don't
want to use namespaces you could add the parameter
no_namespace to the statement. I like the use of
namespaces, so I don't use no_namespaces.
Step 5: Finishing the code for the FileMonitorSink object.
Select the headerfile of the FileMonitorSink. In our example this is
FileMonitorSink.h
- Derive your class from
public IDispEventImpl<1, CFileMonitorSink,
&FILEMONITOR::DIID__IWatchEvents, &FILEMONITOR::LIBID_FILEMONITOR, 1, 0>
The first parameter is an ID. You use this also in the SINK-map.
- Add the following to the COM-map
COM_INTERFACE_ENTRY_IID(FILEMONITOR::DIID__IWatchEvents, IDispatch)
- Create a Sink map
BEGIN_SINK_MAP(CFileMonitorSink)
SINK_ENTRY_EX(1, FILEMONITOR::DIID__IWatchEvents, 1, OnNotify)
END_SINK_MAP()
The Filemonitor sends an event Notify with a BSTR parameter and an
integer parameter. The first parameter is the ID we've used in the
IDispEventImpl. The third parameter is the DISDIP of the method in the
interface IWatchEvents.
- Add the OnNotify() method to your class
void __stdcall OnNotify(BSTR sPathName, short nType)
{
AFX_MANAGE_STATE(AfxGetAppModuleState())
MessageBox(NULL, _T("File notification"), _T("FileMonitorApp"), MB_OK);
}
Note the use of AFX_MANAGE_STATE
macro. You have to use this in every
method of this class. See for more information about this in step 7. At
the moment we use a MessageBox
to notify us when the sink-interface
receives an event. At a later time we will change that code.
Step 6: Change the Application.
Select the headerfile which define the dialog. In our example this is
TempMonitorDlg.h.
- Add a member which contains a pointer to the
IWatch
interface of the
FileMonitor control
CComPtr<FILEMONITOR::IWatch> m_FileMonitor;
- Add a member which is a COM-object of the sink interface.
CComObject<CFileMonitorSink> *m_FileMonitorSink;
- Add the following code to the OnInitDialog-method
m_FileMonitor.CoCreateInstance(__uuidof(FILEMONITOR::Watch), NULL, CLSCTX_INPROC_SERVER);
CComObject<CFileMonitorSink>::CreateInstance(&m_FileMonitorSink);
Step 7: Link the Sink-interface to the FileMonitor-control.
Before we can receive events from the FileMonitor, we've to link the
Sink-interface to the FileMonitor-control. This is also called Advising.
Because we've implemented IDispEventImpl in the sink object, we can use
the method DispEventAdvise.
The first parameter is the object we want to advise.
The second parameter will notify us if the advise succeeded or not. This
method will be used to advise the FileMonitor.
This is the code
for the Start-method:
STDMETHODIMP CFileMonitorSink::Start(IUnknown *pSinkThisObject, VARIANT_BOOL *succeeded)
{
AFX_MANAGE_STATE(AfxGetAppModuleState())
if ( DispEventAdvise(pSinkThisObject) == S_OK)
{
m_Object = pSinkThisObject;
*succeeded = VARIANT_TRUE;
}
else
{
*succeeded = VARIANT_FALSE;
}
return S_OK;
}
A Note about the AFX_MANAGE_STATE()
macro. Visual C++
generates the wrong code for it. You have to change
AFX_MANAGE_STATE(AfxGetStaticModuleState())
to the code above. This is a
bug in Visual C++. Check this every time you add a method to an
ATL-object in a MFC application. You can read more about this in the Q231592
article of Microsoft.
Step 8: Start the sinking of the FileMonitor events.
- Change the
OnInitDialog
method after the creation of the
sink-object.
VARIANT_BOOL succeeded;
m_FileMonitorSink->Start(m_FileMonitor, &succeeded);
- Handle the WM_DESTROY-message as follows:
void CTempMonitorDlg::OnDestroy()
{
CDialog::OnDestroy();
m_FileMonitorSink->Stop();
}
Step 9: Add the code for monitoring the temporary file directory.
Step 10: Compile and run the first test.
- When the program is running, then try to change, delete or create a
file in the temporary directory. On my system this was the
C:\Windows\Temp. You should see the messagebox, when you do this.
Step 11: Finishing our application.
Note : If you find another way which is better than
this, please notify me. I've
created this example with lots of information I've find on the internet
and in the "Professional ATL COM" Programming book.
License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here