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

Launching a MAPI Form

It would be useful to know how to launch a new form. I assume that the form is already installed on the system. How someone would programmatically launch a new form?

If we follow the route of raw MAPI standards the problem appears to be not trivial. Form servers are separate COM executables, and they expect significant volume of work to be performed by their clients. For example, you need to implement IMAPIMessageSite interface among other things. Form server may call methods of this interface. This interaction is complex.

An alternative (and easier) way is to use IMAPISession::PrepareForm and IMAPISession::ShowForm methods. The last one utilizes Outlook automation. As a result, the code is smaller at expense of performance. For example, the following code (Forms/Launch) shows how you can launch a new form IPM.Note.MyMessage, which you should install before you run the code:
 

#include <afxwin.h>
#include <edk.h>

int main()
{
    /*
     * Algorithm:
     *  1. Create a new message in Outbox.
     *  2. Call IMAPISession::PrepareForm
     *  3. Call IMAPISession::ShowForm
     */
 
    HRESULT hr;
    LPMAPISESSION pSession = NULL;

    // Initialize MAPI
    hr = MAPIInitialize(NULL);
    if (FAILED(hr)) throw -1;

    // Obtain MAPI session
    hr = MAPILogonEx(0,    // Handle to parent window
      "MS Exchange Settings", // Profile name
      NULL,   // Password
      MAPI_NEW_SESSION |
      MAPI_EXTENDED |
      MAPI_LOGON_UI, // Logon flags
      &pSession);  // Resulting MAPI session
    if (FAILED(hr)) throw -1;

    // Find default message store
    ULONG cbDefStoreEid = 0;
    LPENTRYID pDefStoreEid = NULL;
    hr = HrMAPIFindDefaultMsgStore(pSession, &cbDefStoreEid, &pDefStoreEid);
    if (FAILED(hr)) throw -1;

    // Open default message store
    LPMDB pDefMsgStore = NULL;
    hr = pSession->OpenMsgStore(0, cbDefStoreEid, pDefStoreEid, NULL,
        MDB_WRITE | MAPI_DEFERRED_ERRORS, &pDefMsgStore);
    if (FAILED(hr)) throw -1;

    // Obtain Entry ID for Outbox.
    ULONG ulValues;
    LPSPropValue pPropValues = NULL;
    hr = pDefMsgStore->GetProps(NULL,
         0,
         &ulValues,
         &pPropValues);
    if (FAILED(hr)) throw -1;

    // Find PR_IPM_OUTBOX_ENTRYID
    BOOL bOutboxFound = FALSE;
    for (ULONG ul = 0; ul < ulValues; ul++)
    {
        if (PR_IPM_OUTBOX_ENTRYID == pPropValues[ul].ulPropTag)
        {
            bOutboxFound = TRUE;
            break;
        }
    }
    assert(bOutboxFound);
    // We have PR_IPM_OUTBOX_ENTRYID here

    // Try to open the Outbox
    ULONG ulObjType = 0;
    LPMAPIFOLDER pOutbox = NULL;
    hr = pDefMsgStore->OpenEntry(pPropValues[ul].Value.bin.cb,
         (ENTRYID *) pPropValues[ul].Value.bin.lpb,
         NULL,
         MAPI_BEST_ACCESS,
         &ulObjType,
         (LPUNKNOWN *) &pOutbox);
    if (FAILED(hr)) throw -1;
    // We have the Outbox opened...

    // Create a new message in Outbox. We'll need it to associate
    // with a form.
    LPMESSAGE pMessage = NULL;
    hr = pOutbox->CreateMessage(NULL, 0, &pMessage);
    if (FAILED(hr)) throw -1;

    // Prepare form
    ULONG ulToken = 0;
    hr = pSession->PrepareForm(NULL, pMessage, &ulToken);
    if (FAILED(hr)) throw -1;

    // Show the form
    hr = pSession->ShowForm(NULL,
       pDefMsgStore,
       pOutbox,
       NULL,
       ulToken,
       NULL,
       MAPI_NEW_MESSAGE,
       0,
       MSGFLAG_UNSENT,
       MAPI_ACCESS_MODIFY,
       "IPM.Note.MyMessage");

    // Cleanup
    if (pMessage)
        pMessage->Release();
    if (pOutbox)
        pOutbox->Release();
    if (pPropValues)
        MAPIFreeBuffer(pPropValues);
    if (pDefMsgStore)
        pDefMsgStore->Release();
    if (pSession)
        pSession->Release();
    ::MAPIUninitialize();
    return 0;
}

This algorithm is quite straightforward: I locate the Outbox, create a message in there, then call the IMAPISession::PrepareForm followed by IMAPISession::ShowForm. If you run this code under debugger and observe what happens in the system when you execute the ShowForm statement you will see that Outlook.exe appears in list of running process displayed by the Task Manager. Also, the performance appears to be miserable here because of huge amount of work associated with automation.
 

[ Contents | Home ]

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