В данной статье описывается, как разрабатывать Windows-приложения для карманных компьютеров, поддерживающих .NET Compact Framework. Рассматривается весь цикл разработки, отладки и развертывания приложения, а также показываются отличия между .NET Framework и .NET Compact Framework.
Smart Device Extensions (SDE) for Microsoft Visual Studio .NET позволяет применить весь ваш опыт .NET-программирования при разработке Windows-приложений для устройств, поддерживающих Microsoft .NET Compact Framework. С помощью SDE можно создавать приложения для платформ Pocket PC и Microsoft Windows CE .NET, используя знакомые языки - Microsoft Visual Basic .NET и те же инструментальные средства и библиотеки классов, что и при разработке .NET-приложений для настольных компьютеров и серверов. Так как карманные устройства не поддерживают все возможности, предоставляемые их полноразмерными "сородичами", самое сложное - выяснить, какие составные части Microsoft .NET Framework претерпели изменения из-за приведения этой инфраструктуры в соответствие с ограниченными возможностями мобильных устройств. К счастью, среда Visual Studio полностью поддерживает мобильные устройства и, в частности, позволяет отлаживать на настольном компьютере приложения, рассчитанные на эти устройства.
Создавать SDE-приложения в Visual Basic .NET очень просто. Начнем с традиционного приложения "Здравствуй, мир!" для демонстрации всего процесса разработки, который состоит из следующих этапов.
Будем считать, что у вас имеется подключенное устройство или (при отсутствии настоящего устройства) эмулятор Pocket PC.
Рис. 1. Диалоговое окно New Project, шаблон Smart Device Application
Рис. 2. Smart Device Application Wizard
Вы должны увидеть приложение на Visual Basic .NET.
Теперь создадим небольшую тестовую программу.
MsgBox("Здравствуй, мир")
Visual Studio .NET свяжется с устройством и установит вашу программу. Прежде всего на устройство установится .NET Compact Framework, если этой инфраструктуры еще не было на устройстве. Затем ваше приложение будет скопировано в каталог \Program Files (по умолчанию). И, наконец, приложение запустится (или запустите его сами).
Рис. 4. Диалоговое окно "HelloWorld", показываемое на устройстве
Итак, мы создали приложение (пусть и тривиальное), развернули его на интеллектуальном устройстве. Все это наверняка показалось вам очень знакомым, так как при разработке других приложений в Visual Studio .NET вы делали почти то же самое. Теперь закончим разработку приложения и создадим редистрибутивный пакет, чтобы вы могли поделиться этой мощной программой с друзьями и удивить их своим мастерством программирования!
Так как мы хотим, чтобы наша программа для интеллектуального устройства выглядела как настоящее профессиональное приложение, добавим в нее значок (icon) и создадим редистрибутивный CAB-файл. Затем CAB-файл можно будет открыть и запустить щелчком или касанием указателя (tap), либо предварительно скопировать этот файл на устройство. CAB-файл можно запускать из любого места, так как он содержит всю информацию по установке, необходимую интеллектуальному устройству. При запуске CAB-файла из него автоматически извлекаются файлы приложения и помещаются в подкаталог каталога \Program Files с тем же именем, что и проект для интеллектуального устройства.
Вы можете управлять тем, куда устанавливаются файлы приложения. Для этого нужно перед запуском мастера CAB-файлов указать свой INF-файл (с расширением .inf) и при необходимости библиотеку Setup.dll. В INF-файле задаются каталоги, файлы, параметры и конфигурации. В файле Setup.dll (необязательном) содержатся функции, реализующие операции, которые выполняются при установке или удалении вашего приложения.
Теперь все готово к компиляции приложения и созданию редистрибутивного пакета.
На этом этапе CAB-файл программы можно скопировать на устройство. Однако сначала следует убедиться, что на устройстве уже установлена .NET Compact Framework. Если известно, что эта инфраструктура не установлена на устройстве или что требуется создать дистрибутив для других пользователей, тогда вы должны создать CAB-файл для инфраструктуры. По умолчанию эти CAB-файлы устанавливаются с SDE в каталог:
C:\Program Files\Microsoft Visual Studio .NET\ CompactFrameworkSDK\v1.0.3300\Windows CE\wce300\
CAB-файлы хранятся в подкаталогах в соответствии с типами процессоров устройств - например, файл с версией инфраструктуры для Pocket PC находится в подкаталоге \arm под именем netcf.cjk.ppc3.arm.cab. Файл с инфраструктурой для эмулятора содержится в подкаталоге \x86 под именем netcf.cjk.ppc3.x86.cab.
Итак, что же происходит в действительности, когда вы создаете и запускаете SDE-приложение HelloWorld? Самое важное, о чем нужно знать: когда вы выбираете создание SDE-проекта, вы начинаете работать с другим шаблоном, чем при создании настольного проекта. В частности, разработка ведется для .NET Compact Framework, а не для полной версии инфраструктуры.
Рассмотрим структуру только что созданной программы HelloWorld (в принципе, подойдет любой SDE-проект). Окна проекта показаны на рис. 9.
Рис. 9. Ссылки SDE-проекта
При разработке настольных приложений используются .NET Framework-сборки, размещаемые в Global Assembly Cache (GAC). Эти сборки находятся в кэше на каждом настольном компьютере, на котором установлена .NET Framework. Однако чтобы воспользоваться сборками при программировании для мобильного устройства, их приходится развертывать на этом устройстве. При установке SDE эти сборки копируются в подкаталог \CompactFrameworkSDK\v1.0.3300\Windows CE каталога Microsoft Visual Studio .NET. Если вы просмотрите содержимое этого подкаталога, то обнаружите подкаталоги arm, mips, sh3 и x86, соответствующие типам процессоров, поддерживаемых .NET Compact Framework. В этих подкаталогах находятся редистрибутивные CAB-файлы.
А сейчас немного базовой информации. При компиляции проекта в Visual Studio .NET исходный код компилируется в одну или несколько сборок (файлов с расширениями .EXE и .DLL). В этих .NET-сборках содержатся метаданные и код на языке MSIL (Microsoft Intermediate Language). Машинный исполняемый код в сборках не содержится. Вместо этого во время выполнения осуществляется компиляция по запросу (JIT-компиляция) MSIL-кода в машинный. Конечно, в ваших приложениях активно используются типы, определенные в библиотеке классов .NET Framework, которая также является набором сборок, содержащих метаданные и MSIL-код. Эти сборки скомпилированы и хранятся на вашем настольном компьютере в каталоге исполняющей среды.
Как вы могли догадаться, в SDE при компиляции сборок, использующих .NET Compact Framework, применяются те же принципы. Поскольку эти сборки содержат MSIL, а не машинный код, при разработке программы на настольном компьютере используются, по сути, те же сборки .NET Compact Framework, что и сборки, развертываемые на устройстве! Можно всесторонне исследовать какую-нибудь из сборок .NET Compact Framework, например, system.dll, с помощью утилиты ildasm.exe из состава .NET Framework SDK (она устанавливается с Visual Studio .NET)
Пожалуй, основная проблема при работе с мобильными устройствами - их аппаратные ограничения. Очевидно, размер экрана портативных устройств меньше, чем у компьютеров (обычно 320 x 240 пикселов). Мощность процессора у них еще меньше (в первую очередь по соображениям продления срока работы от аккумуляторной батареи). Объем памяти, обычно используемой для длительного хранения данных, у таких устройств тоже намного меньше, чем у компьютеров. Кроме того, используются несколько иные методы ввода. У типичного целевого устройства SDE имеется от 16 до 64 Мбайт памяти для постоянного хранения программ и для их выполнения.
При установке .NET Compact Framework требуется примерно 1,3 Мбайт дискового пространства (общий размер файлов - 2,0 Мбайт, но он сокращается за счет оптимизации хранения файлов в Windows CE). При запуске SDE-программы на устройстве загружаются CLR и код приложения, так что для работы SDE-программы, использующей Windows Forms, требуется минимум 1 Мбайт. Дополнительные копии такого приложения будут требовать значительно меньше памяти (около 0,75 Мб каждая).
Так как общий размер файлов .NET Compact Framework примерно в 20 раз меньше, чем в полной .NET Framework, и, например, Windows Forms-программа для устройства требует в 8 раз меньше памяти, очевидно, что .NET Compact Framework тщательно оптимизирована самыми разными способами.
В частности, в версии этой библиотеки для мобильных устройств полностью поддерживаются класс Collection, функции преобразования типов, управляющие символы, DateTime, MsgBox и общеупотребительные константы вроде CrLf. Но из библиотеки удалены:
Если проанализировать, какие возможности отсутствуют в .NET Compact Framework, то окажется, что большинство этих упрощений вполне оправданно. Например, в Windows CE используются собственная файловая система, так что код файлового ввода-вывода для Windows CE-устройств будет совершенно другим, чем для настольных компьютеров.
В большинстве программ для интеллектуальных устройств применяется пользовательский интерфейс на основе Windows. Поэтому изменения, внесенные в Windows Forms, представляют огромный интерес для разработчиков, желающих писать программы для устройств с малым форм-фактором. Поскольку приложения, использующие формы, должны быть отлично знакомы программисту на Visual Basic, ваш предыдущий опыт окажется весьма кстати.
Для начала посмотрим на список элементов управления, входящих в версию Windows Forms для .NET Compact Framework:
Button | PictureBox |
CheckBox | ProgressBar |
Combobox | RadioButton |
DomainUpDoan | StatusBar |
HScrollBar | TabControl |
Label | TextBox |
ListBox | Timer |
MainMenu | TrackBar |
NumericUpDown | VScrollBar |
Panel |
Как видите, основные элементы управления (и не только основные) по-прежнему присутствуют, так что разработка небольших приложений и утилит для интеллектуальных устройств не составляет сложности. Однако некоторые "продвинутые" элементы управления полной версии .NET Framework недоступны. Многие из них, например Command, PropertyStore и ToolTip, или не годятся для портативных устройств, или должны реализовываться в Windows CE совершенно по-другому. Некоторые элементы управления, например Splitter, требуют выполнения пользовательским интерфейсом операций, непривычных большинству пользователей, работающих с портативными устройствами. Другие элементы управления вроде CheckedListBox можно имитировать, комбинируя элементы более низкого уровня. Вы также обнаружите, что недоступны и другие возможности полной версии Windows Forms, такие как HTML Help и средства прямого взаимодействия с операционной системой, например NativeWindows, SendKeys, OSFeature (используется для поддержки тем) и SystemInformation.
В версии класса Form .NET Compact Framework поддерживаются более трех четвертей событий и методов и примерно половина свойств класса Form полной версии. Можно задавать цвета, некоторые стили, подключать меню. Нельзя создать MDI-приложение, показать форму в панели задач, реализовать операции drag-and-drop и обрабатывать ряд событий клавиатуры (например, нажатие кнопки Cancel), не используемые на портативных устройствах.
Рассмотрим один из элементов управления - TabControl - и обсудим, что в версии для .NET Compact Framework осталось прежним, а что изменилось. Как и раньше, вкладки настраиваются в TabPage Collection Editor:
Рис. 12. Элемент управления TabControl в TabPage Collection Editor
Возможностей для настройки внешнего вида вкладок меньше, чем в полной версии. Не поддерживаются такие "продвинутые" параметры, как свойства группы Behavior (AllowDrop, ContextMenu, ImeMode) и AutoScroll. Но эти параметры используются не часто. Единственное широко применяемое свойство, отсутствующее в компактной версии, - свойство Tag. То же относится и к самому TabControl: основные свойства UI сохранились, но некоторые возможности не применимы к Windows CE-устройствам, поэтому, например, свойства ContextMenu и ToolTipText отсутствуют в компактной версии. Другие свойства просто убраны для сокращения размера элемента управления. Отсутствуют и такие свойства, как Accessibility и DataBinding, - они зависимы от других средств .NET Framework, которые также отсутствуют.
Из-за меньшего размера экрана мобильных устройств есть вероятность, что придется полностью перерабатывать UI. В большинстве случаев при переносе существующих приложений на мобильное устройство единственное, о чем следует беспокоиться, - отсутствие некоторых элементов управления, из-за чего, возможно, придется создавать UI заново.
Так как у мобильного устройства крошечная клавиатура (или она вообще показывается на экране), ввести текст на мобильном устройстве не так просто, как на настольном или наладонном компьютере. Вам придется еще раз подумать о взаимодействии пользователя с приложением, чтобы как можно больше информации вводить через сенсорный экран или выделенные аппаратные кнопки.
.NET Compact Framework SDK, поставляемый с SDE, включает набор программ-примеров, демонстрирующих базовые приемы разработки для платформ портативных устройств. Вы можете использовать эти программы как основу для своих приложений. Доступны следующие примеры.
Кроме того, к этому документу прилагаются два примера, демонстрирующие некоторые аспекты программирования для интеллектуальных устройств на Visual Basic.
Одним из элементов управления, чаще всего используемых разработчиками на Visual Basic, является сетка того или иного вида, в которой показываются табличные данные. Хотя в .NET Compact Framework сетки отсутствуют, вместо них можно применить элемент управления ListView, выглядящий так же, как сетка:
Рис. 13. Пример ListView на мобильном устройстве
Как все это работает, показывается в примере Authors, прилагаемом к данному документу. Прежде всего нужно передать данные на устройство. В нашем примере XML-файл копируется на устройство на этапе разработки. Сначала вы должны добавить файл в проект, и обычно для этого используется команда Add Existing Item в Solution Explorer.
Кроме того, можно указать папку, в которую будут помещаться при развертывании исполняемый файл приложения и файл данных. Для этого нужно или задать Output File Folder в окне Properties проекта, или войти в диалоговое окно Properties проекта, выбрать подузел Device Extensions узла Common Properties и ввести путь в поле Output file folder. В нашем примере использовалась папка \Samples\VB.NET, так что в исходном коде также выполняется обращение к файлу в этой папке:
Private Const AUTHORSXML As String = "\Samples\VB.NET\AuthorsDB.xml"
Затем объявляем DataSet:
Private dsAuthors As System.Data.DataSet
Теперь мы готовы к тому, чтобы загрузить XML-файл в DataSet методом ReadXml:
Private Sub loadXMLData() dsAuthors = New DataSet("AuthorsDB") Try Dim fs As New FileStream(AUTHORSXML, FileMode.Open) Dim xr As New XmlTextReader(fs) dsAuthors.ReadXml(xr) xr.Close() fs.Close() Catch e As System.IO.FileNotFoundException MessageBox.Show("File " & AUTHORSXML & " not found.") Catch e As XmlException MessageBox.Show("XmlException occured") End TryEnd Sub
А вот обработчик события Load класса Form, где вызывается процедура загрузки, а затем DataSet перебирается в цикле, в котором все записи добавляются в элемент управления ListView:
Private Sub frmAuthors_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load loadXMLData() Dim dr As DataRow Dim it As ListViewItem For Each dr In dsAuthors.Tables("Authors").Rows it = New ListViewItem(dr("id").ToString()) it.SubItems.Add(dr("name").ToString()) it.SubItems.Add(dr("phone").ToString()) lvCompanies.Items.Add(it) NextEnd Sub
Наконец, мы задаем свойства элемента управления, в частности Columns. Это делается так же, как и для элемента управления ListView в полной версии .NET Framework, - или в период выполнения, или в редакторе свойств:
Рис. 14. Набор Columns элемента управления ListView
Программисты на Visual Basic традиционно использовали прямые обращения к DLL, входящим в состав Windows (а также к другим DLL), чтобы получить доступ к функциональности, не предоставляемой VB и его исполняющей средой. Первоначально Microsoft Win32 API применялся для работы с INI-файлами, затем - с реестром, а в дальнейшем Win32-функции стали широко использоваться для решения более сложных задач, таких как синхронизация процессов (например, WaitForMultipleObjects) или графические операции (BitBlit, StretchBlit и др.). Большинство этих функций теперь вызывается через классы базовой Framework Class Library. Без преувеличения можно сказать, что доступны тысячи таких классов. Но в некоторых приложениях все же приходится обращаться к Win32-функциям, не имеющим эквивалента в NET Framework (например, к GetPrivateProfileString). В управляемом коде для этого используется подмножество сервисов Interop, называемое PInvoke (сокращение от Platform Invocation). Имейте в виду, что при использовании PInvoke, разработчик не должен забывать о проблемах безопасности, возникающих при вызове неуправляемого кода, и учитывать их в своих программах.
И там, где .NET Compact Framework реализует лишь подмножество полной Framework Class Library, вы можете с помощью PInvoke получить доступ к отсутствующей функциональности, напрямую вызывая соответствующие функции Windows CE API. Так, в .NET Compact Framework-версии Windows Forms класс Cursor не реализован. К счастью, мы можем задействовать Win32-функции LoadCursor и ShowCursor для изменения вида курсора. В Windows CE эти функции находятся в библиотеке coredll.dll, и их объявления выглядят примерно так:
Declare Function LoadCursor Lib "coredll.dll" (ByVal zeroValue As Integer, ByVal cursorID As Integer) As IntegerDeclare Function SetCursor Lib "coredll.dll" (ByVal cursorHandle As Integer) As Integer
Какой-либо инструмент, например API Text Viewer, входящий в состав Visual Basic 6.0, позволяет выполнить большую часть работы по определению вида соответствующего оператора Declare. Кроме того, вам может потребоваться доступ к Windows CE SDK, чтобы определить, как именно должны вызваться API-функции на платформе Windows CE. В частности, вам может понадобиться передать функциям соответствующие константы и даже структуры. Например, чтобы задать форму курсора как в Windows, нужно знать числовой идентификатор такого курсора:
Private hourGlassCursorID As Integer = 32514 ' &H7F02
Тогда задать нужную форму курсора довольно легко:
cursorHandle = LoadCursor(0, hourGlassCursorID)
Законченная программа, показывающая, как все это работает, есть в примере WaitCursor, поставляемом с .NET Compact Framework SDK. Обратите внимание, что курсор "песочные часы" на интеллектуальном устройстве выглядит совершенно по-другому.
Конечно, есть и функциональность, доступная только в Windows CE; к ней тоже можно обращаться через PInvoke. Например, функция GetSystemPowerStatusEx имеется только в Windows CE API и предназначена для получения информации о состоянии дополнительной аккумуляторной батареи. В стандартном Win32 API такой функции нет. Объявление этой функции несколько сложнее, чем предыдущее объявление:
Declare Function GetSystemPowerStatusEx Lib "coredll" _ Alias "GetSystemPowerStatusEx" _ (<[In](), Out()> ByVal lpSystemPowerStatus As SYSTEM_POWER_STATUS_EX, _ ByVal fUpdate As Boolean) As Long
Первое, что бросается в глаза, - указание типов параметра в объявлении. Эти типы используются, чтобы задать, какие параметры являются входными и какие параметры будут возвращаться. Так как "In" является еще и ключевым словом Visual Basic, приходится заключать "In" в квадратные скобки. Типы "In" и "Out" определяются в InteropServices, следовательно, вы должны импортировать это пространство имен:
Imports System.Runtime.InteropServices
Далее вы заметите, что функция возвращает структуру SYSTEM_POWER_STATUS_EX. Чтобы работать с этой структурой, можно или воспользоваться ключевым словом Structure, или поместить ее определение в класс и соответственно упорядочить члены класса:
<StructLayout(LayoutKind.Sequential)> _Public Class SYSTEM_POWER_STATUS_EX Public ACLineStatus As Byte Public BatteryFlag As Byte Public BatteryLifePercent As Byte Public Reserved1 As Byte Public BatteryLifeTime As Int16 Public BatteryFullLifeTime As Int16 Public Reserved2 As Byte Public BatteryBackupFlag As Byte Public BackupBatteryLifeTime As Byte ' Ошибка в документации Public Reserved3 As Byte Public BackupBatteryLifePercent As Byte ' Ошибка в документации Public BackupBatteryFullLifeTime As ByteEnd Class
Обратите внимание, что два члена - BackupBatteryLifeTime и BackupBatteryLifePercent - на самом деле надо поменять местами, а в документации они идут в неправильном порядке.
Теперь вызов функции не представляет сложности:
Dim sps As New SYSTEM_POWER_STATUS_EX()ret = GetSystemPowerStatusEx(sps, False)
Ниже показан внешний вид нашей программы-примера и вкладки Power из апплета System в Settings при выполнении на карманном компьютере iPAQ, к которому подключена внешняя батарея. Для устройства, работающего от батареи и успевшего частично ее разрядить, мы увидим следующую картину:
Рис. 16. GetPowerStatusEx и Power на устройстве с частично разряженными батареями
Важно заметить, что не обязательно будут использоваться все поля структуры. Например, iPAQ не передает для внешней батареи, подключаемой по кабелю, BatteryBackupFlag и бит Charging, так что и в нашем примере, и во встроенном модуле Power показывается не вся возможная информация.
Данная статья с небольшими сокращениями и изменениями взята с сайта http://www.gotdotnet.ru