⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mapiex.cpp

📁 A (hopefully) complete extended MAPI wrapper for WinXP, WinCE, and .NET.
💻 CPP
字号:
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: MAPIEx.cpp
// Description: Windows Extended MAPI class 
//
// Copyright (C) 2005-2006, Noel Dillabough
//
// This source code is free to use and modify provided this notice remains intact and that any enhancements
// or bug fixes are posted to the CodeProject page hosting this class for the community to benefit.
//
// Usage: see the Codeproject article at http://www.codeproject.com/internet/CMapiEx.asp
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "MAPIExPCH.h"
#include "MAPIEx.h"
#include "MAPISink.h"

#ifdef _WIN32_WCE
#pragma comment(lib,"cemapi.lib")
#pragma comment(lib,"UUID.lib")
#else
#pragma comment (lib,"mapi32")
#endif
#pragma comment(lib,"Ole32.lib")

/////////////////////////////////////////////////////////////
// CMAPIEx

#ifdef UNICODE
int CMAPIEx::cm_nMAPICode=MAPI_UNICODE;
#else
int CMAPIEx::cm_nMAPICode=0;
#endif

CMAPIEx::CMAPIEx()
{
	m_pSession=NULL;
	m_pMsgStore=NULL;
	m_pFolder=NULL;	
	m_pContents=NULL;
	m_pHierarchy=NULL;
	m_sink=0;
}

CMAPIEx::~CMAPIEx()
{
	Logout();
}

BOOL CMAPIEx::Init(BOOL bMultiThreadedNotifcations)
{
#ifdef _WIN32_WCE
	if(CoInitializeEx(NULL, COINIT_MULTITHREADED)!=S_OK) return FALSE;
#endif
	if(bMultiThreadedNotifcations) {
		MAPIINIT_0 MAPIInit={ 0, MAPI_MULTITHREAD_NOTIFICATIONS };
		if(MAPIInitialize(&MAPIInit)!=S_OK) return FALSE;
	} else {
		if(MAPIInitialize(NULL)!=S_OK) return FALSE;
	}
	return TRUE;
}

void CMAPIEx::Term()
{
	MAPIUninitialize();
#ifdef _WIN32_WCE
	CoUninitialize();
#endif
}

BOOL CMAPIEx::Login(LPCTSTR szProfileName)
{
	return (MAPILogonEx(NULL,(LPTSTR)szProfileName,NULL,MAPI_EXTENDED | MAPI_USE_DEFAULT | MAPI_NEW_SESSION,&m_pSession)==S_OK);
}

void CMAPIEx::Logout()
{
	if(m_sink) {
		if(m_pMsgStore) m_pMsgStore->Unadvise(m_sink);
		m_sink=0;
	}

	RELEASE(m_pHierarchy);
	RELEASE(m_pContents);
	RELEASE(m_pFolder);
	RELEASE(m_pMsgStore);
	RELEASE(m_pSession);
}

// if I try to use MAPI_UNICODE when UNICODE is defined I get the MAPI_E_BAD_CHARWIDTH 
// error so I force narrow strings here
LPCTSTR CMAPIEx::GetProfileName()
{
	if(!m_pSession) return NULL;

	static CString strProfileName;
	LPSRowSet pRows=NULL;
	const int nProperties=2;
	SizedSPropTagArray(nProperties,Columns)={nProperties,{PR_DISPLAY_NAME_A, PR_RESOURCE_TYPE}};

	IMAPITable*	pStatusTable;
	if(m_pSession->GetStatusTable(0,&pStatusTable)==S_OK) {
		if(pStatusTable->SetColumns((LPSPropTagArray)&Columns, 0)==S_OK) {
			while(TRUE) {
				if(pStatusTable->QueryRows(1,0,&pRows)!=S_OK) MAPIFreeBuffer(pRows);
				else if(pRows->cRows!=1) FreeProws(pRows);
				else if(pRows->aRow[0].lpProps[1].Value.ul==MAPI_SUBSYSTEM) {
					strProfileName=GetValidString(pRows->aRow[0].lpProps[0]);
					FreeProws(pRows);
				} else {
					FreeProws(pRows);
					continue;
				}
				break;
			}
		}
		RELEASE(pStatusTable);
	}
	return strProfileName;
}

