CEMAPI实战攻略(二)——建立与短信信箱的连接
CEMAPI實戰攻略
by 吳春雷
QQ:819543772
Email:wuchunlei@163.com
二.建立與短信信箱的連接
上一部分已經討論過,如何搭建開發和測試環境,以及如何初始化CEMAPI,再繼續這一部分的討論之前,我們先要澄清幾個概念。第一個是會話(Seesion),相信開發網絡應用的朋友都不陌生,為了提高通訊效率降低通訊開銷,有時候我們需要再目標與本地之間創建一個通道,在通道創建之初,目標與本地先做一些列的響應和請求確認兩邊的身份,當通道建立以后,目標與本地之間的通訊過程中就不再涉及兩邊的身份確認,這通常目標與本地之間的建立的通道,通常被稱作會話,也就是Session。在使用Cemapi讀取短信之前,應用程序也需要與設備上的信息(郵件)系統之間建立一個Session,用以 確認雙方的身份,這是采用Cemapi讀取短信的第一步。第二個概念是短消息(郵件)倉庫(MsgStore),在WM中,郵件和短消息是屬于一個系統的,Session建立了與這個系統之間的連接,然后必須告訴系統,我們的程序是要對郵件功能進行操作,還是要對短信功能進行操作,通過調用相應的函數(后面會介紹),MsgStore會指向我們需要操作的短信或郵件的倉庫上。第三個概念是信箱,或者叫文件夾(Folder),當獲得了指向一個具體倉庫的MsgStore以后,下一步就需要獲取具體的信箱(文件夾)了,比如當程序確定了希望對收件箱還是發件箱進行操作以后,Folder將會指向我們想要操作的具體的信箱。
OK,澄清了這三個概念,就可以進一步討論,如何建立會話,獲取具體信箱了。
1.?????? 會話接口IMAPISession
從mapidefs.h中我們可以看到,通過DECLARE_MAPI_INTERFACE_這個宏使IMAPISession派生自IUnKnow接口,IUnKnow接口中定義引用技術等與COM有關的基本操作,關于IUnKnow的詳細內容大家可以參見COM技術的相關資料。IMAPISession接口中值得注意的一個函數是GetMsgStoresTable,后面我們將通過調用該函數獲取短信(郵件)倉庫的列表。
2.?????? 如何創建與MAPI的會話
Cemapi中,我們將使用MAPILogonEx函數建立與短信(郵件)系統的會話,MAPILogonEx在Mapix.h中的定義如下:
typedef HRESULT (STDMETHODCALLTYPE MAPILOGONEX)(
??? ULONG ulUIParam,
??? LPTSTR lpszProfileName,
??? LPTSTR lpszPassword,
??? ULONG ulFlags,??
??? LPMAPISESSION FAR * lppSession
);
MAPILOGONEX MAPILogonEx;
從定義中可以看出MAPILogonEx函數返回一個HRESULT類型,采用宏FAILED和SUCCESSED可以判斷函數是否成功返回。同時,該函數有五個參數,這五個參數分別表示,短信(郵件)系統登陸UI的現實方式以及Session的共享方式,配置文件的文件名,郵箱密碼,編碼方式(默認)和指向IMAPISession接口指針的指針,對于短信應用程序的開發,前四個參數均無意義,可以直接設置為NULL。如果函數調用成功,我們將會從最后一個參數那里得到短信(郵件)系統的Session指針。調用方法如下:
IMAPISession *m_pSession=NULL;
???????? hr=MAPILogonEx(NULL,NULL,NULL,NULL,&m_pSession);
???????? if(FAILED(hr) || NULL==m_pSession)
???????? {
????????????? //異常處理
???????? }
3.?????? 如何終止與短信(郵件)系統的會話,并釋放Session對象
使用IMAPISession接口中Logoff方法可以終止與短信(郵件)系統的會話,Logoff方法定義為:
HRESULT IMAPISession::Logoff(ULONG ulUIParam,ULONG ulFlags,ULONG ulReserved);
方法返回一個HRESULT對象,通過它可以判斷調用是否成功。前兩個參數的意義與MAPILogonEx中的同名參數相同,最后一個參數保留不用。對于短信操作來說,三個參數均可設置為NULL。
當成功Logoff以后,如果確信不再需要Session對象以后,可以通過Release方法釋放對象。源代碼如下:
if(NULL!=m_pSession)??????? //釋放Session
???????? {
????????????? HRESULT hr=m_pSession->Logoff(NULL,NULL,NULL);
????????????? if(FAILED(hr))
{
???? //異常處理
}
????????????? m_pSession->Release();
????????????? m_pSession=NULL;
}
4.?????? 短信(郵件)倉庫接口IMsgStore
IMsgStore繼承自IMAPIProp接口,而IMAPIProp接口又繼承自IUnknow接口,這個接口中值得我們重點關注的函數有GetProps,OpenEntry兩個函數,后面我們將會通過這兩個函數獲取具體信箱(Folder)對象。
5.?????? 建立與短信倉庫的連接
在實現連接以前,先來看一個很有意思的宏
#define SizedSPropTagArray(_ctag, _name) /
struct _SPropTagArray_ ## _name /
{ /
??? ????????? ULONG?? cValues; /
??? ????????? ULONG?? aulPropTag[_ctag]; /
} _name
為什么說這個結構體有意思,仔細看一下就知道了,利用了一個帶參數的宏,實現了動態聲明結構體的功能,更奇妙的是,連結構體的名稱都可以動態創建。大家別怪我顧洛寡聞,這種聲明方式還真是不太常見。這個數據結構在Cemapi中扮演一個很重要的角色,通過定制的實現它,可以告訴函數,我希望獲取或設置那些屬性。看下面一段程序:
SizedSPropTagArray(2 , Columns) = ???????? {
????????????? 2,
????????????? PR_ENTRYID, //Entry ID
????????????? PR_DISPLAY_NAME //Display Name
};
這段程序動態的聲明了一個名為_SPropTagArray_Columns的結構體,并且聲明了一個名為Columns的結構體變量。這個結構體中有一個ULONG類型的成員變量,和一個長度為2的ULONG類型的數組成員組成。結構體中cValues的值被初始化為2,aulPropTag[0]=PR_ENTRYID,aulProTag[1]=PR_DISPLAY_NAME。
這里面涉及到了兩個常量符號,PR_ENTRYID和PR_DISPLAY_NAME,這兩個符號分別表示對象ID和顯示名稱,這里所說的對象可以是短信(郵件)存儲倉庫,也可是具體信箱Folder,還可以是短消息本身,調用不同的函數,這些符號會被解釋為具體對象的某些屬性。
另外還有一個重要的接口需要說明,那就是IMAPITable,這個接口也從IUnKnow中繼承。在WM系統中的短信(郵件)倉庫、具體信箱Folder以及Folder中的短信都不是唯一的,在使用Cemapi中的接口方法獲取這些對象的時候,將會采用表的形式返回結果,IMAPITable接口的作用就是用于描述這個表的結構。
有了這兩個類型作為基礎,我們就可以通過嘗試獲取WM系統中的短信(郵件)倉庫列表了,前面提到了IMAPISession接口一個方法GetMsgStoresTable,從名字上應該就很直觀的知道了這個方法的功能,即獲取MsgStore(短信郵件倉庫)列表。該方法定義為:
HRESULT IMAPISession::GetMsgStoresTable(ULONG ulFlags,LPMAPITABLE FAR * lppTable)
???????? 返回值依舊標志方法是否運行成功,不再贅述。參數中
ulFlags:表示字符編碼類型,這里好像只有MAPI_UNICODE標志供選擇。
lppTable:實際是一個IMAPITable **類型,該方法通過它返回MsgStore(短信郵件倉庫)列表。
當GetMsgStoresTable方法成功獲取了IMAPITable接口的對象以后,這時該對象里面的數據還是以原始的方式組織的,我們無法獲取表中的記錄,這時候就需要調用IMAPITable接口中的SetColumns方法來告訴IMAPTABLE對象,內部數據將以什么形式進行組織。該方法定義為:
HRESULT IMAPITable::SetColumns(LPSPropTagArray , ULONG);
返回值用于判斷方法調用是否成功。參數說明:
LPSPropTagArray:用于說明IMAPITable中記錄的組織形式,把前面提到過的Columns對象作為參數傳入,則表示告訴IMAPITable對象,表格中每條記錄有兩列,第一列是對象ID(PR_ENTRYID),第二列是對象現實名稱(PR_DISPLAY_NAME)。
ULONG:某種標志,一般設置為0,這里我沒有找到相關資料,希望高手們補充。
有了表格,有了記錄的結構,下一步要做什么應該很容易就能想到。Yes ,取表格中的所有記錄,并且遍歷這些記錄,查找顯示名稱(PR_DISPLAY_NAME)為SMS的記錄。這里再介紹一種數據結構SRowSet,其定義如下:
typedef struct _SRowSet
{
??? ULONG?????????? cRows;????????? /* 行數 */
??? SRow??????????? aRow[MAPI_DIM]; /* 行記錄具體信息 */
} SRowSet, FAR * LPSRowSet;
???? 很有意思,MAPI_DIM的值為1,但是絕不是說所有從IMAPITable中取出的行記錄都只有一列,恰恰相反,列的數量是由我們前面提到的動態結構體變量Columns中的cValues的值來決定的,這里請讀者朋友們注意。SRow也為一個結構體,其定義如下:
typedef struct _SRow
{
??? ULONG?????????? ulAdrEntryPad;?
??? ULONG?????????? cValues;??????? /* 用于標志lpProps成員的數量 */
??? LPSPropValue??? lpProps;??????? /* 屬性結構體*/
} SRow, FAR * LPSRow;
lpProps成員所對應的結構體SPropValue才是行記錄中真正的數據。其定義如下
typedef struct _SPropValue
{
??? ULONG?????? ulPropTag;??????????????? /*屬性標志,常用于輔助判斷屬性值是否成功獲取*/
??? ULONG?????? dwAlignPad;
??? union _PV?? Value;
} SPropValue, FAR * LPSPropValue;
這個結構中Value成員非常有用,它由很多成員組成,每個成員對應著對象的一個屬性,該聯合體定義如下:
typedef union _PV
{
??? short int?????????? i;????? ????/* case PT_I2 */
??? LONG??????????????? l;????????? /* case PT_LONG */
??? ULONG?????????????? ul;???????? /* alias for PT_LONG */
??? float?????????????? flt;??????? /* case PT_R4 */
??? double????????????? dbl;??????? /* case PT_DOUBLE */
??? unsigned short int? b;????????? /* case PT_BOOLEAN */
??? CURRENCY??????????? cur;??????? /* case PT_CURRENCY */
??? double????????????? at;???????? /* case PT_APPTIME */
??? FILETIME??????????? ft;???????? /* case PT_SYSTIME */
??? LPSTR?????????????? lpszA;????? /* case PT_STRING8 */
??? SBinary???????????? bin;??????? /* case PT_BINARY */
??? LPWSTR????????????? lpszW;????? /* case PT_UNICODE */
??? LPGUID????????????? lpguid;???? /* case PT_CLSID */
??? LARGE_INTEGER?????? li;???????? /* case PT_I8 */
??? SShortArray???????? MVi;??????? /* case PT_MV_I2 */
??? SLongArray????????? MVl;??????? /* case PT_MV_LONG */
??? SRealArray????????? MVflt;????? /* case PT_MV_R4 */
??? SDoubleArray??????? MVdbl;????? /* case PT_MV_DOUBLE */
??? SCurrencyArray????? MVcur;????? /* case PT_MV_CURRENCY */
??? SAppTimeArray?????? MVat;?????? /* case PT_MV_APPTIME */
??? SDateTimeArray????? MVft;?????? /* case PT_MV_SYSTIME */
??? SBinaryArray??????? MVbin;????? /* case PT_MV_BINARY */
??? SLPSTRArray???????? MVszA;????? /* case PT_MV_STRING8 */
??? SWStringArray?????? MVszW;????? /* case PT_MV_UNICODE */
??? SGuidArray????????? MVguid;???? /* case PT_MV_CLSID */
??? SLargeIntegerArray? MVli;?????? /* case PT_MV_I8 */
??? SCODE?????????????? err;?? ?????/* case PT_ERROR */
??? LONG??????????????? x;????????? /* case PT_NULL, PT_OBJECT (no usable value) */
} __UPV;
看到這么成員是不是眼有些花呀?我認為這些成員不必全部了解,因為我們不必像想孔乙己那樣,知道茴香豆的茴字怎么寫,還要知道有幾種寫法(當然您也可以不這么認為)。其實我們只需要知道ft,lpszA,lpszW以及bin這四個成員就可以了,他們分別代表發送(接收)時間,顯示名稱或消息標題或正文或發送號碼或接受號碼等字符串(ASCII),顯示名稱或消息標題或正文或發送號碼或接受號碼等字符串(UNICODE)以及對象的EntryID(對象可以是短信郵件倉庫,可以是具體信箱Folder也可以是某條短信)。在這一小節中,我們只用到了lpszW和bin。SBinary也為一個結構體對象,它用來唯一標示某一對象的ID,其定義如下:
typedef struct _SBinary
{
??? ULONG?????? cb;
??? LPBYTE????? lpb;
} SBinary, FAR *LPSBinary;
這里面的兩個成員含義不必深究,我們只需要知道,這兩個成員所組成的結構體對象SBinary可以作為唯一標示對象的ID,(對象依舊可以是短信郵件倉庫,可以是具體信箱Folder也可以是某條短信,在這一小節中它表示短信郵箱倉庫對象的ID。
???? IMAPITable中提供了QueryRows方法來獲取行記錄,其定義如下:
???????? HRESULT IMAPITable::QueryRows(LONG,ULONG,SRowSet **);
???? 返回值用于判斷方法調用是否成功,這里要注意,如果取不到任何行記錄的時候也會返回失敗,因此可以用于判斷行記錄是否已經遍歷完畢。參數說明:
???? LONG:希望獲取多少行記錄。
ULONG:標志可以是如下定義的符號之一,很抱歉,具體每種標志代表什么含義,并沒有資料特別的說明,有興趣的朋友可以研究一下。再短信應用中,這個值一般會設置為0。
#define TBL_LEAF_ROW??????????? ((ULONG) 1)
#define TBL_EMPTY_CATEGORY????? ((ULONG) 2)
#define TBL_EXPANDED_CATEGORY?? ((ULONG) 3)
#define TBL_COLLAPSED_CATEGORY? ((ULONG) 4)
SRowSet **:這個參數用于返回查找到的行記錄。
每次QueryRows成功執行以后,IMAPITable中的游標會自動移動第一個參數LONG行記錄,直到遍歷完畢為止。
現在我們已經獲取短信郵件系統中的所有短信郵件倉庫了,下面要做的就是找到顯示名稱為SMS的那個MsgStore倉庫,并獲去指向該倉庫的對象指針。還記得Columns這個動態結構體變量嗎?我們通過SetColumns方法給行記錄定義了兩列,第一列為對象ID(PR_ENTRYID),第二列為顯示名稱(PR_DISPLAY_NAME),那么每一個SRowSet對象中就會有兩個SPropValue結構體對象,第一個就代表PR_ENTRYID,第二個則代表PR_DISPLAY_NAME,第一個SPropValue中的Value聯合體中的bin成員有效,而第二個SPropValue中的Value聯合體中的lpszW成員有效。如果我們使用QueryRows方法獲取到的SRowSet *對象為m_pRows,則下面代碼則表示上述說明內容。
m_pRows->aRow[0].lpProps[0].Value.bin為PR_ENTRYID
m_pRows->aRow[0].lpProps[1].Value.lpszW為PR_DISPLAY_NAME
有了對象ID,我們就可以通過IMAPISession中的OpenEntry方法獲取短信倉庫對象IMsgStore了。OpenEntry方法定義為:
HRESULT IMAPISession::OpenEntry(ULONG,LPENTRYID,LPCIID,ULONG,ULONG*,LPUNKNOW*);
返回值說明了方法調用是否成功,參數說明如下:
ULONG:短信郵件倉庫的EntryId,也即對應的SBinary結構中的cb成員
LPENTRYID:短信郵件倉庫的EntryId指針,也即對應的SBinary結構中的lpb成員
LPCIID:本質是一個指向GUID結構體變量的指針,若想更深入的了解GUID結構體請參考COM相關資料,這里只給出定義:
typedef struct _GUID {????????? // size is 16
??? DWORD Data1;
??? WORD?? Data2;
??? WORD?? Data3;
??? BYTE? Data4[8];
} GUID;
ULONG:訪問標志,cemapi中只支持最優訪問方式,MAPI_BEST_ACCESS
ULONG*:用于返回Message類型
LPUNKNOW *:一個指向IUnKnow或其派生類指針的指針,用于返回派生自IUnknow接口的對象,這里是IMsgStore對象。
OK,相關的內容基本上已經介紹完了,說了很多,估計您已經看的云里霧里了,還是用一段完整程序來給上面的內容做一個總結吧。
IMAPITable *m_pTable? = NULL;???????
HRESULT hr? = 0;
???????? SRowSet *m_pRows? = NULL; ??????
???????? SizedSPropTagArray(2 , Columns) =
???????? {
????????????? 2 ,
????????????? PR_ENTRYID, //
????????????? PR_DISPLAY_NAME //Display Name
???????? };
?
???????? if(NULL==m_pSession)
???????? {
????????????? //異常處理
???????? }
?
???????? hr=m_pSession->GetMsgStoresTable(MAPI_UNICODE , &m_pTable);??? //獲取IMAPITable對象
?
???????? if(FAILED(hr) || NULL==m_pTable)
???????? {
?????????????????? //沒有取到表結構或取表結構時出錯
???????? }
?
???????? hr=m_pTable->SetColumns((LPSPropTagArray)&Columns, 0);? //設置行記錄結構
???????? if(FAILED(hr))
???????? {
????????????? //異常處理
???????? }
?
???????? while(SUCCEEDED(m_pTable->QueryRows(1, 0, &m_pRows)))? //循環遍歷所有行記錄
???????? {
????????????? if (NULL == m_pRows || m_pRows->cRows != 1)
????????????? {
?????????????????? break;
????????????? }
???????? ???? //查找顯示名字為SMS的行記錄
????????????? if (_tcsicmp(m_pRows->aRow[0].lpProps[1].Value.lpszW, _T("SMS")) == 0)
???????? ???? {
?????????????????? ULONG ulMsgType;
?????????????????? //則獲取指向短信倉庫的對象
?????????????????? hr=m_pSession->OpenEntry(m_pRows->aRow[0].lpProps[0].Value.bin.cb,
?????????????????? ? (LPENTRYID)m_pRows->aRow[0].lpProps[0].Value.bin.lpb,
?????????????????? ? NULL,
?????????????????? ? MAPI_BEST_ACCESS,
?????????????????? ? &ulMsgType,
?????????????????? ? (LPUNKNOWN*)&m_pMsgStore);
?????????????????? if(FAILED(hr) || NULL==m_pMsgStore)
?????????????????? {
?????????????????????? //異常處理
?????????????????? }
?????????????????? break;
????????????? }
?
????????????? FreeProws(m_pRows);??? //釋放
???????? ???? m_pRows = NULL;
???????? }
???????? if(m_pRows)??????? //釋放資源
???????? {
????????????? FreeProws(m_pRows);
????????????? m_pRows = NULL;
???? }
?
6.?????? 釋放IMsgStore對象
IMsgStore接口提供了Release方法釋放對象資源,調用方式如下:
if(NULL!=m_pMsgStore)
{
?? m_pMsgStore->Release();
}
7.?????? 與某一具體信箱建立連接,獲取具體信箱接口IMAPIFolder對象
獲取具體信箱IMAPIFolder對象要比獲取IMsgStore對象容易很多,因為在短信倉庫MsgStore下,只有收件箱,發件箱,草稿箱,廢件箱,已發送郵件箱5種具體信箱(Folder),我們可以通過指定要獲取的信箱(Folder)類型來直接獲取指向該具體信箱的IMAPIFolder對象。
首先,依舊需要建立一個動態的SPropTagArray結構體變量,用于告訴短信倉庫IMsgStore對象,我們需要獲取哪一個具體信箱的IMAPIFolder對象,代碼如下:
SizedSPropTagArray(1, Columns) =
???????? {
????????????? 1,
????????????? PR_CE_IPM_INBOX_ENTRYID???? /*表示要獲取指向系統收件箱的IMAPIFolder對象*/
???????? };
???????? 用于表示具體信箱(Folder)的標志:
???????? PR_CE_IPM_INBOX_ENTRYID:系統收件箱
???????? PR_CE_IPM_OUTBOX_ENTRYID:系統發件箱
???????? PR_CE_IPM_DRAFTS_ENTRYID:草稿箱
PR_IPM_SENTMAIL_ENTRYID:已發郵件箱
PR_IPM_WASTEBASKET_ENTRYID):廢件箱
然后我們需要用一個新的方法GetProps來獲取具體信箱(Folder)的屬性信息,其實我們的主要目的是獲取屬性中該具體信箱的EntryID。該方法被定義為:
HRESULT IMsgStore::GetProps(SPropTagArray *,ULONG,ULONG *,SPropTagArray**);
方法返回值標志方法是否執行成功。參數說明:
SPropTagArray * :利用前面動態結構體對象Columns,告訴IMsgStore對象,我需要取哪個具體信箱的屬性。
ULONG:指明當前的編碼方式,MAPI_UNICODE
SPropTagArray**:用于返回從具體信箱中獲取的屬性
???????? ???????? 最后用IMsgStore對象的OpenEntry方法建立獲取指向具體信箱的IMAPIFolder接口對象。該方法的定義與IMAPISession中的同名對象相同,這里不再贅述。
?????? 獲取指向具體信箱的IMAPIFolder接口對象的源程序如下:
???????? HRESULT hr=0;
???????? LPSPropValue stProps? = NULL;
???????? ULONG ulValues?? = 0;
SizedSPropTagArray(1, Columns) =
???????? {
????????????? 1,
????????????? PR_CE_IPM_INBOX_ENTRYID???? /*表示要獲取指向系統收件箱的IMAPIFolder對象*/
???????? };
// 獲取Folder的Entry ID,然后通過OpenEntry獲得對象
???????? m_pMsgStore->GetProps((LPSPropTagArray) &Columns, MAPI_UNICODE, &ulValues, &stProps);
????????
???????? hr=m_pMsgStore->OpenEntry(stProps[0].Value.bin.cb, (LPENTRYID)stProps[0].Value.bin.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&m_pFolder );
?
???????? if(FAILED(hr) || NULL==m_pFolder)
???????? {
????????????? //異常處理
???????? }
???????? MAPIFreeBuffer(stProps);???????? //釋放掉對象
8.?????? 釋放掉Folder對象
If(NULL!=m_pFoder)
{
???? m_pFolder->Release();
}
9.?????? 本節所涉及到的源程序
//獲取IMAPISession會話對象
void Session()
{
IMAPISession *m_pSession=NULL;
???????? hr=MAPILogonEx(NULL,NULL,NULL,NULL,&m_pSession);
???????? if(FAILED(hr) || NULL==m_pSession)
???????? {
????????????? //異常處理
???????? }
?
}
//獲取指向短信倉庫的IMsgStroe接口對象
void MsgStore()
{
IMAPITable *m_pTable? = NULL;???????
HRESULT hr? = 0;
???????? SRowSet *m_pRows? = NULL; ??????
???????? SizedSPropTagArray(2 , Columns) =
???????? {
????????????? 2 ,
????????????? PR_ENTRYID, //
????????????? PR_DISPLAY_NAME //Display Name
???????? };
?
???????? if(NULL==m_pSession)
???????? {
????????????? //異常處理
???????? }
?
???????? hr=m_pSession->GetMsgStoresTable(MAPI_UNICODE , &m_pTable);??? //獲取IMAPITable對象
?
???????? if(FAILED(hr) || NULL==m_pTable)
???????? {
?????????????????? //沒有取到表結構或取表結構時出錯
???????? }
?
???????? hr=m_pTable->SetColumns((LPSPropTagArray)&Columns, 0);? //設置行記錄結構
???????? if(FAILED(hr))
???????? {
????????????? //異常處理
???????? }
?
???????? while(SUCCEEDED(m_pTable->QueryRows(1, 0, &m_pRows)))? //循環遍歷所有行記錄
???????? {
????????????? if (NULL == m_pRows || m_pRows->cRows != 1)
????????????? {
?????????????????? break;
????????????? }
???????? ???? //查找顯示名字為SMS的行記錄
????????????? if (_tcsicmp(m_pRows->aRow[0].lpProps[1].Value.lpszW, _T("SMS")) == 0)
???????? ???? {
?????????????????? ULONG ulMsgType;
?????????????????? //則獲取指向短信倉庫的對象
?????????????????? hr=m_pSession->OpenEntry(m_pRows->aRow[0].lpProps[0].Value.bin.cb,
?????????????????? ? (LPENTRYID)m_pRows->aRow[0].lpProps[0].Value.bin.lpb,
?????????????????? ? NULL,
?????????????????? ? MAPI_BEST_ACCESS,
?????????????????? ? &ulMsgType,
?????????????????? ? (LPUNKNOWN*)&m_pMsgStore);
?????????????????? if(FAILED(hr) || NULL==m_pMsgStore)
?????????????????? {
?????????????????????? //異常處理
?????????????????? }
?????????????????? break;
????????????? }
?
????????????? FreeProws(m_pRows);??? //釋放
???????? ???? m_pRows = NULL;
???????? }
???????? if(m_pRows)??????? //釋放資源
???????? {
????????????? FreeProws(m_pRows);
????????????? m_pRows = NULL;
???? }
?
}
??? //獲取指向具體信箱的IMAPIFolder接口對象
void Folder(ULONG ulType)
???? {
???????? HRESULT hr=0;
???????? LPSPropValue stProps? = NULL;
???????? ULONG ulValues?? = 0;
???????? ULONG ulTags[]?? = { 1, ulType};
?
???? ?// 獲取Folder的Entry ID,然后通過OpenEntry獲得對象
???????? m_pMsgStore->GetProps((LPSPropTagArray) ulTags, MAPI_UNICODE, &ulValues, &stProps);
????????
???????? hr=m_pMsgStore->OpenEntry(stProps[0].Value.bin.cb, (LPENTRYID)stProps[0].Value.bin.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&m_pFolder );
?
???????? if(FAILED(hr) || NULL==m_pFolder)
???????? {
????????????? throw(CMsgException(_T("獲取FOLDER失敗!"),_T("CMsgControl->Folder"),ERR_GET_FOLDER));
???????? }
???????? MAPIFreeBuffer(stProps);???????? //釋放掉對象
}
//釋放掉IMAPISession、IMsgStore、IMAPIFolder對象
void UnInit()
???? {
???????? if(NULL!=m_pSession)??????? //釋放Session
???????? {
????????????? m_pSession->Logoff(NULL,NULL,NULL);
????????????? m_pSession->Release();
????????????? m_pSession=NULL;
???????? }
?
???????? if(NULL!=m_pMsgStore)? //釋放MsgStore
???????? {
????????????? m_pMsgStore->Release();
????????????? m_pMsgStore=NULL;
???????? }
?
???????? if(NULL!=m_pFolder)???????? //釋放Folder
???????? {
????????????? m_pFolder->Release();
????????????? m_pMsgStore=NULL;
???????? }
?}
總結
以上是生活随笔為你收集整理的CEMAPI实战攻略(二)——建立与短信信箱的连接的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Pr 入门教程:如何设置动画旋转图形?
- 下一篇: Vue双向绑定是怎么实现的?