Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2. The Excel version is Excel 2003/Office 11. Topics and sub topics for this tutorial are listed below. Don’t forget to read Tenouk’s small disclaimer. The supplementary notes for this tutorial are automation, variant and COlevariant class.
The MYMFC29E Automation Client Example
This program uses the new #import directive to generate smart pointers. It behaves just like MYMFC29D except that it doesn't run Excel. The #import statements are in the StdAfx.h file to minimize the number of times the compiler has to generate the driver classes.
The MYMFC29E Steps From Scratch
As usual start with AppWizard, just follow the shown steps and option settings. These monotonous steps provide a very good practice for you!
Figure 1: MYMFC29E – Visual C++ new project dialog. |
|
Figure 2: MYMFC29E – AppWizard step 1 of 6, an SDI application.
Figure 3: MYMFC29E – AppWizard step 2 of 6.
Figure 4: MYMFC29E – AppWizard step 3 of 6.
Figure 5: MYMFC29E – AppWizard step 4 of 6, de-selecting the printing services.
Figure 6: MYMFC29E – AppWizard step 5 of 6.
Figure 7: MYMFC29E – AppWizard step 6 of 6.
Figure 8: MYMFC29E project summary.
Add a new dialog. Insert new dialog and use the following information for the dialog, static text and edit controls. Leave the static texts IDs to the default.
ID |
Item |
IDD_ALARMDLG |
Dialog with ‘29E Alarm Dialog’ caption |
IDC_HOURS |
Hours edit box |
IDC_MINUTES |
Minutes edit box |
IDC_SECONDS |
Seconds edit box |
Table 1. |
Figure 9: Adding new dialog and editing its property.
Next, use ClassWizard to create CAlarmDialog, a new class for the dialog.
Figure 10: Adding new class, CAlarmDialog for the dialog.
Fill in the CAlarmDialog class information.
Figure 11: Entering the CAlarmDialog class information.
Add member variables and initialize them. Click the Member Variables tab and use the following information for the variables.
ID |
Type |
Member name |
Min/Max value |
IDC_HOURS |
int |
m_nHours |
0/23 |
IDC_MINUTES |
int |
m_nMinutes |
0/59 |
IDC_SECONDS |
int |
m_nSeconds |
0/59 |
Table 2. |
Figure 12: Adding member variables to controls in dialog.
Add menu items for Bank Comp.
ID |
Menu |
Prompt |
ID_BANKOLE_LOAD |
Load |
Load the bank component, MYMFC29A.EXE |
ID_BANKOLE_TEST |
Test |
Test the bank component |
ID_BANKOLE_UNLOAD |
Unload |
Unload the bank component |
Table 3. |
Figure 13: Adding Bank Comp menu and its’ items.
Add menu items for DLL Comp.
ID |
Menu |
Prompt |
ID_DLLOLE_LOAD |
Load |
Load the DLL component, MYMFC29B.DLL |
ID_DLLOLE_GETDATA |
Get Data |
Get data from the DLL component |
ID_DLLOLE_UNLOAD |
Unload |
Unload the DLL component |
Table 4. |
Figure 14: Adding DLL Comp menu and its’ items.
Add menu items for Clock Comp.
ID |
Menu |
Prompt |
ID_CLOCKOLE_LOAD |
Load |
Load the clock component, MYMFC29C.EXE |
ID_CLOCKOLE_CREATEALARM |
Create Alarm |
Create an alarm |
ID_CLOCKOLE_REFRESHTIME |
Refresh Time |
Refresh the time from the system clock |
ID_CLOCKOLE_UNLOAD |
Unload |
Unload the clock component |
Table 5. |
Figure 15: Adding Clock Comp menu and its’ items.
Next, Using ClassWizard, add the menu commands and update command UI events in the CMymfc29EView class for all the menu items created previously.
|
Figure 16: Adding menu Commands and Update Commands to CMymfc29EView class.
The Coding Part
Add the automation support manually. Add the following code in StdAfx.h.
#include <afxdisp.h>
Listing 1.
Then add this call at the beginning of the application's InitInstance() function in mymfc29D.cpp.
AfxOleInit();
Listing 2.
Back to StdAfx.h and add the following #import directives. you should change the path accordingly to suit your project directory. For Tenouk, all Visual C++ project is under F:\mfcproject directory.
#import "..\mymfc29A\debug\mymfc29A.tlb" rename_namespace("BankDriv")
using namespace BankDriv;
#import "..\mymfc29B\debug\mymfc29B.tlb" rename_namespace("Mymfc29BDriv")
using namespace Mymfc29BDriv;
#import "..\mymfc29C\debug\mymfc29C.tlb" rename_namespace("ClockDriv")
using namespace ClockDriv;
Listing 3.
Add the following embedded smart pointers in the CMymfc29EView class header, mymfc29EView.h.
public:
IMymfc29BAutoPtr m_auto;
IBankPtr m_bank;
IMymfc29CPtr m_clock;
IAlarmPtr m_alarm;
Listing 4.
Add the #include directive for AlarmDialog.h in the CMymfc29EView class implementation, mymfc29EView.cpp. If you rebuild your ClassWizard database, this step is unnecessary.
#include "AlarmDialog.h"
Listing 5.
Add code for CMymfc29DView::OnDraw() member function in mymfc29EView.cpp.
void CMymfc29EView::OnDraw(CDC* pDC)
{
CMymfc29EDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(100, 0, "--COleDispatchDriver usage, mymfc29E--");
pDC->TextOut(10, 25, "Run this program from the debugger to see test output.");
pDC->TextOut(10, 50, "The MYMFC29A, MYMFC29B and MYMFC29C components...");
pDC->TextOut(10, 75, "...must be built and registered prior to loading this crap...");
pDC->TextOut(10, 100, "Originally for VC++ 6 + Excel 97 but here VC++ 6 + Excel 2003...");
}
Listing 6.
Finally, add codes for the commands and update command UI events of the CMymfc29EView class.
void CMymfc29EView::OnBankoleLoad()
{
if(m_bank.CreateInstance(__uuidof(Bank)) != S_OK)
{
AfxMessageBox("Bank component not found");
return;
}
else
{ AfxMessageBox("OK, Bank component found lor!"); }
}
void CMymfc29EView::OnUpdateBankoleLoad(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_bank.GetInterfacePtr() == NULL); }
void CMymfc29EView::OnBankoleTest()
{
try {
m_bank->Deposit(20.0);
m_bank->Withdrawal(15.0);
TRACE("new balance = %f\n", m_bank->GetBalance());
}
catch(_com_error& e)
{ AfxMessageBox(e.ErrorMessage()); }
}
Listing 7.
void CMymfc29EView::OnUpdateBankoleTest(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_bank.GetInterfacePtr() != NULL); }
void CMymfc29EView::OnBankoleUnload()
{ m_bank.Release(); }
void CMymfc29EView::OnUpdateBankoleUnload(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_bank.GetInterfacePtr() != NULL); }
void CMymfc29EView::OnClockoleCreatealarm()
{
CAlarmDialog dlg;
try
{
if (dlg.DoModal() == IDOK)
{
COleDateTime dt(2004, 12, 23, dlg.m_nHours, dlg.m_nMinutes, dlg.m_nSeconds);
LPDISPATCH pAlarm = m_clock->CreateAlarm(dt);
m_alarm.Attach((IAlarm*) pAlarm); // releases prior object!
m_clock->RefreshWin();
}
}
catch(_com_error& e)
{ AfxMessageBox(e.ErrorMessage()); }
}
Listing 8.
void CMymfc29EView::OnUpdateClockoleCreatealarm(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_clock.GetInterfacePtr() != NULL); }
void CMymfc29EView::OnClockoleLoad()
{
if(m_clock.CreateInstance(__uuidof(Document)) != S_OK)
{
AfxMessageBox("Clock component not found");
return;
}
try
{
m_clock->PutFigure(0, COleVariant("XII"));
m_clock->PutFigure(1, COleVariant("III"));
m_clock->PutFigure(2, COleVariant("VI"));
m_clock->PutFigure(3, COleVariant("IX"));
OnClockoleRefreshtime();
m_clock->ShowWin();
}
catch(_com_error& e)
{ AfxMessageBox(e.ErrorMessage()); }
}
void CMymfc29EView::OnUpdateClockoleLoad(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_clock.GetInterfacePtr() == NULL); }
Listing 9.
void CMymfc29EView::OnClockoleRefreshtime()
{
COleDateTime now = COleDateTime::GetCurrentTime();
try
{
m_clock->PutTime(now);
m_clock->RefreshWin();
}
catch(_com_error& e)
{ AfxMessageBox(e.ErrorMessage()); }
}
void CMymfc29EView::OnUpdateClockoleRefreshtime(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_clock.GetInterfacePtr() != NULL); }
void CMymfc29EView::OnClockoleUnload()
{ m_clock.Release(); }
void CMymfc29EView::OnUpdateClockoleUnload(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_clock.GetInterfacePtr() != NULL); }
Listing 10.
void CMymfc29EView::OnDlloleGetdata()
{
try {
m_auto->DisplayDialog();
COleVariant vaData = m_auto->GetTextData();
ASSERT(vaData.vt == VT_BSTR);
CString strTextData = vaData.bstrVal;
long lData = m_auto->GetLongData();
TRACE("CMymfc29DView::OnDlloleGetdata-long = %ld, text = %s\n", lData, strTextData);
}
catch(_com_error& e)
{ AfxMessageBox(e.ErrorMessage()); }
}
void CMymfc29EView::OnUpdateDlloleGetdata(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_auto.GetInterfacePtr() != NULL); }
Listing 11.
void CMymfc29EView::OnDlloleLoad()
{
if(m_auto.CreateInstance(__uuidof(Auto)) != S_OK)
{
AfxMessageBox("Mymfc29BAuto component not found");
return;
}
else
{ AfxMessageBox("Mymfc29BAuto component found lol!"); }
}
void CMymfc29EView::OnUpdateDlloleLoad(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_auto.GetInterfacePtr() == NULL); }
void CMymfc29EView::OnDlloleUnload()
{ m_auto.Release(); }
void CMymfc29EView::OnUpdateDlloleUnload(CCmdUI* pCmdUI)
{ pCmdUI->Enable(m_auto.GetInterfacePtr() != NULL); }
Listing 12.
Check your ClassView for the added classes and the member functions.
Figure 17: The added classes seen through ClassView.
Further reading and digging:
Win32 process, thread and synchronization story can be found starting from Module R.
MSDN What's New (MFC Feature Pack) - feature pack.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Unicode and Multi-byte character set: Story and program examples.