Портал DotNETForDevices.com опубликовал статью о создании приложений, использующих GPS.
Скачать статью в PDF (зеркало)
Скачать пример к статье (зеркало)

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

M.

Mobile Application Blocks. Наконец-то дождались!

На CodePlex наконец-то появился первый релиз Mobile Application Block.

Mobile Application Block – это набор готовых решений типовых задач, возникающих при разработке приложений для мобильных устройств на платформе .NET Compact Framework.

Как пишут сами авторы, это порт Mobile Client Software Factory для Visual Studio 2008 с более легковесным механизмом Dependency Injection.

В текущей версии доступны такие блоки как:

  • Configuration
  • ConnectionMonitor
  • ContainerModel
  • DataAccess
  • DisconnectedAgent
  • EndpointCatalog
  • PasswordAuthentication

Диаграммы классов нескольких блоков можно посмотреть ниже:

Mobile Application Block - Configuration - Class Diagram
Mobile Application Block - Configuration - Class Diagram
Mobile Application Block - ContainerModel - Class Diagram
Mobile Application Block - ContainerModel - Class Diagram

Mobile Application Block - Disconnected Agent - Class Diagram
Mobile Application Block - Disconnected Agent - Class Diagram

Все это добро весит совсем немного, после установки для каждого блока создается Visual Studio Solution с примером и юнит-тестами, так что процесс ознакомления с функционалом, предоставляемым MAB должен пройти быстро и безболезненно.

Скачать Mobile Application Block можно на странице проекта.

П.

Программная отправка SMS на C++ с помощью 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
Скриншот тестового приложения: