23 July 2009

Перевод: 30 дней Windows Mobile, день третий — GPS Compass (.NET vs WinAPI/C)

Development of mobile applications
Translation
Original author: Chris Craft и Christopher Fairbairn
Третья часть из цикла переводов. Сегодня у нас на очереди GPS Compass. Предыдущая статья, менеджер Bluetooth — http://habrahabr.ru/blogs/mobiledev/61703/.

Крис Крафт. C#


Оригинал находится здесь.

Я не дизайнер, но как уже говорилось раньше, приложение должно выглядеть привлекательным. Поэтому для GPS компаса я нашёл очень хорошее бесплатное изображение в Wikimedia. Когда основа для оформления была выбрана, осталось определиться с механизмом получения GPS-данных. Были доступны следующие варианты:
  1. получать данные через последовательный порт
  2. с помощью OpenNetCF GPS библиотеки
  3. используя GPS Intermediate Driver



Приложение GPS Compass Я остановился на третьем варианте, т.к. он достаточно новый и как говорится в документации «он полезен, т.к. обеспечивает промежуточный уровень абстракции между производителями GPS-устройств и разработчиками». Никто не изготавливает оборудование одинаковым образом — всегда существуют особенности и подводные камни.


Для тестирования приложения мне было необходимо устройство с GPS, и у меня даже такое было (AT&T Tilt), но, к сожалению, в помещении уровень сигнала стремился к нулю. К счастью у Microsoft нашлась утилита FakeGPS, как раз подходящая для моих целей. Данная утилита использует текстовый файл с GPS данными для эмуляции функционирования настоящего GPS-приёмника.

В документации я быстро обнаружил то, что нужно — описание структуры GPS_POSITION. Для моего простого приложения мне было необходимо только одно поле flHeading, в градусах. Север соответствует нулю.

На данном этапе в комплекте с Windows Mobile 6 SDK в примерах я обнаружил приложение GPS Application — C:\Program Files\Windows Mobile 6 SDK\Samples\PocketPC\CS\GPS

Безусловно, можно было всё написать с нуля, но я опять повторю — всегда старайтесь по максимуму использовать имеющиеся наработки.

В приложении был хороший статус-экран, вызов которого я вынес в меню. Однако, главная составляющая приложения, конечно же отображена на скриншоте выше. В принципе, на основе этого примера можно строить любые приложения, использующие GPS.

Скачать исходный код.

Прим. переводчика: Крис не любит приводить примеры кода в своих статьях, предпочитая сразу давать ссылку на файл с исходным кодом проекта. Однако, я позволяю себе делать особенно интересные вставки, если это актуально. В случае с GPS Compass приводить куски кода бесполезно, т.к. получится или слишком мало, или слишком много. Скажу одно — если бы у Криса не было под рукой приложения из SDK, намучился бы он капитально, т.к. в примере написаны все обёртки вокруг native-структур, перечислений и методов, данный пример ещё и хорош для изучения особенностей маршаллинга больших и сложных структур.

Кристофер Фэрбейрн. WinAPI — C


В Windows Mobile 5 и выше существует унифицированный API под названием GPS Intermediate Driver, который позволят множеству приложений одновременно использовать одно GPS-устройство. Это интерфейс высокого уровня, избавляющий нас от необходимости разбирать NEMA предложения и т.д.

Чтобы подключиться к GPS устройству нам необходимо подключить gpsapi.h и вызвать GPSOpenDevice
// Откроем соединение с GPS Intermediate Driver<br/>
HANDLE hGPS = GPSOpenDevice(NULL, NULL, NULL, 0);


* This source code was highlighted with Source Code Highlighter.


Данный API считает ссылки, это означает, что каждый вызов GPSOpenDevice должен обязательно иметь закрывающий GPSCloseDevice. GPS-оборудование отключится только когда последний клиент завершит соединение.


Далее для получения информации мы воспользуемся методами GPSGetPosition или GPSGetDeviceState для получения положения или статуса устройства соответственно. Например, чтобы получить текущее местоположение, можно воспользоваться следующим кодом:

GPS_POSITION pos;<br> <br>// Инициализируем структуру<br>memset(&pos, 0, sizeof(pos));<br>pos.dwVersion = GPS_VERSION_CURRENT;<br>pos.dwSize = sizeof(pos);<br> <br>// Просим GPS intermediate driver <br>// заполнить структуру.<br>GPSGetPosition(hGPS, &pos, 500000, 0);<br><br>* This source code was highlighted with Source Code Highlighter.


Обращаю внимание, что структура GPS_POSITION содержит поле dwValidFlags. Это битовая маска, которая говорит о том, какие поля содержат корректную информацию. Например, если в поле не выставлен флаг GPS_VALID_LATITUDE, это означает, что на поле dblLatitude нельзя полагаться.

В нашем GPS компасе мы используем одну интересную возможность. Передавая два обработчика событий в качестве параметров методу GPSOpenDevice, мы избавляем себя от необходимости периодически опрашивать устройство с помощью GPSGetPosition. Вместо этого мы просто ждём, пока не сработает то или иное событие, с гарантией получая данные, отличающиеся от ранее полученных значений.

Создание меню.


Это первое приложение, в котором потребовалось меню. Меню создаётся в редакторе ресурсов и загружается с помощью SHCreateMenuBar. Вызов данного метода обычно помещается в обработчике WM_INITDIALOG:

case WM_INITDIALOG:<br> // Configure the menu<br> SHMENUBARINFO mbi;<br> memset(&mbi, 0, sizeof(mbi));<br> mbi.cbSize = sizeof(mbi);<br> mbi.hWndParent = hWnd; // the dialog's handle<br> mbi.nToolBarId = IDR_MENU; // the menu resource id<br> mbi.hInstRes = GetModuleHandle(NULL);<br> mbi.dwFlags = SHCMBF_HMENU;<br> <br> // Create the menu<br> SHCreateMenuBar(&mbi);<br> break;<br><br>* This source code was highlighted with Source Code Highlighter.


Далее существует целый набор API для взаимодействия с элементами меню. Например, можно активирировать или деактивировать определённый элемент с помощью EnableMenuItem:
// Disable a menu item with id 'IDC_SOME_ITEM'<br>EnableMenuItem(hMenu, IDC_SOME_ITEM,<br> MF_BYCOMMAND | MF_GRAYED);<br> <br>// Enable a menu item with id 'IDC_SOME_ITEM'<br>EnableMenuItem(hMenu, IDC_SOME_ITEM,<br> MF_BYCOMMAND | MF_ENABLED);<br><br>* This source code was highlighted with Source Code Highlighter.


Обратите внимание, что один и тот же метод вызывается для установки различных состояний элементов меню. Правильное место для подобных вызовов — в обработчике WM_INITMENUPOPUP. Это сообщение посылается владельцу меню непосредственно перед отображением меню.

Скачать исходный код.

Заключение от переводчика


Что мне нравится в переводе сразу двух статей — Крис описывает, как по-быстрому накидать нужный функционал на C#, а Кристофер всегда копает глубже и описывает тонкости библиотек, которые зачастую просто не увидеть из .net, если не вникать. Соответственно, даже если нет необходимости или желания программировать на чистом WinAPI, знать, как всё устроено внутри, очень полезно.

Tags:windows mobilecompact frameworkwinapigps api
Hubs: Development of mobile applications
+8
1.7k 19
Comments 16