Сегодня Microsoft опубликовала информацию о том, как будет функционировать online-сервис продажи мобильных приложений Windows® Marketplace for Mobile.

Итак, информация к размышлению:

  1. Сколько будет зарабатівать разработчик на продаже своих приложений?
    • Разработчик будет получать 70% от продаж в Windows Marketplace for Mobile (на сколько я понимаю, процент сравним с AppStore от Apple).
    • Приложение может продаваться на 29 торговых площадках (markets) с ценовым разграничением по каждой из них.
    • Также приложение может распространяться бесплатно, т.е. в Windows Marketplace for Mobile можно будет запостить и бесплатные приложения.
  2. Что нужно для регистрации?
    • Информация о регистрации будет доступна чуть позже (весной). Прием приложений планируется начать к лету.
    • Разработчики смогут выкладывать 5 приложений ежегодно за $99. И еще прийдется платить по $99 за каждое дополнительное приложение.
    • Для студентов, участвующих в программе DreamSpark, цены будут значительно снижены.
  3. Что нужно для того, чтобы приложение попалов Marketplace?
    • Сказано, что значительное внимание будет уделено совместимости и корректной работе приложений на мобильных устройствах. Планируется организовать процесс сертификации и тестирования приложений, выкладываемых в Marketplace.
    • разработчикам будет предоставляться детальная информация о результатах сертификации на Windows Marketplace for Mobile developer portal.
  4. Что нужно для того, чтобы начать разработку для Windows Mobile?
    • Можно использовать Visual Studio и .NET Compact Framework 3.5 (я так понимаю, они это говорят в рекламных целях, C++ еще вроде никто не отменял).
    • Скачать Windows Mobile 6.0 SDK и ознакомиться с информацией на http://developer.windowsmobile.com.

Ознакомиться с пресс-релизом можно здесь.

Интервью с Inigo Lopez, Marketplace Product Manager:

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

This post has 2 Comments

2
  1. Вообще-то в платформе .Net Можно писать и на C++ и на еще целом ряде языков в том и фишка платформы. Идея платформы – использование промежуточного универсального байт-кода. Не зависимого от процессора и высокоуровнего языка, при этом можно подключать даже модули написанные на разных языках.
    http://ru.wikipedia.org/wiki/Microsoft_.NET

  2. Вообще-то в платформе .Net Можно писать и на C++

    У Вас получилось написать приложение для Windows Mobile на Managed C++ и .NET CF? Хотел бы я на это посмотреть. Managed C++ не поддерживается для Smart Device проектов.
    А банальные обертки к unmanaged-библиотекам это совсем не то что хотелось бы.

Leave a Reply

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

У.

Уиии! iPhone OS 3.0 Released!!!

iPhone OS 3.0 Preview Event

Обновление ПО iPhone 3.0

Ссылки для скачивания прошивок
iPhone 2G | iPhone 3G

Это обновление содержит около 100 новых функций, включая перечисленные ниже:

  • Команды «Вырезать», «Копировать» и «Вставить» с функцией отмены путем встряхивания
  • Клавиатура в горизонтальном положении в ключевых программах
  • Улучшена программа «SMS/MMS»
    • Отправка и получение фотографий, контактов, аудиофайлов и ссылок на местоположение по MMS*
    • Переадресация и удаление одного или нескольких сообщений
  • Добавлена функция поиска в программах Mail, «Календарь», «Заметки» и iPod
  • Поиск Spotlight по всему iPhone
  • Поддержка CalDAV и подписок в программе «Календарь»
  • Улучшения в работе Safari
    • Производительность
    • Поддержка HTML 5
    • HTTP-стриминг аудио и видео
    • Автозаполнение имен и паролей
  • Новая программа «Диктофон»
  • Синхронизация заметок на Mac или ПК с Windows через iTunes
  • Доступ к Интернету в режиме модема через USB и Bluetooth*
  • Поиск и загрузка фильмов, телешоу и аудиокниг из iTunes Store**
  • Стерео Bluetooth***
  • Автоматический вход в сети Wi-Fi
  • Улучшена программа «Акции»
  • Дополнительные параметры функции «Родительский контроль» для программ, музыки, фильмов и телешоу
  • Создание и вход в учетную запись iTunes**
  • Вход в учетную запись YouTube и доступ к подпискам, рейтингам и Избранному**
  • Функция перемешивания элементов плейлистов встряхиванием
  • Добавлены языки, словари и клавиатуры
  • Функции «Найти мой iPhone» и «Удаленное стирание» (Remote Wipe) через MobileMe (необходима подписка)**
  • Поддержка еще большего количества политик Exchange
  • Создание и отправка приглашений на совещания и встречи Exchange
  • Поиск сообщений электронной почты на сервере (Exchange Server 2007 и поддерживаемые серверы IMAP)
  • Поиск в корпоративном каталоге LDAP
  • VPN по требованию и поддержка прокси VPN
  • Шифрование профилей конфигурации
  • Шифрование резервных копий iTunes
  • 1000 новых интерфейсов прикладного программирования (API) для разработчиков, включая:
    • Встроенные покупки
    • Служба Push-уведомлений Apple
    • Поддержка аксессуаров
    • Одноранговое подключение Peer to Peer
    • Встроенные карты
    • Доступ к медиатеке iPod
  • Исправления ошибок

