Categories: ComponentswxWidgets

Отправка SMS под wxWinCE с помощью CE MAPI

Появилась необходимость программно отправлять SMS с телефона под управлением Windows Mobile. Решил не изобретать велосипед и поиспользовать MAPI для этих целей. После недолгих поисков набрел на эту статью на CodeProject. Немного переделал код для использования с wxWidgets. Вот что получилось

wxSendSMS.h

#ifndef _WX_SMS_SENDER_H
#define _WX_SMS_SENDER_H

#include <wx/wx.h>
#include <atlbase.h>
#include <cemapi.h>
#include <mapiutil.h>

class wxSMSSender
{
public:
 virtual bool Send(const wxString & from,
  const wxString & to, const wxString & text) = 0;
};

class wxSMSSenderMAPI : public wxSMSSender
{
 HRESULT GetSMSFolder(const CComPtr<imsgStore>& msgStore,
  CComPtr<imapifolder>& folder);
 HRESULT GetSMSMsgStore(const CComPtr<imapisession>& session,
  CComPtr<imsgStore>& msgStore);
 HRESULT SendSMSMessage(const CComPtr<imapisession>& session,
  LPCTSTR lpszFrom, LPCTSTR lpszTo, LPCTSTR lpszMessage);
public:
 virtual bool Send(const wxString & from,
  const wxString & to, const wxString & text);
};

#endif

wxSendSMS.cpp

#include "wxSMSSender.h"

HRESULT wxSMSSenderMAPI::GetSMSFolder(
   const CComPtr<imsgStore>& msgStore,
   CComPtr<imapifolder>& folder)
{
 // Now get the Drafts folder.
 SPropTagArray propDefaultFolder;
 propDefaultFolder.cValues = 1;
 propDefaultFolder.aulPropTag[0] = PR_CE_IPM_DRAFTS_ENTRYID;

 ULONG values;
 LPSPropValue propVals;
 HRESULT hr = msgStore->GetProps(&propDefaultFolder,
  MAPI_UNICODE, &values, &propVals);
 if (FAILED(hr))
 {
  return hr;
 }

 SBinary& eidDrafts = propVals->Value.bin;

 hr = msgStore->OpenEntry(eidDrafts.cb, (LPENTRYID)eidDrafts.lpb,
  NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&folder);
 return hr;
}

HRESULT wxSMSSenderMAPI::GetSMSMsgStore(
   const CComPtr<imapisession>& session,
   CComPtr<imsgStore>& msgStore)
{
 // first we get the msgstores table from the session
 CComPtr<imapitable> table;
 HRESULT hr = session->GetMsgStoresTable(MAPI_UNICODE, &table);
 if (FAILED(hr))
 {
  return FALSE;
 }

 // 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 = table->QueryRows(1, 0, &pRowSet);

  // If we failed to query the
  // rows then we need to break
  if (FAILED(hr)) break;

  // 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 = session->OpenMsgStore(NULL, blob.cb,
    (LPENTRYID)blob.lpb, NULL, 0, &msgStore);
  }
  else
  {
   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 values;
  SPropValue* pProps = NULL;
  hr = msgStore->GetProps(&props, MAPI_UNICODE, &values, &pProps);
  if (FAILED(hr) || values != 1)
  {
   break;
  }

  // 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))
 {
  msgStore.Release();
 }

 return hr;
}

HRESULT wxSMSSenderMAPI::SendSMSMessage(const CComPtr<imapisession>& session,
   LPCTSTR lpszFrom, LPCTSTR lpszTo, LPCTSTR lpszMessage)
{

 // now get the SMS message store
 CComPtr<imsgStore> msgStore;
 HRESULT hr = GetSMSMsgStore(session, msgStore);
 if (FAILED(hr)) return hr;

 CComPtr<imapifolder> folder;
 hr = GetSMSFolder(msgStore, folder);
 if (FAILED(hr)) return hr;

 CComPtr<imessage> message;
 hr = folder->CreateMessage(NULL, 0 ,&message);
 if (FAILED(hr)) return hr;

 // 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 = message->ModifyRecipients(MODRECIP_ADD, &adrlist);
 if (FAILED(hr)) return hr;

 // 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 = message->SetProps(sizeof(props) / sizeof(SPropValue),
  (LPSPropValue)&props, NULL);
 if (FAILED(hr)) return hr;

 // having set all the required fields we can now
 // pass the message over to the msgstore transport
 // to be delivered.
 hr = message->SubmitMessage(0);
 if (FAILED(hr)) return hr;

 return FALSE;
}

bool wxSMSSenderMAPI::Send(const wxString & from,
  const wxString & to, const wxString & text)
{
 do
 {
  HRESULT hr = MAPIInitialize(NULL);
  if (FAILED(hr)) break;
  CComPtr<imapisession> mapiSession;
  hr = MAPILogonEx(0 ,NULL, NULL, 0, &mapiSession);
  if (FAILED(hr)) break;
  bool result = SUCCEEDED(SendSMSMessage(mapiSession,
   from.GetData(), to.GetData(), text.GetData()));
  mapiSession->Logoff(0, 0, 0);
  mapiSession.Release();
  MAPIUninitialize();
  return result;
 }
 while(false);
 return false;
}

А пользоваться этим всем очень просто:

wxSMSSenderMAPI sender;
if(!sender.Send(m_FromTextCtrl->GetValue(),
 m_ToTextCtrl->GetValue(), m_SMSTextCtrl->GetValue()))
{
 wxMessageBox(_("Не могу отправить SMS!"));
}

Исходный код примера отправки SMS с помощью CE MAPI для Windows Mobile
Скриншот тестового приложения:

Отправка SMS с помощью CE MAPI - Скришот под Windows Mobile

T-Rex

Share
Published by
T-Rex

Recent Posts

Разработка кроссплатформенных модульных приложений на C++ с библиотекой wxWidgets

Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…

10 years ago

wxWidgets App With Plugins (Windows/Linux/Mac) – Sample Source Code

I can see that there is still a lot of topics at wxWidgets forums related…

11 years ago

wxToolBox is Now Open-Source!

I've just published the source code of wxToolBox component and a couple of sample apps at…

11 years ago

Microsoft Kinect Helper Library and Sample for wxWidgets

Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…

13 years ago

wxJSON 1.1.0 Released

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…

14 years ago

wxRuby. Оно даже работает!

Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…

15 years ago