| Tenouk C & C++ | MFC Home | Automation 10 | Automation 12 | Download | Site Index |


 

 

 

 

 

 

Automation 11

 

 

 

 

 

 

 

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.

  1. The Story - Type Libraries and ODL Files

  2. The Controller Class for mymfc29A.exe

  3. The Controller Class for mymfc29B.dll

  4. The Controller Class for mymfc29C.exe

  5. Controlling Microsoft Excel

 

 

Let play around with our program. Make sure you have already build/run/registered the MYMFC29A, MYMFC29B and MYMFC29C components in order to test MYMFC29D program. Build and run MYMFC29D, the output is shown below. Test all the components through the menu items.

 

 

Figure 52: MYMFC29D output.

 

Figure 52: MYMFC29D output.

 

Figure 53: MYMFC29D – testing the Bank Comp Load menu.

 

Figure 53: MYMFC29D – testing the Bank Comp Load menu.

 

Figure 54: MYMFC29D – testing the DLL Comp Load menu.

 

Figure 54: MYMFC29D – testing the DLL Comp Load menu.

 

Figure 55: MYMFC29D – testing the Clock Comp Load menu.

 

Figure 55: MYMFC29D – testing the Clock Comp Load menu.

 

Figure 56: MYMFC29D – testing the Clock Comp Create Alarm menu. Enter the alarm values.

 

Figure 56: MYMFC29D – testing the Clock Comp Create Alarm menu. Enter the alarm values.

 

Figure 57: MYMFC29D – the alarm was set.

 

Figure 57: MYMFC29D – the alarm was set.

 

Figure 58: MYMFC29D – testing the Clock Comp Unload menu, unloading the clock.

 

Figure 58: MYMFC29D – testing the Clock Comp Unload menu, unloading the clock.

 

Figure 59: MYMFC29D – testing the Excel Comp Load menu.

 

Figure 59: MYMFC29D – testing the Excel Comp Load menu.

 

Figure 60: Viewing the loaded Excel processes using SPY++.

 

Figure 60: Viewing the loaded Excel processes using SPY++.

 

Figure 61: The Excel program was loaded.

 

Figure 61: The Excel program was loaded.

 

The Story: Type Libraries and ODL Files etc.

 

We've told you that type libraries aren't necessary for the MFC IDispatch implementation, but Visual C++ has been quietly generating and updating type libraries for all your components. What good are these type libraries? VBA can use a type library to browse your component's methods and properties, and it can use the type library for improved access to properties and methods, a process called early binding described later in this module. But we're building a C++ client program here, not a VBA program. It so happens that ClassWizard can read a component's type library and use the information to generate C++ code for the client to use to "drive" an Automation component. AppWizard initializes a project's Object Description Language (ODL) file when you first create it. ClassWizard edits this file each time you generate a new Automation component class or add properties and methods to an existing class. Unlike it does with the ClassWizard (CLW) file, ClassWizard can't rebuild an ODL file from the contents of your source files. If you mess up your ODL file, you'll have to re-create it manually. When you were adding properties and methods to your component classes, ClassWizard was updating the project's ODL file. This file is a text file that describes the component in an ODL. (Your GUID will be different if you used AppWizard to generate this project.) Here's the ODL file for the bank component:

 

// Originally just a manually created odl template

 

[ uuid(40980C17-DB2B-498F-85AC-BE88F2B549CF), version(1.0) ]

library mymfc29A

{

importlib("stdole32.tlb");

importlib("stdole2.tlb");

 

//  Primary dispatch interface for CBank

 

       [ uuid(122FA935-F2E8-4EB0-B974-D0BF4C59E53D) ]

       dispinterface IBank

       {

              properties:

                     // NOTE - ClassWizard will maintain property information here.

                     //    Use extreme caution when editing this section.

                     //{{AFX_ODL_PROP(CBank)

                     [id(1)] double Balance;

                     //}}AFX_ODL_PROP

 

              methods:

                     // NOTE - ClassWizard will maintain method information here.

                     //    Use extreme caution when editing this section.

                     //{{AFX_ODL_METHOD(CBank)

                     [id(2)] double Withdrawal(double dAmount);

                     [id(3)] void Deposit(double dAmount);

                     //}}AFX_ODL_METHOD

 

       };

 

       //  Class information for CBank

       [ uuid(58E7A2CE-C23D-4A09-A1AD-E4710AE28E4D) ]

       coclass Bank

       {

              [default] dispinterface IBank;

       };

 

       //{{AFX_APPEND_ODL}}

};

 