Продукты, совместимые с этим обновлением ПО:

  • iPhone
  • iPhone 3G
  • iPhone 3G S
  1. P2P-соединение для многопользовательских игр требует установки соответствующих приложений.
  2. С момента появления в App Store, они доступны для загрузки.
    MMS не поддерживается iPhone первого поколения. Отправка видео не поддерживается iPhone 3G.
  3. Для загрузки файлов объёмом свыше 10 МБ необходимо подключение к Wi–Fi.
  4. Использование телефона в качестве модема в настоящее время не доступно в США и некоторых других странах. Обратитесь к своему мобильному оператору за подробностями.

Обсуждение на Хабре.

О.

Отправка USSD-запроса в Windows Mobile

В этот раз будем учиться делать странное, а именно отправлять USSD-запрос оператору мобильной связи с помощью TAPI в Windows Mobile.

USSD (Unstructured Supplementary Service Data) — стандартный сервис в сетях GSM, позволяющий организовать интерактивное взаимодействие между абонентом сети и сервисным приложением в режиме передачи коротких сообщений. – Wikipedia

На самом деле USSD-запросы это то, чем каждый из нас пользуется довольно часто, например, при пополнении счета или при запросе состояния счета у оператора мобильной связи.

Примеры USSD-запросов:

  • *101#
  • *100*111122223333444455#

Вот именно такой финт ушами мы и будем пытаться реализовать с помощью программных средств.

Долгих вступлений не будет, а будет сразу практика с простеньким примером. Рассмотрим простейшее приложение, которое отправляет запрос состояния счета мобильному опреатору.

Для начала нам надо инициализировать TAPI.

#include <windows.h>
#include <tapi.h>
#include <extapi.h>
#include <tsp.h>

#define EXT_API_LOW_VERSION     0x00010000
#define EXT_API_HIGH_VERSION    0x00010000

long InitializeTAPI(HLINEAPP & lineApp, DWORD & lowAPIVersion, DWORD & deviceCount)
{
	LINEINITIALIZEEXPARAMS	lineParams;
	ZeroMemory(&lineParams,sizeof(LINEINITIALIZEEXPARAMS));

	lineParams.dwTotalSize	= sizeof(LINEINITIALIZEEXPARAMS);
	lineParams.dwOptions	= LINEINITIALIZEEXOPTION_USEHIDDENWINDOW; 

	lowAPIVersion = TAPI_CURRENT_VERSION;

	return lineInitializeEx(&lineApp,
		(HINSTANCE)GetModuleHandle(NULL),
		LineCallback,
		L"wxUSSDRequest",
		&deviceCount,
		&lowAPIVersion,
		&lineParams);
}

LineCallback – это callback-функция, которая будет вызываться при наступлении событий TAPI.

