HOWTO: Using Recipients Collection RawTable with Active Msg/VC++

ID: Q175368

The information in this article applies to:

SUMMARY

The Collaboration Data Objects Library (formally known as Active Messaging, versions noted above) contains a bug that prevents the successful execution of the GetItem() method of any object that has this method. This is documented in the Microsoft Knowledge Base Article:

   ARTICLE-ID: Q173850
   TITLE     :PRB: #Import Does not Include Index Parameter Error from VC5

The article documents the problem, and indicates that context-specific workarounds are available. The following article covers one of these workarounds and can be used as a template for any Collection that includes a RawTable property.

MORE INFORMATION

The code sample below instantiates an Active Messaging Session, logs on to that Session, grabs the first Message it finds in your Inbox, and then uses the RawTable Method off of the Recipients Collection to get a pointer to the underlying Extended MAPI IMAPITable, which contains information about the Recipients of this Message.

To demonstrate that we have this information, it also collects the names of the Recipients into a string and subsequently displays the string in a MessageBox.

Code Sample Follows:

    #import "olemsg32.dll" no_namespace

    #include <stdio.h>
    #include <assert.h>
    #include <tchar.h>

    #define INITGUID

    #define USES_IID_IMAPITable
    #define USES_IID_IMAPITableData

    #include "mapidefs.h"
    #include "MAPIGUID.H"

    // Arbitrary Maximum # of recipients we will process
    #define MAX_RECIPS 500

    void dump_com_error(_com_error &e)
    {
      _tprintf(_T("Oops - hit an error!\n"));
      _tprintf(_T("\a\tCode = %08lx\n"), e.Error());
      _tprintf(_T("\a\tCode meaning = %s\n"), e.ErrorMessage());
      _bstr_t bstrSource(e.Source());
      _bstr_t bstrDescription(e.Description());
      _tprintf(_T("\a\tSource = %s\n"), (LPCTSTR) bstrSource);
      _tprintf(_T("\a\tDescription = %s\n"), (LPCTSTR) bstrDescription);
    }

    // If this is placed in the scope of the smart pointers, they must be
    // explicitly Release(d) before CoUninitialize() is called.  If any
    // reference count is non-zero, a protection fault will occur.
    struct StartOle {
        StartOle() { CoInitialize(NULL); }
        ~StartOle() { CoUninitialize(); }
    } _inst_StartOle;

    void main(int argc, char *argv[])
    {
      TCHAR szNames[MAX_RECIPS * 20];

      try
      {
        SessionPtr pSession("MAPI.Session");
        pSession->Logon();

        FolderPtr     pFolder = pSession->Inbox;
        MessagesPtr   pMessages = pFolder->Messages;
        MessagePtr    pMessage = pMessages->GetFirst();

        if (pMessage!=NULL)
        {
          RecipientsPtr  pRecipColl=pMessage->Recipients;
          LPMAPITABLE    lpRecipsTable = NULL;
          IUnknown*      lpRecipsObj = NULL;
          HRESULT        hr = S_OK;
          int            iNumRows = 0;

          // Get an IUnknown Interface to the Recipient Obj
          (IUnknown*)lpRecipsObj = pRecipColl->RawTable;

          // From this point down to (but not including) the Logoff, we
          // are using pure Extended MAPI functionality except for refering
          // to the field names by their constants as defined in the Active
          // Messaging Library. (aka - ActMsgPR_DISPLAY_NAME)
          // 
          // Get an Interface to the IMAPITable from that interface
          hr = lpRecipsObj->QueryInterface(IID_IMAPITable,
                                           (void**)&lpRecipsTable);

          // Make sure we got a table back
          if(lpRecipsTable)
          {
            LPSRowSet     lpRows = NULL;  // Table
            LPSRow         lpRow  = NULL;  // 1 row from table
            LPSPropValue  lpProp = NULL;  // 1 Prop (column) from row
            SizedSPropTagArray(1, Columns) =
            {
              1,  // number of properties
              {
                ActMsgPR_DISPLAY_NAME
              }
            };

            // Set the columns to just ActMsgPR_DISPLAY_NAME
            hr = lpRecipsTable->SetColumns((LPSPropTagArray)&Columns, 0);

            // If you care to use TBLVU32 to view you IMAPITable, insert
            // the code commented after the end of the program at this
            // point.

            // Set BookMark to beginning of table
            hr = lpRecipsTable->SeekRow(BOOKMARK_BEGINNING,0,NULL);

            // Find out how many rows are in the table.
            ULONG lCount = 0;
            hr = lpRecipsTable->GetRowCount(0, &lCount);

            // Get all of the rows.
            hr = lpRecipsTable->QueryRows(lCount, 0, &lpRows);

            // Get number of rows returned
            iNumRows = lpRows->cRows;

            // Loop through the rows and collect the names for later use
            for (int iIndex =0; iIndex < iNumRows; iIndex++)
            {
              lpRow = &lpRows->aRow[iIndex];
              lpProp = &lpRow->lpProps[0];
              if(lpProp->ulPropTag == ActMsgPR_DISPLAY_NAME)
              {
                // append the name and a ";" to the string of names
                strcat(&szNames[0], lpProp->Value.lpszA);
                strcat(&szNames[0], ";");
              }
            }
          }
          char sNumRecips[35];
          sprintf(sNumRecips, "There are %d Recipients", iNumRows);
          MessageBox(NULL, szNames, sNumRecips, MB_OK);
        }
        // Logoff the Active Messaging MAPI Session
        pSession->Logoff();

      }
      catch (_com_error &e)
      {
        dump_com_error(e);
      }
    }

    /*
    #ifdef _DEBUG
      // Prepare to show the table with tblvu32.dll
      HINSTANCE hInstTableVu = LoadLibrary("tblvu32.dll");

      ULONG (PASCAL *lpfnViewMAPITable)(LPMAPITABLE FAR *, HWND);
      (FARPROC&)lpfnViewMAPITable = GetProcAddress(hInstTableVu,
                                    "ViewMapiTable");

      lpfnViewMAPITable((LPMAPITABLE FAR *)&lpRecipsTable, NULL);
      FreeLibrary (hInstTableVu);
    #endif _DEBUG
    */ 

REFERENCES

This sample assumes that Collaboration Data Objects (CDO) version 1.1 is installed on your system. For additional information on obtaining the Active Messaging library, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q171440
   TITLE     : Where to Acquire the Collaboration Data Objects  Libraries

For additional information about Collaboration Data Objects versus Active Messaging, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q176916
   TITLE     : INFO: Active Messaging and Collaboration Data Objects (CDO)

Keywords          : kbActMsg kbCDO100a kbCDO110 kbMsg kbVC kbGrpMsg 
Version           : WINDOWS:1.0,1.0a,1.1
Platform          : WINDOWS
Issue type        : kbhowto

Last Reviewed: April 10, 1999