Notice: This website is an unofficial Microsoft Knowledge Base (hereinafter KB) archive and is intended to provide a reliable access to deleted content from Microsoft KB. All KB articles are owned by Microsoft Corporation. Read full disclaimer for more details.

How To Programmatically Move an Exchange Mailbox Using CDOEXM in Visual C++


View products that this article applies to.

This article was previously published under Q297393

↑ Back to the top


Summary

This article provides two samples that demonstrate how to move a mailbox in Exchange from its current mailbox store to another mailbox store programmatically by using Microsoft Visual C++. The first sample uses Active Directory Services Interface (ADSI) and Collaboration Data Objects for Exchange Management (CDOEXM). The second sample uses Collaboration Data Objects for Exchange 2000 (CDO) and CDOEXM.

↑ Back to the top


More information

Background

In Exchange, moving a mailbox entails:
  • Modifying attributes on the user object in Active Directory that specify the user's mailbox store.
  • Moving the physical mailbox of the user to the new store location.
The CDOEXM::IMailboxStore interface is an interface that enables programmatically performing mailbox-related tasks like creating mailboxes for users, deleting mailboxes for users, and moving users' mailboxes across mailbox stores in a Windows 2000 domain or a Windows 2003 domain. The CDOEXM interfaces can be derived from either CDO interfaces or ADSI interfaces. For additional information about the advantages and disadvantages of using each of the following approaches, click the following article number to view the article in the Microsoft Knowledge Base:
297390� INFO: Comparing Use of ADSI and CDO to Access CDOEXM Recipient-Related Methods
The IMailboxStore method, MoveMailbox, performs two sets of tasks as follows:
  • Directory-related tasks on the user object
    • Updates the homeMTA attribute.
    • Updates the store's distinguished name on the homeMDB attribute.
    • Deletes the target e-mail address for the user object stored in the targetAddress attribute. This will be updated by the Recipient Update Service (RUS) when it runs against this user.
  • Store-related tasks
    • Copies the user's mailbox from the current store on an Exchange server to a new store location specified on the same or another Exchange server.
    • Transfers the messages and content from the user's old mailbox to the user's new mailbox.
    • Marks the user's old mailbox to be deleted. The actual mailbox is actually "tombstoned" (marked as deleted) once the Cleanup Agent is run against the store. This is indicated by a red cross in front of the mailbox when viewed from the Exchange System Manager.
If the user object has been set to be mailbox-enabled but the RUS hasn't run against the user object yet, then MoveMailbox forces the RUS to run against this user. Also, if this user's physical mailbox is still nonexistent in the information store (if this mailbox has not been accessed yet), this mailbox is created in the new mailbox store after MoveMailbox is called on the user.

Although the CDOEXM interfaces can be derived either from ADSI or CDO interfaces, they cannot be directly used to bind to an object in the Active Directory. The CDOEXM interfaces are available in Cdoexm.dll, which is installed along with the Microsoft Exchange System Management Tools. Do not manually register this file into the registry. You can install the Exchange System Management component by running Exchange Server Setup from the Exchange Server CD.

Using ADSI

This sample requires Adsiid.lib and Activeds.lib for the ADSI interfaces, which can be found under the Libs folder in a Platform SDK installation. The Platform SDK can be downloaded from the following Microsoft Web site: This sample, in addition to the ADSI libraries, requires Cdoexm.dll, which is installed along with the Microsoft Exchange System Management Tools. Therefore, it must be run on a Windows 2000 Server, a Windows 2000 Advanced Server member server, or a Windows Server 2003 server, in the same domain as the Exchange server, that has at least the MS Exchange System Management Tools component installed.

To build this sample, include the Adsiid.lib and Activeds.lib libraries in the Object/Library modules textbox, which is accessible from the Project menu by pointing to Settings and then clicking Link.

Sample Code

#include "stdio.h"
#include "activeds.h"
 
//Importing the libraries required to use CDOEXM
//TODO: change the file path below to point to the file
#import <G:\Program Files\Exchsvr\BIN\cdoexm.dll> no_namespace raw_interfaces_only exclude("IDataSource2")
 
int main(void)
{
 // Declare variables
 HRESULT hr;
 LPWSTR strUserLDAPPath;
 LPWSTR strMailboxStore;
 IADsUser *pUser = NULL;
 IMailboxStore *pMailbox = NULL;
 
//TODO: change the string below to the LDAP path for the user to 
//perform the MoveMailbox task on
 strUserLDAPPath = L"LDAP://domain/CN=user1,OU=MyOU,DC=domain,DC=com";
 
//TODO: Change the string below to the Distinguished Name or LDAP path
// for the new mailbox store to move the user's mailbox to
 strMailboxStore = L"CN=2nd Mailbox Store,CN=First Storage Group,CN=InformationStore,CN=EX2K,CN=Servers,CN=SITE1,CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=dom,DC=com";
 
 //Initialize COM
 hr = CoInitialize(NULL);
 if (FAILED(hr)) {
  wprintf(L"Failed to CoInitialize: 0x%x\n", hr);
  return hr;
 }
 
 //Bind to the existing mailbox enabled user using ADSI
 hr = ADsGetObject(strUserLDAPPath, IID_IADsUser, (void**)&pUser);
 if (FAILED(hr)) {
  wprintf(L"Failed to get IADsUser: 0x%x\n", hr);
  pUser->Release();
  CoUninitialize();
  return hr;
 }
 
 //Query for the IMailboxStore Interface using the IADsUser object
 hr = pUser->QueryInterface(__uuidof(IMailboxStore), (void**)&pMailbox);
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"QueryInterface of IMailboxStore failed!\n");
  pUser->Release();
  pMailbox->Release();
  CoUninitialize();
  return hr;
 }
 
 //Move the Mailbox
 hr = pMailbox->MoveMailbox(strMailboxStore);
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"MoveMailbox failed!\n");
  pUser->Release();
  pMailbox->Release();
  CoUninitialize();
  return hr;
 }
 
 //Apply changes made to the cache back onto the user object in the Active Directory
 hr = pUser->SetInfo();
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"SetInfo failed!\n");
  pUser->Release();
  pMailbox->Release();
  CoUninitialize();
  return hr;
 }
 
 //Cleanup and uninitialize COM
 pUser->Release();
 pMailbox->Release();
 pUser = NULL;
 pMailbox = NULL;
 CoUninitialize();
 return 0;
}
				

Using CDO

This sample requires Cdoex.dll for the IPerson interface on the CDO.Person object. This .dll file is available only on an Exchange server. It also requires Cdoexm.dll for the IMailboxStore interface on the CDOEXM object. This .dll is available on Exchange servers as well. Therefore, this code can only be run from an Exchange server. Do not manually attempt to register either of these files into the registry to work around this limitation.

Sample Code

#include "stdio.h"
 
// Importing the libraries required to use CDOEXM
//TODO: change the path to the files location
#import <c:\program files\common files\system\ado\msado15.dll> no_namespace raw_interfaces_only
#import <C:\Program Files\Common Files\Microsoft Shared\CDO\cdoex.dll> no_namespace raw_interfaces_only rename("Folder","CDOEXFolder") 
#import <G:\Program Files\Exchsvr\BIN\cdoexm.dll> no_namespace raw_interfaces_only
 
int main(void)
{
 // Declare variables
 HRESULT hr;
 LPWSTR strUserLDAPPath;
 LPWSTR strMailboxStore;
 IPerson* pUser = NULL;
 IDataSource* pDataSource = NULL;
 IMailboxStore *pMailbox = NULL;
 
//TODO: Change this string to the LDAP path for the user to perform
//the MoveMailbox task on
 strUserLDAPPath = L"LDAP://domain/CN=user2,OU=MyOU,DC=domain,DC=com";
 
//TODO: Change this string to the Distinguished Name or LDAP path for
// the new mailbox store to move the user's mailbox to
 strMailboxStore = L"CN=2nd Mailbox Store,CN=First Storage Group,CN=InformationStore,CN=EX2K,CN=Servers,CN=SITE1,CN=Administrative Groups,CN=Microsoft,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=com";
 
 //Initialize COM
 hr = CoInitialize(NULL);
 if (FAILED(hr)) {
  wprintf(L"Failed to CoInitialize: 0x%x\n", hr);
  return hr;
 }
 
 //Create Instance of IPerson interface
 hr = CoCreateInstance( __uuidof(Person),
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      __uuidof(IPerson),
                     (void**) &pUser
                     );
 if (FAILED(hr)) {
  wprintf(L"Failed to Create Instance of IPerson object: 0x%x\n", hr);
  pUser->Release();
  pUser = NULL;
  CoUninitialize();
  return hr;
 }
 
 hr = pUser->get_DataSource(&pDataSource);
 if (FAILED(hr)) {
  wprintf(L"Failed to get_DataSource: 0x%x\n", hr);
  pUser->Release();
  pDataSource->Release();
  pUser = NULL;
  pDataSource = NULL;
  CoUninitialize();
  return hr;
 }
 
 //Bind to the existing mailbox enabled user
 hr = pDataSource->Open(strUserLDAPPath,
       NULL,
       adModeReadWrite,
       adFailIfNotExists,
       adOpenSource,
       L"",
       L"");
 if (FAILED(hr)) {
  wprintf(L"Failed to bind to LDAP path: 0x%x\n", hr);
  pUser->Release();
  pDataSource->Release();
  pUser = NULL;
  pDataSource = NULL;
  CoUninitialize();
  return hr;
 }
 
 //Query for the IMailboxStore Interface using the IADsUser object
 hr = pUser->QueryInterface(__uuidof(IMailboxStore), (void**)&pMailbox);
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"QueryInterface of IMailboxStore failed!\n");
  pUser->Release();
  pDataSource->Release();
  pMailbox->Release();
  pUser = NULL;
  pMailbox = NULL;
  pDataSource = NULL;
  CoUninitialize();
  return hr;
 }
 
 //Move Mailbox
 hr = pMailbox->MoveMailbox(strMailboxStore);
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"MoveMailbox failed!\n");
  pUser->Release();
  pMailbox->Release();
  pDataSource->Release();
  pUser = NULL;
  pMailbox = NULL;
  pDataSource = NULL;
  CoUninitialize();
  return hr;
 }
 
 //Update changes made by CDOEXM by Saving DataSource
 hr = pDataSource->Save();
 if (!SUCCEEDED(hr)) 
 {
  wprintf(L"Failed to Save DataSource!\n");
  pUser->Release();
  pMailbox->Release();
  pDataSource->Release();
  pUser = NULL;
  pMailbox = NULL;
  pDataSource = NULL;
  CoUninitialize();
  return hr;
 }
 
 CoUninitialize();
 return 0;
}
				

↑ Back to the top


References

For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:
297398� How To Delete a Mailbox Using CDOEXM and Visual C++

↑ Back to the top


Keywords: kbdswadsi2003swept, kbhowto, KB297393

↑ Back to the top

Article Info
Article ID : 297393
Revision : 13
Created on : 10/25/2007
Published on : 10/25/2007
Exists online : False
Views : 504