Are you a world traveler? ZoneTick is a cool utility that'll help you stay in touch over multiple time zones!
 
Starting a CDO Session  
Nik Okuntseff  MS Exchange Server Programming 

Starting a CDO Session

The following code sample (CDO/Session) illustrates straightforward C++ approach to using CDO through IDispatch interface. The procedure is to create an instance of the object, obtain IDispatch COM interface from it, and then use it as necessary.

#include <afxwin.h>
#include <objbase.h>

#define dispidM_Logon 119
 
// GUID value for the Session object
static const CLSID GUID_OM_SESSION =
{0x3FA7DEB3, 0x6438, 0x101B, {0xAC, 0xC1, 0, 0xAA, 0, 0x42, 0x33, 0x26}};

int main()
{
    HRESULT hr;
 
    // Initialize COM.
    hr = CoInitialize(NULL);
    if (FAILED(hr)) throw -1;

    // Create an instance of the Session object.
    LPUNKNOWN punk = NULL;
    hr = CoCreateInstance(GUID_OM_SESSION,
       NULL,
       CLSCTX_SERVER,
       IID_IUnknown,
       (void **) &punk);
    if (FAILED(hr)) throw -1;

    // Get IDispatch interface.
    IDispatch * pSession = NULL;
    hr = punk->QueryInterface(IID_IDispatch, (void **) &pSession);
    punk->Release(); // No longer needed.
    if (FAILED(hr)) throw -1;
 
    // Logon to underlying MAPI.
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    VARIANT varRetVal;
    VariantInit(&varRetVal);
    hr = pSession->Invoke(dispidM_Logon, // value = 119
       IID_NULL,
       LOCALE_SYSTEM_DEFAULT,
       DISPATCH_METHOD,
       &dispparamsNoArgs,
       &varRetVal,
       NULL,
       NULL);
    if (FAILED(hr)) throw -1;
    ::MessageBox(NULL, "Successfully logged on!", "Success", MB_OK | MB_ICONINFORMATION);
 
    // Do other things here...
 
    // Release all objects and exit.
    pSession->Release();
    CoUninitialize();
    return 0;
}

Let's go through code and see what happens. Before entering main I define the dispatch identifier (119) for Logon method for CDO session. Knowledge of this ID saves me one function call to IDispatch::GetIDsOfNames. I will need this ID to put in the following IDispatch::Invoke call.

GUID_OM_SESSION uuid identifies CDO session object. I pass it to the CoCreateInstance function immediately after initializing COM library. I use the resulting IUnknown pointer to inquire about IDispatch interface and then call its Invoke method to process logon. That's standard COM way of doing things.

Alternatively, you could use the COleDispatchDriver MFC class and benefit from the opportunity of ClassWizard to generate COleDispatchDriver derived classes automatically. This is accomplished in the following way:

  • Use AppWizard to create an MFC project (such as dialog based, for example).
  • Invoke ClassWizard and use Add Class... - From a Type Library option. Specify olemsg32.dll name. Select all available objects in the library and press OK.
If everything goes smoothly ClassWizard will generate two files: olemsg32.h and olemsg32.cpp. You would also see a rich collection of classes (one class for each CDO object) added to your class view. All these classes use COleDispatchDriver as their base class. You can use them right away.

The following code fragment (from my CDO/SessionMFC project) describes how you can start a CDO session in this environment:

void CSessionMFCDlg::OnStart()
{
    try
    {
        // Initialize session object.
        Session session;
        BOOL bResult = session.CreateDispatch("MAPI.Session");
        ASSERT(bResult);
 
        // Logon.
        VARIANT vResult;
        session.InvokeHelper(0x77, DISPATCH_METHOD, VT_VARIANT, (void*) &vResult, NULL);
 
        // Display success.
        ::MessageBox(NULL, "Successfully logged on!", "Success", MB_OK | MB_ICONINFORMATION);
        session.Logoff();
    }
    catch (...)
    {
        ::MessageBox(NULL, "Exception raised...", "Error", MB_OK | MB_ICONINFORMATION);
    }
}

The first thing I do here is call the COleDispatchDriver::CreateDispatch method. This creates an IDispatch interface and attaches it to the session object. The Logon in this fragment is done via the InvokeHelper call. You may wonder why I do it in the following way instead of calling the Logon method generated by the ClassWizard. If you take a closer look at Logon you will see that it takes 7 parameters, all VARIANTs. Initializing such number of VARIANTs is painful. I made a shortcut by looking at how ClassWizard implements the Logon and doing the same with little overhead. Notice the 0x77 parameter (decimal 119), used in the first code fragment.

Although ClassWizard in fact generates a lot of code, it does not provide you with convenient methods. You still need to do a lot of initialization work yourself, or overload methods. In this context, Visual Basic would be perhaps a better choice of development environment. You should also consider Visual Basic for Active Server Pages programming. My goal now, however, is to demonstrate C++ way of using CDO. Microsoft provides the CDOMFC sample, where you should definitely take a look if you are going this way. This sample is a dialog based app, with which you can create and send e-mail messages. The classes generated by ClassWizard have been modified to simplify usage (by providing the Logon function with no parameters, for example, in the way similar to the above).

One other detail that I need to address here is exception orientation of COleDispatchDriver derived classes. This means the code will throw if something goes wrong. Thus, you need to use try/catch blocks to handle errors.
 

[ Contents | Home ]

Send comments and suggestions to niko@wrconsulting.com
Copyright © 1997-1998 by Nik Okuntseff