原文:http://blog.csdn.net/cjwn/archive/2009/02/08/3868466.aspx
在Windows Mobile 6上通过CEMAPI POOM发送短信
在Winodws Mobile上第三方软件一般是通过
1)调用SmsMessageSend API函数发送短信。
或者通过
2)CreateProcess或者ShellExecuteEx方式,调用命令(不含尖括号)
</windows/tmail.exe -service "SMS" -to "短信接收方号码" -body "短信内容">
下面的例子,就是调用Windows Mobile自带的短信程序(tmail.exe),编辑一条收件人为10086,短信内容为 CXYE,查询余额的短信。
/windows/tmail.exe -service "SMS" -to "10086" -body "KTIP1000"
最终效果如截图。
<Place Holder for SMS Send UI>
1)和2)这两种方法都有各自的优缺点。
第一种方法,短信发送成功后在微软自带的已发送邮件箱(Sent Items)中找不到已经发送的短信。发送失败也没有提示。当然可以自己硬行构造POOM的短信对象来实现这个不足。
第二种方法,就是通过tmail.exe -service "SMS" -to "" -body "" 的方法不能够自动发送短信,只是停留在编辑完成界面,还需要用户手动点击"发送"按钮,或者通过程序实现。
下面介绍一种方法既能够让已发短信出现在已发送邮件箱中,也能够将短信编辑完成后自动发送。
这就是通过CEMAPI来发送短信。这个在www.codeproject.com 上05年的一篇文章已经实现了。请原文请参考 http://www.codeproject.com/KB/mobile/SMS_CEMPI.aspx .
我使用和实践了这段代码,发现几个问题。
1)发送短信不成功后,短信会到草稿箱,但是点开改短信,再次发送时,就无法发送了。
<Place Holder for Screen shot>
此时,短信的内容放置到了主题(Subject)上,这和普通使用时候遇到的情况不一样,短信内容应该在正文(Body)中.
2)短信发送时候,需要设置一个参数,那就是本机号码。至于如何获得本机号码,是非常麻烦的。
3)此Sample是在EVC下编译的,而且缺少.rc2文件。虽然作者已经说明了如何解决。
但是我还是重新改写了以下,将所有的CComPtr<IMAPISession> 之类的定义改成了WM6上建议的IMAPISession
改正了 SendSMSMessage 函数的HRESULT 类型返回值 Return S_OK.
但是1)和2)的问题仍旧需要解决。
// --- SMSHelper.cpp ---
#include "Log.h"
#include "SMSHelper.h"
/
// This function is used to get the msgstore named SMS from msgstores on the
// device.
// I could have used just raw pointers but it is much easier and safer to just
// use smart pointers.
HRESULT GetSMSMsgStore( IMAPISession* pSession, IMsgStore ** ppMsgStore)
{
// first we get the msgstores table from the session
IMAPITable * pTable=NULL;
HRESULT hr = pSession->GetMsgStoresTable(MAPI_UNICODE, &pTable);
if (FAILED(hr) && pTable!=NULL )
{
//MessageBox(NULL, L"Failed: GetMsgStoresTable", L"GetSMSMsgStore", MB_OK);
WriteString( L"Failed: GetMsgStoresTable - GetSMSMsgStore" );
return FALSE;
}
WriteString( L"Passed: GetMsgStoresTable - GetSMSMsgStore" );
// next we loop over the message stores opening each msgstore and
// getting its name to see if the name matches SMS.
// If it does then we break out of the loop
while (TRUE)
{
SRowSet* pRowSet = NULL;
hr = pTable->QueryRows(1, 0, &pRowSet);
// If we failed to query the
// rows then we need to break
if (FAILED(hr) && pRowSet!=NULL)
{
//MessageBox(NULL, L"Failed: QueryRows", L"GetSMSMsgStore", MB_OK);
WriteString( L"Failed: QueryRows - GetSMSMsgStore" );
break;
}
WriteString( L"Passed: QueryRows - GetSMSMsgStore" );
// if we got no rows back then just exit the loop
//remembering to set an error
if (pRowSet->cRows == 1)
{
ASSERT(pRowSet->aRow[0].lpProps->ulPropTag == PR_ENTRYID);
SBinary& blob = pRowSet->aRow[0].lpProps->Value.bin;
hr = pSession->OpenMsgStore(NULL, blob.cb, (LPENTRYID)blob.lpb, NULL, 0,ppMsgStore);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: OpenMsgStore", L"GetSMSMsgStore", MB_OK);
WriteString( L"Failed: OpenMsgStore - GetSMSMsgStore" );
}
WriteString( L"Passed: OpenMsgStore - GetSMSMsgStore" );
}
else
{
//MessageBox(NULL, L"pRowSet->cRows != 1", L"GetSMSMsgStore", MB_OK);
WriteString( L"pRowSet->cRows != 1 - GetSMSMsgStore" );
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}
// now remember to free the row set
FreeProws(pRowSet);
if (FAILED(hr))
{
break;
}
// now get the display name property from the
// message store to compare it against the name
// 'SMS'
SPropTagArray props;
props.cValues = 1;
props.aulPropTag[0] = PR_DISPLAY_NAME;
ULONG cValues;
SPropValue* pProps = NULL;
hr = (*ppMsgStore)->GetProps(&props, MAPI_UNICODE, &cValues, &pProps);
if (FAILED(hr) || cValues != 1)
{
//MessageBox(NULL, L"Failed: GetProps", L"GetSMSMsgStore", MB_OK);
WriteString( L"Failed: GetProps - GetSMSMsgStore" );
break;
}
WriteString( L"Passed: GetProps - GetSMSMsgStore" );
// if the name matches SMS then break and as
// hr == S_OK the current MsgStore smart pointer
// will correctly be set.
if (_tcsicmp(pProps[0].Value.lpszW, _T("SMS")) == 0)
{
break;
}
}
// if we failed for some reason then we clear out
// the msgstore smartpointer and return the error.
if (FAILED(hr) )
{
(*ppMsgStore)->Release();
}
return hr;
}
/
// This function is used to get the folder named drafts from the msgstore on the
// device.
// I could have used just raw pointers but it is much easier and safer to just
// use smart pointers.
HRESULT GetSMSFolder(IMsgStore* pMsgStore, IMAPIFolder** ppFolder)
{
// Now get the Drafts folder.
SPropTagArray propDefaultFolder;
propDefaultFolder.cValues = 1;
propDefaultFolder.aulPropTag[0] = PR_CE_IPM_DRAFTS_ENTRYID;
ULONG cValues;
LPSPropValue pPropVals;
HRESULT hr = pMsgStore->GetProps (&propDefaultFolder, MAPI_UNICODE, &cValues, &pPropVals);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: GetProps", L"GetSMSFolder", MB_OK);
WriteString( L"Failed: GetProps - GetSMSFolder" );
return hr;
}
WriteString( L"Passed: GetProps - GetSMSFolder" );
SBinary& eidDrafts = pPropVals->Value.bin;
hr = pMsgStore->OpenEntry(eidDrafts.cb, (LPENTRYID)eidDrafts.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)ppFolder);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: OpenEntry", L"GetSMSFolder", MB_OK);
WriteString( L"Failed: OpenEntry - GetSMSFolder" );
}
WriteString( L"Passed: OpenEntry - GetSMSFolder" );
return hr;
}
/
// This function is used to get the send the message.
// This uses an opened MAPI session
HRESULT SendSMSMessage( ICEMAPISession * pSession, LPCTSTR lpszFrom, LPCTSTR lpszTo, LPCTSTR lpszMessage)
{
// now get the SMS message store
IMsgStore* pMsgStore = NULL;
HRESULT hr = GetSMSMsgStore(pSession, &pMsgStore);
if (FAILED(hr) && pMsgStore!=NULL)
{
//MessageBox(NULL, L"Failed: GetSMSMsgStore", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: GetSMSMsgStore - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: GetSMSMsgStore - SendSMSMessage" );
IMAPIFolder* pFolder=NULL;
hr = GetSMSFolder(pMsgStore, &pFolder);
if (FAILED(hr) && pFolder!=NULL )
{
//MessageBox(NULL, L"Failed: GetSMSFolder", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: GetSMSFolder - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: GetSMSFolder - SendSMSMessage" );
IMessage* pMessage=NULL;
hr = pFolder->CreateMessage(NULL, 0 ,&pMessage);
if (FAILED(hr) && pMessage!=NULL)
{
//MessageBox(NULL, L"Failed: CreateMessage", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: CreateMessage - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: CreateMessage - SendSMSMessage" );
// set the recipients
// set up the required fields for a recipient
SPropValue propRecipient[3];
// it is vital we clear the property structure
// as there are fields we do not use but MAPI seems
// to be sentative to them.
ZeroMemory(&propRecipient, sizeof(propRecipient));
// set the recipient type which coul be to, cc, bcc
// but ehre must at least be a to field
propRecipient[0].ulPropTag = PR_RECIPIENT_TYPE;
propRecipient[0].Value.l = MAPI_TO;
// we set the type of address to sms instead of
// smtp
propRecipient[1].ulPropTag = PR_ADDRTYPE;
propRecipient[1].Value.lpszW = _T("SMS");
// we finally set the email address to the
// phone number of the person we are sending the message
// to
propRecipient[2].ulPropTag = PR_EMAIL_ADDRESS;
propRecipient[2].Value.lpszW = (LPWSTR)lpszTo;
// set the addrlist to point to the properties
ADRLIST adrlist;
adrlist.cEntries = 1;
adrlist.aEntries[0].cValues = 3;
adrlist.aEntries[0].rgPropVals = (LPSPropValue)(&propRecipient);
// finally modify the recipients of the message
hr = pMessage->ModifyRecipients(MODRECIP_ADD, &adrlist);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: ModifyRecipients", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: ModifyRecipients - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: ModifyRecipients - SendSMSMessage" );
// now we set the additional properties for the
// message
SPropValue props[4];
//note how we zero out the contents of the
// structure as MAPI is sensative to the
// contents of other fields we do not use.
ZeroMemory(&props, sizeof(props));
// first set the subject of the message
// as the sms we are going to send
props[0].ulPropTag = PR_SUBJECT;
props[0].Value.lpszW = (LPWSTR)lpszMessage;
// next set the senders email address to
// the phone number of the person we are
// sending the message to
props[1].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
props[1].Value.lpszW = (LPWSTR)lpszFrom;
// finally and most importantly tell mapi
// this is a sms message in need of delivery
props[2].ulPropTag = PR_MSG_STATUS;
props[2].Value.ul = MSGSTATUS_RECTYPE_SMS;
props[3].ulPropTag = PR_MESSAGE_FLAGS;
props[3].Value.ul = MSGFLAG_FROMME | MSGFLAG_UNSENT;
hr = pMessage->SetProps(sizeof(props) / sizeof(props[0]), (LPSPropValue)&props, NULL);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: SetProps", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: SetProps - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: SetProps - SendSMSMessage" );
// having set all the required fields we can now
// pass the message over to the msgstore transport
// to be delivered.
hr = pMessage->SubmitMessage(0);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: SubmitMessage", L"SendSMSMessage", MB_OK);
WriteString( L"Failed: SubmitMessage - SendSMSMessage" );
return hr;
}
WriteString( L"Passed: SubmitMessage - SendSMSMessage" );
return S_OK;
}
/
// This is the function that creates the session, using the
// from, the recipient and the message.
// This opens the session, opens the sms message store and opens
// the drafts folder then create a new message and sets the sender,
// recipient and messag, then finally sends the message.
BOOL DoSendMessage(LPCTSTR lpszFrom, LPCTSTR lpszTo, LPCTSTR lpszMessage)
{
HRESULT hr = MAPIInitialize(NULL);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: MAPIInitialize", L"DoSendMessage", MB_OK);
WriteString( L"Failed: MAPIInitialize - DoSendMessage" );
return hr;
}
WriteString( L"Passed: MAPIInitialize - DoSendMessage" );
// Initialized the MAPI subsystem
// CComPtr<IMAPISession> spSession;
ICEMAPISession * pSession = NULL;
BOOL bRet = FALSE;
hr = MAPILogonEx(0 ,NULL, NULL, 0, (LPMAPISESSION *)&pSession);
if (FAILED(hr))
{
//MessageBox(NULL, L"Failed: MAPILogonEx", L"DoSendMessage", MB_OK);
WriteString( L"Failed: MAPILogonEx - DoSendMessage" );
}
else
{
WriteString( L"Passed: MAPILogonEx - DoSendMessage" );
bRet = SUCCEEDED(SendSMSMessage(pSession, lpszFrom, lpszTo, lpszMessage));
if( bRet )
WriteString( L"Passed: SendSMSMessage - DoSendMessage" );
else
WriteString( L"Failed: SendSMSMessage - DoSendMessage" );
pSession->Logoff(0, 0, 0);
pSession->Release();
}
MAPIUninitialize();
return bRet;
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cjwn/archive/2009/02/08/3868466.aspx