The ODL file has a unique GUID type library identifier, 40980C17-DB2B-498F-85AC-BE88F2B549CF, and it completely describes the bank component's properties and methods under a dispinterface named IBank. In addition, it specifies the dispinterface GUID, 122FA935-F2E8-4EB0-B974-D0BF4C59E53D, which is the same GUID that's in the interface map of the CBank class. You'll see the significance of this GUID when you read the "VBA Early Binding" section near the end of this module. The CLSID, 58E7A2CE-C23D-4A09-A1AD-E4710AE28E4D, is what a VBA browser can actually use to load your component.

Anyway, when you build your component project, Visual C++ invokes the MIDL utility, which reads the ODL file and generates a binary TLB file in your project's debug or release subdirectory. Now when you develop a C++ client program, you can ask ClassWizard to generate a driver class from the component project's TLB file.

The MIDL utility generates the type library in a stand-alone TLB file, and that's what Automation controllers such as Excel look for. ActiveX controls have their type libraries bound into their resources.

To actually do this, you click the ClassWizard Add Class button and then select From A Type Library from the drop-down list. You navigate to the component project's TLB file, and then ClassWizard shows you a dialog similar to the illustration below.

 

Figure 62: The IBank class extracted from type library.

 

Figure 62: The IBank class extracted from type library.

 

IBank is the dispinterface specified in the ODL file. You can keep this name for the class if you want, and you can specify the H and CPP filenames. If a type library contains several interfaces you can make multiple selections. You'll see the generated controller classes in the sections that follow.

 

The Controller Class for mymfc29A.exe

 

ClassWizard generated the IBank class (derived from COleDispatchDriver) listed in Listing 14. Look closely at the member function implementations. Note the first parameters of the GetProperty(), SetProperty(), and InvokeHelper() function calls. These are hard-coded DISPIDs for the component's properties and methods, as determined by the component's dispatch map sequence. If you use ClassWizard to delete a property and then add the property back, you'll probably change the component's dispatch IDs. That means that you'll have to regenerate or edit the controller class so that the IDs match.

 

BANKDRIVER.H

 

// Machine generated IDispatch wrapper class(es) created with ClassWizard

/////////////////////////////////////////////////////////////////////////////

// IBank wrapper class

 

class IBank : public COleDispatchDriver

{

public:

       IBank() { }           // Calls COleDispatchDriver default constructor

       IBank(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) { }

       IBank(const IBank& dispatchSrc) : COleDispatchDriver(dispatchSrc) { }

 

// Attributes

public:

       double GetBalance();

       void SetBalance(double);

 

// Operations

public:

       double Withdrawal(double dAmount);

       void Deposit(double dAmount);

};

 

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BANKDRIVER.CPP

// Machine generated IDispatch wrapper class(es) created with ClassWizard

 

#include "stdafx.h"

#include "bankdriver.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

 

/////////////////////////////////////////////////////////////////////////////

// IBank properties

 

double IBank::GetBalance()

{

       double result;

       GetProperty(0x1, VT_R8, (void*)&result);

       return result;

}

 

void IBank::SetBalance(double propVal)

{

       SetProperty(0x1, VT_R8, propVal);

}

 

/////////////////////////////////////////////////////////////////////////////

// IBank operations

 

double IBank::Withdrawal(double dAmount)

{

       double result;

       static BYTE parms[ ] = VTS_R8;

       InvokeHelper(0x2, DISPATCH_METHOD, VT_R8, (void*)&result, parms, dAmount);

       return result;

}

 

void IBank::Deposit(double dAmount)

{

       static BYTE parms[ ] = VTS_R8;

       InvokeHelper(0x3, DISPATCH_METHOD, VT_EMPTY, NULL, parms, dAmount);

}

 

 

Listing 14:  The IBank class listing.

 

The CMymfc29DView class has a data member m_bank of class IBank. The CMymfc29DView member functions for the Mymfc29A.Bank component are listed below. They are hooked up to options on the MYMFC29D main menu. Of particular interest is the OnBankoleLoad() function. The COleDispatchDriver::CreateDispatch function loads the component program (by calling CoGetClassObject() and IClassFactory::CreateInstance) and then calls QueryInterface() to get an IDispatch pointer, which it stores in the object's m_lpDispatch data member. The COleDispatchDriver::ReleaseDispatch function, called in OnBankoleUnload(), calls Release() on the pointer.

 