void FAR PASCAL LineCallback(DWORD hDevice,
							 DWORD dwMsg,
							 DWORD dwCallbackInstance,
							 DWORD dwParam1,
							 DWORD dwParam2,
							 DWORD dwParam3)
{
	switch(dwMsg)
	{
	case LINE_DEVSPECIFIC:
		{
			if(dwParam1 == LINE_USSD)
			{
				DWORD	dwMessageId	= dwParam2;
			}

			break;
		}
	case LINE_REPLY:
		{
			if(dwParam2 == 0) return;
			wprintf(L"Error: ");	
			switch(dwParam2)
			{
			case LINEERR_INVALLINEHANDLE:		wprintf(L"LINEERR_INVALLINEHANDLE");	break;
			case LINEERR_NOMEM:					wprintf(L"LINEERR_NOMEM");				break;
			case LINEERR_OPERATIONUNAVAIL:		wprintf(L"LINEERR_OPERATIONUNAVAIL");	break;
			case LINEERR_OPERATIONFAILED:		wprintf(L"LINEERR_OPERATIONFAILED");	break;
			case LINEERR_RESOURCEUNAVAIL:		wprintf(L"LINEERR_RESOURCEUNAVAIL");	break;
			case LINEERR_INVALPOINTER:			wprintf(L"LINEERR_INVALPOINTER");		break;
			case LINEERR_INVALPARAM:			wprintf(L"LINEERR_INVALPARAM");			break;
			case LINEERR_UNINITIALIZED:			wprintf(L"LINEERR_UNINITIALIZED");		break;
			default:							wprintf(L"Error: %x",dwParam2);			break;
			}
			wprintf(L"\r\n");
			break;
		}
	}
}

Затем нужно получить идентификатор телефонной линии. Сделать это можно с помощью функции lineGetDevCaps.

long GetCellularLineID(HLINEAPP lineApp,
					   DWORD lowAPIVersion,
					   DWORD deviceCount,
					   DWORD & apiVersion)
{
	DWORD				dwReturn		= 0xFFFFFFFF;
	long				lResult			= 0;
	LINEEXTENSIONID		sLineExt		= {0};
	LPLINEDEVCAPS		lpLineDevCaps	= NULL;	
	BOOL				bContinue		= TRUE;

	for(DWORD dwLine = 0; dwLine < deviceCount && bContinue; ++dwLine)
	{
		lResult		= lineNegotiateAPIVersion(lineApp,
			dwLine,
			lowAPIVersion,
			TAPI_CURRENT_VERSION,
			&apiVersion,
			&sLineExt);

		if(0 == lResult)
		{
			lpLineDevCaps	= (LPLINEDEVCAPS)LocalAlloc(LPTR,sizeof(LINEDEVCAPS));
			lResult			= LINEERR_STRUCTURETOOSMALL;

			lpLineDevCaps->dwTotalSize	= sizeof(LINEDEVCAPS);
			lpLineDevCaps->dwNeededSize	= sizeof(LINEDEVCAPS);

			while(LINEERR_STRUCTURETOOSMALL == lResult)
			{
				lResult	= lineGetDevCaps(lineApp,dwLine,TAPI_CURRENT_VERSION,0,lpLineDevCaps);

				if(LINEERR_STRUCTURETOOSMALL == lResult || lpLineDevCaps->dwTotalSize < lpLineDevCaps->dwNeededSize)
				{
					lpLineDevCaps	= (LPLINEDEVCAPS)LocalReAlloc(lpLineDevCaps,lpLineDevCaps->dwNeededSize,LMEM_MOVEABLE);
					lResult			= LINEERR_STRUCTURETOOSMALL;

					lpLineDevCaps->dwTotalSize	= lpLineDevCaps->dwNeededSize;
				}
			}

			if(0 == lResult)
			{
				TCHAR szName[512];

				memcpy((PVOID)szName,(PVOID)((BYTE*)lpLineDevCaps + lpLineDevCaps ->dwLineNameOffset), 
					lpLineDevCaps->dwLineNameSize);

				szName[lpLineDevCaps->dwLineNameSize]	= 0;

				if(_tcscmp(szName,CELLTSP_LINENAME_STRING) == 0)
				{
					dwReturn	= dwLine;
					bContinue	= FALSE;
				}
			}

			LocalFree((HLOCAL)lpLineDevCaps);
		}
	}

	return dwReturn;
}

Теперь нужно открыть телефонную линию для последующей работы с ней. Делается это с помощью функции lineOpen.

HLINE OpenTAPILine(HLINEAPP lineApp, DWORD cellularID, DWORD apiVersion)
{
	DWORD	dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;
	HLINE	hLine		= NULL;
	DWORD	extVersion	= 0;
	long	lReturn		= lineOpen(lineApp, 
		cellularID, 
		&hLine,
		TAPI_CURRENT_VERSION, 0,
		(DWORD)NULL,
		LINECALLPRIVILEGE_OWNER,
		dwMediaMode, 0);

	lReturn = ::lineNegotiateExtVersion(lineApp,
		cellularID,
		apiVersion, 
		EXT_API_LOW_VERSION, 
		EXT_API_HIGH_VERSION, 
		&extVersion);

	return hLine;
}

После завершения работы с TAPI необходимо обязательно закрыть все хэндлы.

void ShutdownTAPI(HLINE cellularLine, HLINEAPP lineApp)
{
	if(cellularLine)
	{
		lineClose(cellularLine);
	}

	if(lineApp)
	{
		lineShutdown(lineApp);
	}
}

И вот мы добрались до самого интересного, а именно до того момента, когда нам все предыдущие части кода нужно использовать для достижения конечной цели – зохвата мира отправки запроса.

int wmain()
{
	HLINEAPP lineApp = NULL;
	DWORD lowAPIVersion = 0;
	DWORD apiVersion = 0;
	DWORD deviceCount = 0;
	DWORD cellularID = 0;
	HLINE cellularLine = NULL;
	TCHAR command[] = _T("*101#");
	int errorCode;

	do
	{
		if(InitializeTAPI(lineApp, lowAPIVersion, deviceCount) != 0) 
		{
			errorCode = 1;
			break;
		}
		cellularID = GetCellularLineID(lineApp, lowAPIVersion, deviceCount, apiVersion);
		if(cellularID == 0xFFFFFFFF)
		{
			errorCode = 2;
			break;
		}
		cellularLine = OpenTAPILine(lineApp, cellularID, apiVersion);
		if(cellularLine == NULL)
		{
			errorCode = 3;
			break;
		}
		// Супер-строчка, которая отправляет USSD-запрос !!! Уиииии!
		if(lineSendUSSD(cellularLine, (const BYTE* const)command, sizeof(command), 0) < 0)
		{
			errorCode = 4;
			break;
		}
		return 0;
	}
	while(false);
	ShutdownTAPI(cellularLine, lineApp);
	return errorCode;
}
&#91;/sourcecode&#93;
И вот, вызов <a href="http://msdn.microsoft.com/en-us/library/ms862581.aspx" title="Отправка USSD запроса">lineSendUSSD</a> - это то к чему мы так стремились. Функция принимает в качестве параметров хэндл телефонной линии, строку запроса и длину запроса. В случае успешного завершения работы возвращается нулевой результат. В случае ошибки возвращается отрицательное значение.

И в качестве дополнения ко всему сказанному выше, класс-обертка для wxWinCE:

<strong>wxUSSDRequest.h</strong>

#ifndef _WX_USSD_REQUEST_H
#define _WX_USSD_REQUEST_H

#include <wx/wx.h>
#include <tapi.h>
#include <extapi.h>
#include <tsp.h>

class wxUSSDRequest
{
	long InitializeTAPI(DWORD & lowAPIVersion,
		DWORD & deviceCount);
	long GetCellularLineID(DWORD lowAPIVersion,
		DWORD deviceCount,
		DWORD & apiVersion);
	HLINE OpenTAPILine(DWORD cellularID, DWORD apiVersion);

	void ShutdownTAPI();

	static void FAR PASCAL LineCallback(DWORD hDevice,
		DWORD dwMsg,
		DWORD dwCallbackInstance,
		DWORD dwParam1,
		DWORD dwParam2,
		DWORD dwParam3);
public:
	wxUSSDRequest();
	~wxUSSDRequest();

	bool SendUSSDCommand(const TCHAR * command, DWORD length);
	int Init();
	bool IsOK();
private:
	HLINEAPP m_LineApp;
	HLINE m_CellularLine;
	bool m_IsOK;
};

#endif

wxUSSDRequest.cpp

#include "wxUSSDRequest.h"

#define EXT_API_LOW_VERSION     0x00010000
#define EXT_API_HIGH_VERSION    0x00010000

wxUSSDRequest::wxUSSDRequest()
: m_LineApp(NULL), m_CellularLine(NULL), m_IsOK(false)
{
	m_IsOK = (Init() == 0);
}

wxUSSDRequest::~wxUSSDRequest()
{
	ShutdownTAPI();
}

int wxUSSDRequest::Init()
{
	int result(0);
	do
	{
		DWORD lowAPIVersion(0);
		DWORD deviceCount(0);
		if(InitializeTAPI(lowAPIVersion, deviceCount) != 0) 
		{
			result = 1;
			break;
		}
		DWORD apiVersion(0);
		DWORD cellularID = GetCellularLineID(lowAPIVersion, deviceCount, apiVersion);
		if(cellularID == 0xFFFFFFFF) 
		{
			result = 2;
			break;
		}
		m_CellularLine = OpenTAPILine(cellularID, apiVersion);
		if(m_CellularLine == NULL) 
		{
			result = 3;
			break;
		}
	}
	while(false);
	return result;
}

bool wxUSSDRequest::IsOK()
{
	return m_IsOK;
}

bool wxUSSDRequest::SendUSSDCommand(const TCHAR * command, DWORD length)
{
	if(lineSendUSSD(m_CellularLine, (const BYTE* const)command, length, 0) < 0)
	{
		return false;
	}
	return true;
}

long wxUSSDRequest::InitializeTAPI(DWORD & lowAPIVersion, DWORD & deviceCount)
{
	LINEINITIALIZEEXPARAMS	lineParams;
	ZeroMemory(&lineParams,sizeof(LINEINITIALIZEEXPARAMS));

	lineParams.dwTotalSize	= sizeof(LINEINITIALIZEEXPARAMS);
	lineParams.dwOptions	= LINEINITIALIZEEXOPTION_USEHIDDENWINDOW; 

	lowAPIVersion = TAPI_CURRENT_VERSION;

	return lineInitializeEx(&m_LineApp,
		(HINSTANCE)wxTheApp->GetInstance(),
		LineCallback,
		wxT("wxUSSDRequest"),
		&deviceCount,
		&lowAPIVersion,
		&lineParams);
}

void wxUSSDRequest::ShutdownTAPI()
{
	if(m_CellularLine)
	{
		lineClose(m_CellularLine);
	}

	if(m_LineApp)
	{
		lineShutdown(m_LineApp);
	}

	m_LineApp		= NULL;
	m_CellularLine	= NULL;
}

long wxUSSDRequest::GetCellularLineID(DWORD lowAPIVersion,
									  DWORD deviceCount,
									  DWORD & apiVersion)
{
	DWORD				dwReturn		= 0xFFFFFFFF;
	long				lResult			= 0;
	LINEEXTENSIONID		sLineExt		= {0};
	LPLINEDEVCAPS		lpLineDevCaps	= NULL;	
	BOOL				bContinue		= TRUE;

	for(DWORD dwLine = 0; dwLine < deviceCount && bContinue; ++dwLine)
	{
		lResult		= lineNegotiateAPIVersion(m_LineApp,
			dwLine,
			lowAPIVersion,
			TAPI_CURRENT_VERSION,
			&apiVersion,
			&sLineExt);

		if(0 == lResult)
		{
			lpLineDevCaps	= (LPLINEDEVCAPS)LocalAlloc(LPTR,sizeof(LINEDEVCAPS));
			lResult			= LINEERR_STRUCTURETOOSMALL;

			lpLineDevCaps->dwTotalSize	= sizeof(LINEDEVCAPS);
			lpLineDevCaps->dwNeededSize	= sizeof(LINEDEVCAPS);

			while(LINEERR_STRUCTURETOOSMALL == lResult)
			{
				lResult	= lineGetDevCaps(m_LineApp,dwLine,TAPI_CURRENT_VERSION,0,lpLineDevCaps);

				if(LINEERR_STRUCTURETOOSMALL == lResult || lpLineDevCaps->dwTotalSize < lpLineDevCaps->dwNeededSize)
				{
					lpLineDevCaps	= (LPLINEDEVCAPS)LocalReAlloc(lpLineDevCaps,lpLineDevCaps->dwNeededSize,LMEM_MOVEABLE);
					lResult			= LINEERR_STRUCTURETOOSMALL;

					lpLineDevCaps->dwTotalSize	= lpLineDevCaps->dwNeededSize;
				}
			}

			if(0 == lResult)
			{
				TCHAR szName[512];

				memcpy((PVOID)szName,(PVOID)((BYTE*)lpLineDevCaps + lpLineDevCaps ->dwLineNameOffset), 
					lpLineDevCaps->dwLineNameSize);

				szName[lpLineDevCaps->dwLineNameSize]	= 0;

				if(_tcscmp(szName,CELLTSP_LINENAME_STRING) == 0)
				{
					dwReturn	= dwLine;
					bContinue	= FALSE;
				}
			}

			LocalFree((HLOCAL)lpLineDevCaps);
		}
	}

	return dwReturn;
}

HLINE wxUSSDRequest::OpenTAPILine(DWORD cellularID, DWORD apiVersion)
{
	DWORD	dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;
	HLINE	hLine		= NULL;
	DWORD	extVersion	= 0;
	long	lReturn		= lineOpen(m_LineApp, 
		cellularID, 
		&hLine,
		TAPI_CURRENT_VERSION, 0,
		(DWORD)this,
		LINECALLPRIVILEGE_OWNER,
		dwMediaMode, 0);

	lReturn				= ::lineNegotiateExtVersion(m_LineApp,
		cellularID,
		apiVersion, 
		EXT_API_LOW_VERSION, 
		EXT_API_HIGH_VERSION, 
		&extVersion);

	return hLine;
}

void FAR PASCAL wxUSSDRequest::LineCallback(DWORD hDevice,
											DWORD dwMsg,
											DWORD dwCallbackInstance,
											DWORD dwParam1,
											DWORD dwParam2,
											DWORD dwParam3)
{
	switch(dwMsg)
	{
	case LINE_DEVSPECIFIC:
		{
			if(dwParam1 == LINE_USSD)
			{
				DWORD	dwMessageId	= dwParam2;
			}

			break;
		}
	case LINE_REPLY:
		{
			wxString strError;

			switch(dwParam2)
			{
			case 0:								strError	= wxEmptyString;						break;
			case LINEERR_INVALLINEHANDLE:		strError	= wxT("LINEERR_INVALLINEHANDLE");		break;
			case LINEERR_NOMEM:					strError	= wxT("LINEERR_NOMEM");					break;
			case LINEERR_OPERATIONUNAVAIL:		strError	= wxT("LINEERR_OPERATIONUNAVAIL");		break;
			case LINEERR_OPERATIONFAILED:		strError	= wxT("LINEERR_OPERATIONFAILED");		break;
			case LINEERR_RESOURCEUNAVAIL:		strError	= wxT("LINEERR_RESOURCEUNAVAIL");		break;
			case LINEERR_INVALPOINTER:			strError	= wxT("LINEERR_INVALPOINTER");			break;
			case LINEERR_INVALPARAM:			strError	= wxT("LINEERR_INVALPARAM");			break;
			case LINEERR_UNINITIALIZED:			strError	= wxT("LINEERR_UNINITIALIZED");			break;
			default:							strError.Format(_("Error: %x"),dwParam2);			break;
			}

			if(!strError.IsEmpty())
			{
				wxLogError(strError);
			}
			break;
		}
	}
}

Пример использования

wxUSSDRequest * m_USSDRequest;
...
wxUSSDRequest * GetUSSDRequest() const { return m_USSDRequest ; }
...
void wxUSSDRequestMainFrame::OnSENDClick( wxCommandEvent& event )
{
	do
	{
		if(!wxGetApp().GetUSSDRequest() || !wxGetApp().GetUSSDRequest()->IsOK()) break;
		wxString command = m_USSDTextCtrl->GetValue().GetData();
		if(!wxGetApp().GetUSSDRequest()->SendUSSDCommand(command, 
			command.Length() * sizeof(wxChar)))
		{
			wxLogError(_("Error sending USSD message '%s'"),
				m_USSDTextCtrl->GetValue().GetData());
		}
	}
	while(false);
}

Скачать исходный код примера.