BOOL CMAPIEx::OpenMessageStore(LPCTSTR szStore)
{
	if(!m_pSession) return FALSE;

	LPSRowSet pRows=NULL;
	const int nProperties=3;
	SizedSPropTagArray(nProperties,Columns)={nProperties,{PR_DISPLAY_NAME, PR_ENTRYID, PR_DEFAULT_STORE}};

	BOOL bResult=FALSE;
	IMAPITable*	pMsgStoresTable;
	if(m_pSession->GetMsgStoresTable(0, &pMsgStoresTable)==S_OK) {
		if(pMsgStoresTable->SetColumns((LPSPropTagArray)&Columns, 0)==S_OK) {
			while(TRUE) {
				if(pMsgStoresTable->QueryRows(1,0,&pRows)!=S_OK) MAPIFreeBuffer(pRows);
				else if(pRows->cRows!=1) FreeProws(pRows);
				else {
					if(!szStore) { 
						if(pRows->aRow[0].lpProps[2].Value.b) bResult=TRUE;
					} else {
						CString strStore=GetValidString(pRows->aRow[0].lpProps[0]);
						if(strStore.Find(szStore)!=-1) bResult=TRUE;
					}
					if(!bResult) {
						FreeProws(pRows);
						continue;
					}
				}
				break;
			}
			if(bResult) {
				RELEASE(m_pMsgStore);
				bResult=(m_pSession->OpenMsgStore(NULL,pRows->aRow[0].lpProps[1].Value.bin.cb,(ENTRYID*)pRows->aRow[0].lpProps[1].Value.bin.lpb,NULL,MDB_NO_DIALOG | MAPI_BEST_ACCESS,&m_pMsgStore)==S_OK);
				FreeProws(pRows);
			}
		}
		RELEASE(pMsgStoresTable);
	}
	return bResult;
}

ULONG CMAPIEx::GetMessageStoreSupport()
{
	if(!m_pMsgStore) return FALSE;

	LPSPropValue props=NULL;
	ULONG cValues=0;
	ULONG rgTags[]={ 1, PR_STORE_SUPPORT_MASK };
	ULONG ulSupport=0;

	if(m_pMsgStore->GetProps((LPSPropTagArray) rgTags, CMAPIEx::cm_nMAPICode, &cValues, &props)==S_OK) {
		ulSupport=props->Value.ul;
		MAPIFreeBuffer(props);
	}
	return ulSupport;
}

LPMAPIFOLDER CMAPIEx::OpenFolder(unsigned long ulFolderID,BOOL bInternal)
{
	if(!m_pMsgStore) return NULL;

	LPSPropValue props=NULL;
	ULONG cValues=0;
	DWORD dwObjType;
	ULONG rgTags[]={ 1, ulFolderID };
	LPMAPIFOLDER pFolder;

	if(m_pMsgStore->GetProps((LPSPropTagArray) rgTags, cm_nMAPICode, &cValues, &props)!=S_OK) return NULL;
	m_pMsgStore->OpenEntry(props[0].Value.bin.cb,(LPENTRYID)props[0].Value.bin.lpb, NULL, MAPI_MODIFY, &dwObjType,(LPUNKNOWN*)&pFolder);
	MAPIFreeBuffer(props);

	if(pFolder && bInternal) {
		RELEASE(m_pFolder);
		m_pFolder=pFolder;
	}
	return pFolder;
}

LPMAPIFOLDER CMAPIEx::OpenRootFolder(BOOL bInternal)
{
	return OpenFolder(PR_IPM_SUBTREE_ENTRYID,bInternal);
}

LPMAPIFOLDER CMAPIEx::OpenInbox(BOOL bInternal)
{
	if(!m_pMsgStore) return NULL;

#ifdef _WIN32_WCE
	return OpenFolder(PR_CE_IPM_INBOX_ENTRYID);
#else
	ULONG cbEntryID;
	LPENTRYID pEntryID;
	DWORD dwObjType;
	LPMAPIFOLDER pFolder;

	if(m_pMsgStore->GetReceiveFolder(NULL,0,&cbEntryID,&pEntryID,NULL)!=S_OK) return NULL;
	m_pMsgStore->OpenEntry(cbEntryID,pEntryID, NULL, MAPI_MODIFY,&dwObjType,(LPUNKNOWN*)&pFolder);
	MAPIFreeBuffer(pEntryID);
#endif

	if(pFolder && bInternal) {
		RELEASE(m_pFolder);
		m_pFolder=pFolder;
	}
	return pFolder;
}

LPMAPIFOLDER CMAPIEx::OpenOutbox(BOOL bInternal)
{
	return OpenFolder(PR_IPM_OUTBOX_ENTRYID,bInternal);
}

LPMAPIFOLDER CMAPIEx::OpenSentItems(BOOL bInternal)
{
	return OpenFolder(PR_IPM_SENTMAIL_ENTRYID,bInternal);
}

LPMAPIFOLDER CMAPIEx::OpenDeletedItems(BOOL bInternal)
{
	return OpenFolder(PR_IPM_WASTEBASKET_ENTRYID,bInternal);
}

LPMAPITABLE CMAPIEx::GetHierarchy(LPMAPIFOLDER pFolder)
{
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return NULL;
	}
	RELEASE(m_pHierarchy);
	if(pFolder->GetHierarchyTable(0,&m_pHierarchy)!=S_OK) return NULL;

	const int nProperties=2;
	SizedSPropTagArray(nProperties,Columns)={nProperties,{PR_DISPLAY_NAME, PR_ENTRYID}};
	if(m_pHierarchy->SetColumns((LPSPropTagArray)&Columns, 0)==S_OK) return m_pHierarchy;
	return NULL;
}

LPMAPIFOLDER CMAPIEx::GetNextSubFolder(CString& strFolderName,LPMAPIFOLDER pFolder)
{
	if(!m_pHierarchy) return NULL;
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return FALSE;
	}

	DWORD dwObjType;
	LPSRowSet pRows=NULL;

	LPMAPIFOLDER pSubFolder=NULL;
	if(m_pHierarchy->QueryRows(1,0,&pRows)==S_OK) {
		if(pRows->cRows) {
			if(pFolder->OpenEntry(pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin.cb,(LPENTRYID)pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin.lpb, NULL, MAPI_MODIFY, &dwObjType,(LPUNKNOWN*)&pSubFolder)==S_OK) {
				strFolderName=GetValidString(pRows->aRow[0].lpProps[0]);
			}
		}
		FreeProws(pRows);
	}
	MAPIFreeBuffer(pRows);
	return pSubFolder;
}

// High Level function to open a sub folder by iterating recursively (DFS) over all folders 
// (use instead of manually calling GetHierarchy and GetNextSubFolder)
LPMAPIFOLDER CMAPIEx::OpenSubFolder(LPCTSTR szSubFolder,LPMAPIFOLDER pFolder)
{
	LPMAPIFOLDER pSubFolder=NULL;
	LPMAPITABLE pHierarchy;

	RELEASE(m_pHierarchy);
	pHierarchy=GetHierarchy(pFolder);
	if(pHierarchy) {
		CString strFolder;
		LPMAPIFOLDER pRecurse=NULL;
		do {
			RELEASE(pSubFolder);
			m_pHierarchy=pHierarchy;
			pSubFolder=GetNextSubFolder(strFolder,pFolder);
			if(pSubFolder) {
				if(!strFolder.CompareNoCase(szSubFolder)) break;
				m_pHierarchy=NULL; // so we don't release it in subsequent drilldown
				pRecurse=OpenSubFolder(szSubFolder,pSubFolder);
				if(pRecurse) {
					RELEASE(pSubFolder);
					pSubFolder=pRecurse;
					break;
				}
			}
		} while(pSubFolder);
		RELEASE(pHierarchy);
		m_pHierarchy=NULL;
	}
	// this may occur many times depending on how deep the recursion is; make sure we haven't already assigned m_pFolder
	if(pSubFolder && m_pFolder!=pSubFolder) {
		RELEASE(m_pFolder);
		m_pFolder=pSubFolder;
	}
	return pSubFolder;
} 

BOOL CMAPIEx::GetContents(LPMAPIFOLDER pFolder)
{
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return FALSE;
	}
	RELEASE(m_pContents);
	if(pFolder->GetContentsTable(0,&m_pContents)!=S_OK) return FALSE;

	const int nProperties=MESSAGE_COLS;
	SizedSPropTagArray(nProperties,Columns)={nProperties,{PR_MESSAGE_FLAGS, PR_ENTRYID }};
	return (m_pContents->SetColumns((LPSPropTagArray)&Columns,0)==S_OK);
}

BOOL CMAPIEx::SortContents(ULONG ulSortParam,ULONG ulSortField)
{
	if(!m_pContents) return FALSE;

	SizedSSortOrderSet(1, SortColums) = {1, 0, 0, {{ulSortField,ulSortParam}}};
	return (m_pContents->SortTable((LPSSortOrderSet)&SortColums,0)==S_OK);
}

BOOL CMAPIEx::GetNextMessage(CMAPIMessage& message,BOOL bUnreadOnly)
{
	if(!m_pContents) return FALSE;
	
	DWORD dwMessageFlags;
	LPSRowSet pRows=NULL;
	BOOL bResult=FALSE;
	while(m_pContents->QueryRows(1,0,&pRows)==S_OK) {
		if(pRows->cRows) {
			dwMessageFlags=pRows->aRow[0].lpProps[PROP_MESSAGE_FLAGS].Value.ul;
			if(bUnreadOnly &&  dwMessageFlags&MSGFLAG_READ) {
				FreeProws(pRows);
				continue;
			}
			bResult=message.Open(this,pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin,dwMessageFlags);
		}
		FreeProws(pRows);
		break;
	}
	MAPIFreeBuffer(pRows);
	return bResult;
}

BOOL CMAPIEx::GetNextContact(CMAPIContact& contact)
{
	if(!m_pContents) return FALSE;

	LPSRowSet pRows=NULL;
	BOOL bResult=FALSE;
	while(m_pContents->QueryRows(1,0,&pRows)==S_OK) {
		if(pRows->cRows) bResult=contact.Open(this,pRows->aRow[0].lpProps[PROP_ENTRYID].Value.bin);
		FreeProws(pRows);
		break;
	}
	MAPIFreeBuffer(pRows);
	return bResult;
}

// Creates a subfolder under pFolder, opens the folder if it already exists
LPMAPIFOLDER CMAPIEx::CreateSubFolder(LPCTSTR szSubFolder,LPMAPIFOLDER pFolder)
{
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return NULL;
	}
	
	LPMAPIFOLDER pSubFolder=NULL;
	ULONG ulFolderType=FOLDER_GENERIC;
	ULONG ulFlags=OPEN_IF_EXISTS | cm_nMAPICode;

	pFolder->CreateFolder(ulFolderType,(LPTSTR)szSubFolder,NULL,NULL,ulFlags,&pSubFolder);
	return pSubFolder;
}

