【转】在Windows Mobile 6上通过CEMAPI 发送短信

原文: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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值