void CMymfc29DView::OnBankoleLoad()

{

   if(!m_bank.CreateDispatch("Mymfc29A.Bank")) {

        AfxMessageBox("Mymfc29A.Bank component not found");

        return;

   }

}

 

void CMymfc29DView::OnUpdateBankoleLoad(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_bank.m_lpDispatch == NULL);

}

 

void CMymfc29DView::OnBankoleTest()

{

    m_bank.Deposit(20.0);

    m_bank.Withdrawal(15.0);

    TRACE("new balance = %f\n",

    m_bank.GetBalance());

}

 

void CMymfc29DView::OnUpdateBankoleTest(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_bank.m_lpDispatch != NULL);

}

 

void CMymfc29DView::OnBankoleUnload()

{  

    m_bank.ReleaseDispatch();

}

 

void CMymfc29DView::OnUpdateBankoleUnload(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_bank.m_lpDispatch != NULL);

}

 

The Controller Class for mymfc29B.dll

 

Listing 15 shows the class header file generated by ClassWizard.

 

AUTODRIVER.H

 

// Machine generated IDispatch wrapper class(es) created with ClassWizard

/////////////////////////////////////////////////////////////////////////////

// IMymfc29BAuto wrapper class

 

class IMymfc29BAuto : public COleDispatchDriver

{

public:

       IMymfc29BAuto() {}         // Calls COleDispatchDriver default constructor

       IMymfc29BAuto(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) { }

       IMymfc29BAuto(const IMymfc29BAuto& dispatchSrc) : COleDispatchDriver(dispatchSrc) { }

 

// Attributes

public:

       long GetLongData();

       void SetLongData(long);

       VARIANT GetTextData();

       void SetTextData(const VARIANT&);

 

// Operations

public:

       BOOL DisplayDialog();

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 15: The Mymfc29BAuto class header file.

 

Notice that each property requires separate Get and Set functions in the client class, even though a data member in the component represents the property.

The view class header has a data member m_auto of class IMymfc29BAuto. Here are some DLL-related command handler member functions from mymfc29DView.cpp:

 

 

 

void CMymfc29DView::OnDlloleGetdata()

{

    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);

}

 

void CMymfc29DView::OnUpdateDlloleGetdata(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_auto.m_lpDispatch != NULL);

}

 

void CMymfc29DView::OnDlloleLoad()

{

    if(!m_auto.CreateDispatch("Mymfc29B.Auto")) {

        AfxMessageBox("Mymfc29B.Auto component not found");

        return;

    }

    m_auto.SetTextData(COleVariant("test"));  // testing

    m_auto.SetLongData(79);  // testing

    // verify dispatch interface

    //  {A9515AD7-5B85-11D0-848F-00400526305B}

    static const IID IID_IMymfc29BAuto = { 0xa9515ad7, 0x5b85, 0x11d0, { 0x84, 0x8f, 0x0, 0x40, 0x5, 0x26, 0x30, 0x5b } };

    LPDISPATCH p;

    HRESULT hr = m_auto.m_lpDispatch->QueryInterface(IID_IMymfc29BAuto, (void**) &p);

    TRACE("OnDlloleLoad — QueryInterface result = %x\n", hr);

    p->Release();

}

 

void CMymfc29DView::OnUpdateDlloleLoad(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_auto.m_lpDispatch == NULL);

}

 

void CMymfc29DView::OnDlloleUnload()

{

    m_auto.ReleaseDispatch();

}

 

void CMymfc29DView::OnUpdateDlloleUnload(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_auto.m_lpDispatch != NULL);

}

 

The Controller Class for mymfc29C.exe

 

Listing 16 shows the headers for the IMymfc29C and IAlarm classes, which drive the MYMFC29C Automation component.

 

CLOCKDRIVER.H

 

// Machine generated IDispatch wrapper class(es) created with ClassWizard

/////////////////////////////////////////////////////////////////////////////

// IMymfc29C wrapper class

 

class IMymfc29C : public COleDispatchDriver

{

public:

       IMymfc29C() {}             // Calls COleDispatchDriver default constructor

       IMymfc29C(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) { }

       IMymfc29C(const IMymfc29C& dispatchSrc) : COleDispatchDriver(dispatchSrc) { }

 

// Attributes

public:

       DATE GetTime();

       void SetTime(DATE);

 

// Operations

public:

       VARIANT GetFigure(short n);

       void SetFigure(short n, const VARIANT& newValue);

       void RefreshWin();

       void ShowWin();

       LPDISPATCH CreateAlarm(DATE Time);

};

/////////////////////////////////////////////////////////////////////////////

// IAlarm wrapper class

 

class IAlarm : public COleDispatchDriver

{

public:

       IAlarm() { }          // Calls COleDispatchDriver default constructor

       IAlarm(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) { }

       IAlarm(const IAlarm& dispatchSrc) : COleDispatchDriver(dispatchSrc) { }

 

// Attributes

public:

       DATE GetTime();

       void SetTime(DATE);

 

// Operations

public:

};

 

 

Listing 16: The IMymfc29C and IAlarm class header files.

 

Of particular interest is the IMymfc29C::CreateAlarm member function in ClockDriver.cpp:

LPDISPATCH IMymfc29C::CreateAlarm(DATE time)

{

    LPDISPATCH result;

    static BYTE parms[] = VTS_DATE;

    InvokeHelper(0x3, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, parms, time);

    return result;

}

This function can be called only after the clock object (document) has been constructed. It causes the MYMFC29C component to construct an alarm object and return an IDispatch pointer with a reference count of 1. The COleDispatchDriver::AttachDispatch function connects that pointer to the client's m_alarm object, but if that object already has a dispatch pointer, the old pointer is released. That's why, if you watch the Debug window, you'll see that the old MYMFC29C instance exits immediately after you ask for a new instance. You'll have to test this behavior with the Excel driver because MYMFC29D disables the Load menu option when the clock is running. The view class has the data members, m_clock and m_alarm. Here are the view class command handlers:

 

void CMymfc29DView::OnClockoleCreatealarm()

{

    CAlarmDialog dlg;

    if (dlg.DoModal() == IDOK)

    {

        COleDateTime dt(1995, 12, 23, dlg.m_nHours, dlg.m_nMinutes, dlg.m_nSeconds);

        LPDISPATCH pAlarm = m_clock.CreateAlarm(dt);

        m_alarm.AttachDispatch(pAlarm);  // releases prior object!

        m_clock.RefreshWin();

    }

}

 

void CMymfc29DView::OnUpdateClockoleCreatealarm(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_clock.m_lpDispatch != NULL);

}

 

void CMymfc29DView::OnClockoleLoad()

{

   if(!m_clock.CreateDispatch("Mymfc29C.Document"))

   {

        AfxMessageBox("Mymfc29C.Document component not found");

        return;

   }

    m_clock.SetFigure(0, COleVariant("XII"));

    m_clock.SetFigure(1, COleVariant("III"));

    m_clock.SetFigure(2, COleVariant("VI"));

    m_clock.SetFigure(3, COleVariant("IX"));

    OnClockoleRefreshtime();

    m_clock.ShowWin();

}

 

void CMymfc29DView::OnUpdateClockoleLoad(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_clock.m_lpDispatch == NULL);

}

 

void CMymfc29DView::OnClockoleRefreshtime()

{

    COleDateTime now = COleDateTime::GetCurrentTime();

    m_clock.SetTime(now);

    m_clock.RefreshWin();

}

 

void CMymfc29DView::OnUpdateClockoleRefreshtime(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_clock.m_lpDispatch != NULL);

}

 

void CMymfc29DView::OnClockoleUnload()

{

    m_clock.ReleaseDispatch();

}

 

void CMymfc29DView::OnUpdateClockoleUnload(CCmdUI* pCmdUI)

{

    pCmdUI->Enable(m_clock.m_lpDispatch != NULL);

}

 

Controlling Microsoft Excel

 

The MYMFC29D program contains code that loads Excel, creates a workbook, and reads from and writes to cells from the active worksheet. Controlling Excel is exactly like controlling an MFC Automation component, but you need to know about a few Excel peculiarities.

If you study Excel VBA, you'll notice that you can use more than 100 "objects" in your programs. All of these objects are accessible through Automation, but if you write an MFC Automation client program, you'll need to know about the objects' properties and methods. Ideally, you'd like a C++ class for each object, with member functions coded to the proper dispatch IDs.

Excel has its own type library, found in the file Excel8.olb (different file name with same OLB extension for Excel of the Office10 and Office11), usually in the \Program Files\Microsoft Office\Office or \Program Files\Microsoft Office\Office10 – Office 2000 or \Program Files\Microsoft Office\Office11 – Office 2003 directory. ClassWizard can read this file, exactly as it reads TLB files, to create C++ driver classes for individual Excel objects. It makes sense to select the objects you need and then combine the classes into a single pair of files, as shown in Figure 63.

 

 

Figure 63: ClassWizard can create C++ classes for the Excel objects listed in Excel8.olb.

 

Figure 63: ClassWizard can create C++ classes for the Excel objects listed in Excel8.olb.

 

You might need to edit the generated code to suit your needs. Let's look at an example. If you use ClassWizard to generate a driver class for the Worksheet object, you get a GetRange() member function, as shown here:

 

LPDISPATCH _Worksheet::GetRange(const VARIANT& Cell1, const VARIANT& Cell2)

{

    LPDISPATCH result;

    static BYTE parms[] = VTS_VARIANT VTS_VARIANT;

    InvokeHelper(0xc5, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, parms, &Cell1, &Cell2);

    return result;

}

 

You know (from the Excel VBA documentation) that you can call the method with either a single cell (one parameter) or a rectangular area specified by two cells (two parameters). Remember: you can omit optional parameters in a call to InvokeHelper(). Now it makes sense to add a second overloaded GetRange() function with a single cell parameter like this:

 

LPDISPATCH _Worksheet::GetRange(const VARIANT& Cell1) // added

{

    LPDISPATCH result;

    static BYTE parms[] = VTS_VARIANT;

    InvokeHelper(0xc5, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, parms, &Cell1);

    return result;

}

 

How do you know which functions to fix up? They're the functions you decide to use in your program. You'll have to read the Excel VBA reference manual to figure out the required parameters and return values.

The MYMFC29D program uses the Excel objects and contains the corresponding classes shown in the table below. All the code for these objects is contained in the files excel8.h and excel8.cpp.

 

Object/Class

View Class Data Member

_Application

m_app

Range

m_range[5]

_Worksheet

m_worksheet

Workbooks

m_workbooks

Worksheets

m_worksheets

 

Table 11.

 

The following view member function, OnExceloleLoad(), handles the Excel Comp Load menu command. This function must work if the user already has Excel running on the desktop. The COM GetActiveObject() function tries to return an IUnknown pointer for Excel. GetActiveObject() requires a class ID, so we must first call CLSIDFromProgID(). If GetActiveObject() is successful, we call QueryInterface() to get an IDispatch pointer and we attach it to the view's m_app controller object of class _Application. If GetActiveObject() is unsuccessful, we call COleDispatchDriver::CreateDispatch, as we did for the other components.

 

void CMymfc29DView::OnExceloleLoad()

{   // If Excel is already running, attach to it; otherwise, start it

    LPDISPATCH pDisp;

    LPUNKNOWN pUnk;

    CLSID clsid;

    TRACE("Entering CMymfc29DView::OnExcelLoad\n");

    BeginWaitCursor();

    ::CLSIDFromProgID(L"Excel.Application.11", &clsid); // from Registry

    if(::GetActiveObject(clsid, NULL, &pUnk) == S_OK) {

        VERIFY(pUnk->QueryInterface(IID_IDispatch, (void**) &pDisp) == S_OK);

        m_app.AttachDispatch(pDisp);

        pUnk->Release();

        TRACE(" attach complete\n");

    }

    else

    {

        if(!m_app.CreateDispatch("Excel.Application.11"))

        {

            AfxMessageBox("Excel 2003 program not found");

        }

        TRACE(" create complete\n");

    }

    EndWaitCursor();

}

OnExceloleExecute() is the command handler for the Execute item in the Excel Comp menu. Its first task is to find the Excel main window and bring it to the top. We must write some Windows code here because a method for this purpose couldn't be found. We must also create a workbook if no workbook is currently open.

We have to watch our method return values closely. The Workbooks Add method, for example, returns an IDispatch pointer for a Workbook object and, of course, increments the reference count. If we generated a class for Workbook, we could call COleDispatchDriver::AttachDispatch so that Release() would be called when the Workbook object was destroyed. Because we don't need a Workbook class, we'll simply release the pointer at the end of the function. If we don't properly clean up our pointers, we might get memory-leak messages from the Debug version of MFC.

The rest of the OnExceloleExecute() function accesses the cells in the worksheet. It's easy to get and set numbers, dates, strings, and formulas. The C++ code is similar to the VBA code you would write to do the same job.

 

void  CMymfc29DView::OnExceloleExecute()

{

   LPDISPATCH pRange, pWorkbooks;

 

   CWnd* pWnd = CWnd::FindWindow("XLMAIN", NULL);

   if (pWnd != NULL) {

     TRACE("Excel window found\n");

     pWnd->ShowWindow(SW_SHOWNORMAL);

     pWnd->UpdateWindow();

     pWnd->BringWindowToTop();

   }

 

   m_app.SetSheetsInNewWorkbook(1);

 

   VERIFY(pWorkbooks = m_app.GetWorkbooks());

   m_workbooks.AttachDispatch(pWorkbooks);

 

   LPDISPATCH pWorkbook = NULL;

   if (m_workbooks.GetCount() == 0) {

      // Add returns a Workbook pointer, but we

      //  don't have a Workbook class

      pWorkbook = m_workbooks.Add(); // Save the pointer for later release

   }

   LPDISPATCH pWorksheets = m_app.GetWorksheets();

   ASSERT(pWorksheets != NULL);

   m_worksheets.AttachDispatch(pWorksheets);

   LPDISPATCH pWorksheet = m_worksheets.GetItem(COleVariant((short) 1));

 

   m_worksheet.AttachDispatch(pWorksheet);

   m_worksheet.Select();

 

   VERIFY(pRange = m_worksheet.GetRange(COleVariant("A1")));

   m_range[0].AttachDispatch(pRange);

 

   VERIFY(pRange = m_worksheet.GetRange(COleVariant("A2")));

   m_range[1].AttachDispatch(pRange);

 

   VERIFY(pRange = m_worksheet.GetRange(COleVariant("A3")));

   m_range[2].AttachDispatch(pRange);

 

   VERIFY(pRange = m_worksheet.GetRange(COleVariant("A3"), COleVariant("C5")));

   m_range[3].AttachDispatch(pRange);

 

   VERIFY(pRange = m_worksheet.GetRange(COleVariant("A6")));

    m_range[4].AttachDispatch(pRange);

 

    m_range[4].SetValue(COleVariant(COleDateTime(2005, 4, 24, 15, 47, 8)));

    // Retrieve the stored date and print it as a string

    COleVariant vaTimeDate = m_range[4].GetValue();

    TRACE("returned date type = %d\n", vaTimeDate.vt);

    COleVariant vaTemp;

    vaTemp.ChangeType(VT_BSTR, &vaTimeDate);

    CString str = vaTemp.bstrVal;

    TRACE("date = %s\n", (const char*) str);

 

    m_range[0].SetValue(COleVariant("test string"));

 

    COleVariant vaResult0 = m_range[0].GetValue();

    if (vaResult0.vt == VT_BSTR) {

        CString str = vaResult0.bstrVal;

        TRACE("vaResult0 = %s\n", (const char*) str);

    }

 

    m_range[1].SetValue(COleVariant(3.14159));

 

    COleVariant vaResult1 = m_range[1].GetValue();

    if (vaResult1.vt == VT_R8) {

        TRACE("vaResult1 = %f\n", vaResult1.dblVal);

    }

 

    m_range[2].SetFormula(COleVariant("=$A2*2.0"));

 

    COleVariant vaResult2 = m_range[2].GetValue();

    if (vaResult2.vt == VT_R8) {

        TRACE("vaResult2 = %f\n", vaResult2.dblVal);

    }

 

    COleVariant vaResult2a = m_range[2].GetFormula();

    if (vaResult2a.vt == VT_BSTR) {

        CString str = vaResult2a.bstrVal;

        TRACE("vaResult2a = %s\n", (const char*) str);

    }

 

    m_range[3].FillRight();

    m_range[3].FillDown();

 

    // cleanup 

    if (pWorkbook != NULL) {

        pWorkbook->Release();

    }

}

 

 

Continue on next module...

 

----------------------End Automation part 3---------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. DCOM at MSDN.

  2. COM+ at MSDN.

  3. COM at MSDN.

  4. Win32 process, thread and synchronization story can be found starting from Module R.

  5. MSDN MFC 7.0 class library online documentation.

  6. MSDN MFC 9.0 class library online documentation - latest version.

  7. MSDN Library

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | Automation 10 | Automation 12 | Download | Site Index |