// Deletes a sub folder and ALL sub folders/messages
BOOL CMAPIEx::DeleteSubFolder(LPCTSTR szSubFolder,LPMAPIFOLDER pFolder)
{
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return FALSE;
	}

	LPMAPIFOLDER pSubFolder=NULL;
	if(GetHierarchy(pFolder)) {
		CString strFolder;
		do {
			RELEASE(pSubFolder);
			pSubFolder=GetNextSubFolder(strFolder,pFolder);
			if(pSubFolder && !strFolder.CompareNoCase(szSubFolder)) break;
		} while(pSubFolder);
	}
	return DeleteSubFolder(pSubFolder,pFolder);
}

// Deletes a sub folder and ALL sub folders/messages
BOOL CMAPIEx::DeleteSubFolder(LPMAPIFOLDER pSubFolder,LPMAPIFOLDER pFolder)
{
	if(!pSubFolder) return FALSE;

	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return FALSE;
	}

	LPSPropValue props=NULL;
	ULONG cValues=0;
	ULONG rgTags[]={ 1, PR_ENTRYID };

	if(pSubFolder->GetProps((LPSPropTagArray) rgTags, CMAPIEx::cm_nMAPICode, &cValues, &props)==S_OK) {
		HRESULT hr=pFolder->DeleteFolder(props[0].Value.bin.cb,(LPENTRYID)props[0].Value.bin.lpb,NULL,NULL,DEL_FOLDERS|DEL_MESSAGES);
		MAPIFreeBuffer(props);
		return (hr==S_OK);
	}
	return FALSE;
}

BOOL CMAPIEx::DeleteMessage(CMAPIMessage& message,LPMAPIFOLDER pFolder)
{
	if(!pFolder) {
		pFolder=m_pFolder;
		if(!pFolder) return FALSE;
	}

	ENTRYLIST entries={ 1, message.GetEntryID() };
	HRESULT hr=pFolder->DeleteMessages(&entries,NULL,NULL,0);
	return (hr==S_OK);
}

BOOL CMAPIEx::CopyMessage(CMAPIMessage& message,LPMAPIFOLDER pFolderDest,LPMAPIFOLDER pFolderSrc)
{
	if(!pFolderDest) return FALSE;

	if(!pFolderSrc) {
		pFolderSrc=m_pFolder;
		if(!pFolderSrc) return FALSE;
	}

	ENTRYLIST entries={ 1, message.GetEntryID() };
	HRESULT hr=pFolderSrc->CopyMessages(&entries,NULL,pFolderDest,NULL,NULL,0);
	return (hr==S_OK);
}

BOOL CMAPIEx::MoveMessage(CMAPIMessage& message,LPMAPIFOLDER pFolderDest,LPMAPIFOLDER pFolderSrc)
{
	if(!pFolderDest) return FALSE;

	if(!pFolderSrc) {
		pFolderSrc=m_pFolder;
		if(!pFolderSrc) return FALSE;
	}

	ENTRYLIST entries={ 1, message.GetEntryID() };
	HRESULT hr=pFolderSrc->CopyMessages(&entries,NULL,pFolderDest,NULL,NULL,MESSAGE_MOVE);
	return (hr==S_OK);
}

// call with ulEventMask set to ALL notifications ORed together, only one Advise Sink is used.
BOOL CMAPIEx::Notify(LPNOTIFCALLBACK lpfnCallback,LPVOID lpvContext,ULONG ulEventMask)
{
	if(GetMessageStoreSupport()&STORE_NOTIFY_OK) {
		if(m_sink) m_pMsgStore->Unadvise(m_sink);
		CMAPISink* pAdviseSink=new CMAPISink(lpfnCallback,lpvContext);
		if(m_pMsgStore->Advise(0,NULL,ulEventMask,pAdviseSink,&m_sink)==S_OK) return TRUE;
		delete pAdviseSink;
		m_sink=0;
	}
	return FALSE;
}

// sometimes the string in prop is invalid, causing unexpected crashes
LPCTSTR CMAPIEx::GetValidString(SPropValue& prop)
{
	LPCTSTR s=prop.Value.LPSZ;
	if(s && !::IsBadStringPtr(s,(UINT_PTR)-1)) return s;
	return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -