Разработка приложений

Активация и деактивация формы

Модель выполнения программ на карманном компьютере отличает­ся от поведения программ, работающих на обычном персональном компьютере. Например, на мобильных компьютерах используется один экземпляр запущенной программы. Аналогом подобного пове­дения на настольных компьютерах является почтовая программа Outlook Express, которая всегда запускается в одном экземпляре. При попытке запуска программы она просто активируется (если уже была запущена). При этом вторая копия программы не запускается.

При создании приложения для КПК разработчику не придется при­лагать никаких усилий для реализации подобного поведения. Среда выполнения. NET Compact Framework сама позаботится о том, чтобы запускался только один экземпляр программы. Следует помнить, что пользователь не должен сам закрывать программу. При запуске новой программы ее окно просто загораживает предыдущую программу.

Учитывая подобное поведение, нужно писать программы, которые не занимают много ресурсов системы. Однажды запущенное приложе­ние может находиться в памяти несколько дней, пока пользователь не перезагрузит компьютер или не закроет программу самостоятельно. Деактивированная программа закроется автоматически, если система обнаружит уменьшение свободной памяти при разрядке батареи. Но, тем не менее, иногда надо проследить, чтобы при закрытии программа освободила ресурсы, которые она использовала. Бывают ситуации, когда приложение под держивает соединение с базой данных или осу­ществляет связь с COM-портами. В этом случае система может не освободить занимаемые программой ресурсы. Для отслеживания со­стояния формы используются события Form. Deacti vate и Form. Act і vated. В листинге 7.1 приведен пример работы с этими событиями.

Листинг 7.1

private void Forml_Activated(object sender. EventArgs e)

{

// Здесь ваш код для восстановления связей с портами и т. д.

Листинг 7.1 (продолжение)

lblInfo. Text = "Приложение активировано”;

}

private void Forml_Deactivate(object sender. EventArgs e)

{

// Здесь ваш код для освобождения ресурсов lblInfo. Text — “Приложение деактивировано";

}

Так как приложение в неактивном состоянии может быть закрыто системой, то важно блокировать возможную потерю данных. Для этого нужно использовать событие Deactivate.

Закрыть или свернуть окно

Закрыть или свернуть — вот в чем вопрос. Компания Microsoft пред­ложила для мобильных приложений модель поведения программ, отличающую от принятой в настольных компьютерах. Когда пользователь щелкает на кнопке закрытия, то на самом деле окно программы не закрывается, а сворачивается. Для пользователей подобное поведение приложений кажется странным, поэтому не­которые разработчики создавали программы, которые позволяли закрывать приложения одним нажатием стилуса. Популярность таких программ говорит о том, что не всем пользователям понрави­лось поведение приложений, которые отнимают ресурсы у систе­мы. Но сейчас не нужно обсуждать целесообразность такого подхо­да к закрытию программ. Разработчик может создать приложение, которое позволит выбрать вариант закрытия приложения. Пользо­ватель может нажать кнопку закрытия, чтобы просто свернуть окно, либо выполнить команду меню Выход, чтобы действительно закрыть приложение.

Но бывают ли такие ситуации, когда действительно требуется при­нудительно закрывать программу? Такая необходимость возника­ет при отладке и тестировании программы в эмуляторе. При стан­дартной модели поведения довольно утомительно каждый раз вручную останавливать программу запущенную в эмуляторе. Ко­нечно, можно временно присвоить свойству Mi nimi zeBox при отлад­ке значение False, что поможет избавиться от этой проблемы. Но перед окончательным релизом программы надо все же поставить значение Тrue. Однако полагаться на свою память не стоит. Гораздо проще воспользоваться условной компиляцией.

При создании приложения надо использовать несколько строчек кода в конструкторе формы сразу после вызова процедуры Initial і zeComponent(), как показано в листинге 7.2.

Листинг 7.2

#if DEBUG

HinimizeBox = false;

#else

MinimizeBox = true;

#endif

Этот код стоит вынести на панель инструментов (рис. 7.1), что по­зволит быстро добавлять эту конструкцию в создаваемые прило­жения. Отныне все примеры в данной книге будут снабжаться этим кодом.

Разработка приложений

Рис. 7.1. Код условной компиляции на панели инструментов

Пиктограмма приложения

Любая серьезная программа должна иметь собственную пиктограм­му. Чтобы указать используемую пиктограмму, надо при помощи команды меню Project ► Properties открыть диалоговое окно Property

Pages, выбрать раздел Application и указать путь к файлу с пикто­граммой в свойстве Icon (рис. 7.2).

< — Мн.! wioft. Visual Studio

• t-ci г» Project Bulo ofcUB uau loue ЛіЛ» СогіпигЛу Me*i

Buid

BliJd Events Djtjg Resources Reference Paths Sign**

Devcej

№»*mwy nwn«! joacrtpp_c>

vrfaj. namespace fCrateApp_CS

Разработка приложений

;гй«ч *■ . — *

Output type Windows Appfcaaon

Рис. 7.2. Добавление пиктограммы для приложения

Разработка приложений

Создание собственных диалоговых окон

Сложные приложения часто используют несколько форм. Напри­мер, во многих программах имеется диалоговое окно 0 программе, в котором отображаются информация о программе, номер версии, сведения об авторе и логотип компании.

Для создания подобных форм хорошо подойдет собственное диа­логовое окно. Чтобы отобразить такое окно, используется метод ShowDi a log. Этот метод делает недоступным родительскую форму, пока диалоговое окно находится на экране. Диалоговое окно может возвращать результат вызова метода ShowDi a log не только себе, но и родительскому окну.

Предположим, что нужно создать специальное окно авторизации пользователя для доступа к программе. В состав проекта нужно вклю­чить новую форму, которая будет реализована как диалоговое окно проверки имени пользователя LogonForm. Это будет маленькое окно без четко очерченной границы. В нем надо разместить текстовое поле и две кнопки. Затем надо задать значения свойств FormBorderStyle, Size и Location. При загрузке основной формы и обработке события Load создается новый экземпляр объекта LogonForm и вызывается как

диалоговое окно. Данное окно может вернуть значения Dial ogResul t. OK, если пользователь ввел имя, или Dial ogResul t. Cancel, если он просто закрыл форму. Если было введено правильное имя, то главная форма продолжает свою работу. В противном случае приложение следует закрыть. Соответствующий код приведен в листинге 7.3.

ВНИМАНИЕ————————————————————

Чтобы элементы управления диалогового окна были доступны вы­зывающей форме, их надо объявить с модификатором public. По умолчанию используется модификатор private.

Листинг 7.3

private void Forml_Load(object sender, EventArgs e)

{

LogonForm LogonFrm = new LogonFormO;

if (LogonFrm. ShowDialogO = DialogResult. Cancel)

{

LogonFrm. Di spose(); this. CloseO;

}

else

{

this. Text +="-"+ LogonFrm. txtCheck. Text:

LogonFrm. Di spose():

}

}

После того как форма авторизации будет отображена на экране, нужно обработать события Cl і ck для нажатия кнопки проверки вве­денного имени пользователя или кнопки отмены. Первая кнопка проверяет правильность ввода имени. Если проверка завершилась успешно, то возвращается значение Di а 1 ogResul t. ОК. Это иллюстри­рует код, приведенный в листинге 7.4.

Листинг 7.4

private void butOKCl і ck( object sender, EventArgs e)

{

if (txtCheck. Text =* "Alex")

{

this. DialogResult = DialogResult. OK;

}

else

{

Листинг 7.4 (продолжение)

MessageBox. Show("В доступе отказано. Попробуйте еще раз", "Вход в програмну");

}

>

Если пользователь не знает имени для доступа к программе, то ему придется нажать кнопку Отмена. В этом случае обработчик собы­тия DutCancel Click, код которого приведен в листинге 7.5, возвра­щает значение Dial ogResul t. Cancel в главную форму, которая за­крывает приложение.

Листинг 7.5

private void butCancel_Click(object sender. System. EventArgs e) {

this. DialogResult = DialogResult. Cancel;

}

Создание заставки Splash Screen

Многие программы имеют так называемые заставки (splash screen). При загрузке формы сначала отображается окно с логотипом ком­пании, названием продукта и дополнительной информацией. Сле­дует реализовать приложение с подобным экраном, чтобы научить­ся использовать эту технологию.

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

Создание подобного окна практически не отличается от предыду­щего примера. Но в этом примере надо использовать таймер, кото­рый будет отвечать за появление и закрытие начальной заставки. Эта же форма будет использоваться как диалоговое окно для стан­дартного пункта меню 0 программе.

Итак, надо создать дополнительную форму AboutForm и задать зна­чения всех необходимых свойств окна. На форме надо располо­жить таймер, интервал срабатывания которого будет равен 3 с. Код, реализующий подобное поведение программы, приведен в ли­стинге 7.6.

Листинг 7.6

protected override void OnPaint(PaintEventArgs e)

{

StringFormat sf = new StringFormatO; sf. Alignment — StringAlignment. Center; sf. LineAlignment = StringAlignment. Center;

Graphics g = e. Graphics;

g. DrawString(".NET Compact Framework", this. Font.

new SolidBrush(Color. Blue), Screen. PrimaryScreen. Bounds, sf);

}

private void timerl_Tick(object sender, EventArgs e)

{

this. CloseO;

>

В событии OnPai nt формы About Form нужно установить свойства для вывода текста. При желании можно добавить отображение логоти­па. Через заданный интервал таймер просто закроет это окно. Код для основной формы MainForm приведен в листинге 7.7.

Листинг 7.7

public MainFormO {

Ini 11alі zeComponent();

#if DEBUG

MinimizeBox = false;

#el se

MinimizeBox = true;

#endi f

AboutForm about = new AboutFormO; about. ShowDi alog();

}

private void mnuAboutCl ick (object sender. EventArgs e)

{

AboutForm about = new AboutFormO: about. ShowDi alog();

}

Теперь при запуске приложения на экране сначала будет отображать­ся заставка. После истечения трех секунд она исчезнет, и пользова­тель увидит основную форму.

Поворот экрана

Устройства с операционной системой Pocket PC 2003 Second Edition и старше обрели долгожданную возможность поворачи­вать содержимое экрана. Раньше пользователям приходилось ус­танавливать дополнительные программы для достижения такого эффекта. А разработчики получили возможность управлять по­воротами экрана управляемыми методами только в. NET Compact Framework 2.0. Но зато теперь это можно сделать буквально од­ной строкой кода. Тем, кто по ряду причин должен по-прежнему использовать. NET Compact Framework 1.0, придется задейство­вать сложный код с вызовами функций API, который приведен в листинге 7.8. Сначала надо установить ссылку на пространство имен Mi crosoft. Wi ndowsCE. Forms. После этого следует просто исполь­зовать нужные свойства класса SystemSettіngs.

Листинг 7.8.

using Microsoft. WindowsCE. Forms;

// запоминаем настройки экрана

ScreenOrientation initialOrientation —

SystemSettі ngs. ScreenOri entati on;

private void butRot90_Clіck(object sender, EventArgs e)

{

// поворачиваем экран на 90 градусов SystemSettі ngs. ScreenOri entati on —

ScreenOri entati on. Angle90;

}

private void butRestore_Click(object sender, EventArgs e)

{

// восстанавливаем старую ориентацию

if (SystemSettіngs. ScreenOrientation !«■ initialOrientation)

{

try

{

SystemSettіngs. ScreenOrientation = initialOrientation; }

catch (Exception)

{

// Невозможно вернуться к старым настройкам

MessageBox. ShowC’He ногу восстановить " +

"предыдущую ориентацию экрана.");

}

}

}

Рекомендации по дизайну форм

Компания Microsoft выработала определенные рекомендации по дизайну форм, которых следует придерживаться. Эти рекоменда­ции можно найти в документации MSND. Так, например, в одной из статей указывается, что в некоторых случаях пользователь пред­почитает пользоваться пальцами вместо стилуса. Поэтому, если форма содержит кнопки, то они должны быть достаточно больши­ми, чтобы было удобно нажимать на них.

Рекомендуемые размеры кнопок для Pocket PC составляют 21 х х 21 пикселов, если пользователь применяет стилус, и 38 х 38 пик­селов, если он предпочитает нажимать кнопки пальцами. Также надо предусмотреть свободное пространство между элементами, чтобы избежать ошибочных нажатий. Если маленькие кнопки для копирования и удаления файлов находятся рядом, то пользовате­ли не раз вспомнят вас недобрым словом при неаккуратном нажа­тии на кнопки.

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

Готовые приложения

До сих пор мы с вами изучали примеры, которые могли бы стать частью настоящих программ. Но сейчас пришло время написать не­сколько приложений, которые уже можно использовать в реальной жизни. Так получилось, что первые две программы были написаны для смартфонов, о которых речь пойдет в дальнейших главах. Но при помощи этих примеров можно получить представление о программировании для этого класса устройств. К тому же, на их основе можно написать аналогичный пример для карманных ком­пьютеров, что поможет увидеть сходство в написании приложений для разных типов устройств.

Файловый менеджер для смартфона

Смартфоны под управлением Windows Mobile 2005 не имеют в со­ставе системы приложения, которое позволяет просматривать со­держимое папок и файлов. В этом разделе будет рассматриваться аналог Проводника для смартфона. Основой данного примера по­служил великолепный проект с открытым исходным кодом, кото­рый находится на сайте www. businessanyplace. net/7p~spfUeman. Ав­тор проекта Кристиан Форсберг (Christian Forsberg) любезно разрешил использовать его программу в качестве учебного посо­бия для этой книги.

Интересна история создания этого приложения. Сам автор ориги­нальной версии писал программу еще на Visual Studio, NET 2003 для смартфонов под управлением системы Smartphone 2003. Когда я скачал исходный код и попытался запустить его, то среда разра­ботки Visual Studio. NET 2005 предложила конвертировать проект. Я согласился, в результате получил новую версию проекта. Теперь, после переделки, проект запускался в Visual Studio 2005 и исполь­зовал эмулятор Smartphone 2003. Но мне захотелось использовать пример для смартфонов Windows Mobile 2005. Для этого достаточ­но было в свойствах проекта выбрать другую платформу. Снова несколько минут раздумий, и Visual Studio выдает еще раз переде­ланный проект. Но и этого мне мало. Проект по-прежнему исполь­зует. NET Compact Framework 1.0. После выбора нужных значений свойств проекта, он стал использовать. NET Compact Framework 2.0. Осталось лишь перевести некоторые команды на русский язык и ввести новые возможности. NET Compact Framework 2.0 вместо старых конструкций, которые применялись для. NET Compact Framework 1.0.

Зачем нужен файловый менеджер

Файловый менеджер необходим как для разработчиков, так и для пользователей. С его помощью можно просматривать содержимое папок, удалять лишние файлы, создавать новые папки и выполнять другие операции с файлами. Трудно сказать, почему Microsoft ре­шила не включать программу подобного рода в состав системы Windows Mobile. Кстати, производители смартфонов самостоятель­но добавляют файловые менеджеры собственной разработки в со­став стандартных программ. Но мы с вами напишем свою програм­му, что гораздо интереснее.

Графический интерфейс программы

У создаваемого приложения будет своя пиктограмма При запуске программа будет отображать содержимое папки My Documents. Сам графический интерфейс программы очень прост и понятен. Нави­гация по папкам осуществляется простым выделением нужной пап­ки и нажатием кнопки Enter. Для перехода на один уровень вверх нужно выделить папку, обозначенную двумя точками. Пункт меню Выход закрывает файловый менеджер, а пункт Меню позволяет вы­брать выполняемую операцию (рис 7.3).

Разработка приложений

Рис. 7.3. Общий вид файлового менеджера

Меню содержит команды для всех стандартных файловых опера­ций. Пользователь может удалять, копировать, добавлять и пере­именовывать файлы. Также имеется возможность работы с ярлы­ками. Чтобы использовать эту возможность, нужно сначала выбрать файл, выполнить команду Копировать, затем перейти в нужную пап­ку и выполнить команду Вставить ярлык. При выборе команды Свой­ства появляется соответствующее окно (рис. 7.4).

В этом окне отображается справочная информация о файле или папке. Пользователь сможет найти размер файла, дату его созда­ния и атрибуты файла, которые можно модифицировать.

■… "тсц

Ом:

on

(rated:

*

илимедом*

*

o’

MMM№

□Mfciv*

□ Емй-оШу

QHiaton

Рис. 7.4. Окно свойств

Код программы

Теперь можно приступить к написанию кода. При запуске програм­мы выполняется обработчик события Form Load. При загрузке ос­новной формы MainForm работает код, приведенный в листинге 7.9.

Листинг 7.9

Li stViewHelper. SetGradient(1 і stVi ew);

string bs = Path. DirectorySeparatorChar. ToStringO;

// Устанавливаем начальную папку this. path = bs + "My Documents" + bs;

// Заполняем список папок и файлов fillListO;

Сначала устанавливается внешний вид элемента listView с гради­ентной закраской фона. Затем устанавливается папка по умолча­нию My Documents, которую программа открывает при загрузке. Ме­тод fi 11 List заполняет список ListView содержимым открываемой папки. Сам код метода приведен в листинге 7.10.

Листинг 7.10

III <summary>

III Заполнение ListView списком папок и файлов III </summary> private void fill ListО {

Cursor. Current = Cursors. WaitCursor;

// Заполняем ListView списком папок и файлов // в выбранной папке ListViewItem lvi;

1 і stVi ew. Begi nUpdate(); listView. Items. ClearO;

// Если не корневая папка if(path. Length > 1)

{

// Добавляем папку "Вверх" lvi = new ListViewItem(UPDIR); lvi. Imagelndex = 0;

1 іstView. Iterns. Add(1vi);

}

// Добавляєм папки

string[] dirs = Directory. GetDirectories(path);

ArrayList list = new ArrayList(dirs. Length); for(int і — 0; і < dirs. Length; i++)

list. Add(dirs[i]); ~

1 і st. Sort(new Si mpleComparer()); foreach(string dir in list)

{

lvi = new ListViewItem(Path. GetFileName(dir)); lvi. Imagelndex = 0; listView. Items. Add(lvi);

}

// Добавляем файлы

string[] files — Directory. GetFiles(path); list = new ArrayList(files. Length); for(int і = 0; і < files. Length; i++) list. Add(files[i]); list. Sort (new SimpleComparerO); foreach(string file in list)

{

lvi = new ListViewItem(Path. GetFileName(file)); lvi. Imagelndex = 1;

1 і stVi ew. Iterns. Add(1vi);

}

1 і stVi ew. EndUpdate(); if(listView. Items. Count > 0)

{

// выделяем первый элемент 1 іstView. Items[0].Selected = true; listView. Items[0].Focused = true;

}

Cursor. Current = Cursors. Default;

}

Итак, посмотрим, что делает метод f і 11 Li St. Перед заполнением элемента списком файлов надо очистить его содержимое от преды­дущих записей при помощи метода Clear. После очистки списка надо проверить, является ли папка корневой. Если папка не корне­вая, то в список добавляется специальная папка «На один уровень выше». Затем в список добавляются все папки в отсортированном порядке.

После этого наступает очередь файлов. Они сортируются и зано­сятся в список. Наконец, первый элемент списка выделяется дру­гим цветом. Заодно на первом элементе устанавливается фокус вво­да. Навигация по папкам и файлам осуществляется с помощью кнопок и дополняется кнопкой Action. Код навигации приведен в листинге 7.11.

Листинг 7.11

III <summary>

III Навигация по папкам и файлам III </summary>

III <рагаш name="sender"></param>

III <param пате=пе"></рагат>

private void 1 іstView_ItemActivate(object sender.

System. EventArgs e)

{

Cursor. Current — Cursors. WaitCursor:

ListViewItem lvi — 1 і stV і ew. Iterns[1 і stVi ew. SelectedIndi ces[0]]: bool isFolder — lvi. Imagelndex = 0: if(lvi. Text = UPDIR)

{

path = path. Substrings, path. Substrings, path. Length — l).LastlndexOf(Path. DirectorySeparatorChar) + 1): fillListO;

}

else if(isFolder)

{

path += lvi. Text + Path. DirectorySeparatorChar; fillListO:

}

else

Shell Execute. Start(path + lvi. Text):

Cursor. Current = Cursors. Default;

}

После нажатия кнопки действия приложение получает информа­цию о выделенном пункте. Если выделена специальная папка пе­рехода на один уровень выше, то текущий путь заменяется путем к родительской папке. Если выделена папка, то путь меняется на

путь к выделенной папке. Если выделен файл, то приложение пы­тается запустить его с помощью ассоциированной программы.

Теперь разберем код для команд меню. Для команды Вырезать код приведен в листинге 7.12.

Листинг 7.12

private void cutMenuItem_Click(object sender, System. EventArgs e)

{

ListViewItem Ivi =

1 іstVіew.11ems[1 іstVіew. SelectedIndіces[0]]; clipboardFileName — this. path + Ivi. Text: clipboardAction — ClipboardAction. Cut:

}

Путь к текущему выбранному файлу сопоставляется с производи­мым действием. Код, выполняющийся после выбора команды Ко­пировать, приведен в листинге 7.13.

Листинг 7.13

private void copyMenuItemCl і ck (object sender, System. EventArgs e)

{

ListViewItem lvi =

1 і stVi ew. Iterns[listView. Selectedlndices[0]]; clipboardFileName = path + lvi. Text: clipboardAction = ClipboardAction. Copy;

}

Для команды меню Вставить код немного усложняется. Он приве­ден в листинге 7.14.

Листинг 7.14

private void pasteMenuItem Click(object sender,

System. EventArgs e)

{

// Если файл существует

string dest — path + Path. GetFileName(clipboardFileName); і f(Fi1e. Exi sts(dest))

{

if(MessageBox. Show("<I^n уже существует, перезаписать?", this. Text,

MessageBoxButtons. YesNo. MessageBoxIcon. Questі on,

, 2#! 73 продолжение jP’

Листинг 7.14 (продолжение)

MessageBoxDefaultButton. Button2) — DialogResult. Yes) File. Delete(dest);

el se

return;

}

// Перемещаем или копируем

string s = path. Substrings, path. Length — 1):

swi tch(clі pboardActi on)

{

case Cl іpboardAction. Cut:

File. Move(cl і pboardF і1eName. dest); break:

case Cl іpboardAction. Copy:

File. CopyCclipboardFileName, dest. false); break;

}

cl іpboardAction = Cl іpboardAction. None; clipboardFileName = string. Empty; fillListO;

}

Перед тем как вставить файл в другую папку, нужно удостоверить­ся, что в ней нет файла с таким именем. Если же такой файл суще­ствует, то надо предупредить пользователя и узнать, что он хочет сделать. Код для команды Вставить ярлык приведен в листинге 7.15.

Листинг 7.15

private void pasteShortcutMenuItem_Click(object sender.

System. EventArgs e)

{

int і * 2;

string s = string. Empty; string dest; while(true)

{

dest = path + "Shortcut" + s + " to " +

Path. GetFi1eName(Path. GetFi1eNameWi thoutExtensi on (clipboardFileName) + ".Ink"); ifUFile. Exists(dest)) break:

s = " (" + i. ToStringO + ")";

}

StreamWriter sw = new StreamWriter(dest); s = clipboardFileName; if(s. IndexOf(" ") > 0) s = + s + s = s. Length. ToStringO + "#" + s; sw. WriteLine(s); sw. CloseO; fillListO;

}

В этом коде создается уникальное имя ярлыка, которое затем запи­сывается в виде файла с добавлением. К имени ярлыка добавляет­ся расширение. LNK.

Код для команды Переименовать приведен в листинге 7.16.

Листинг 7.16

private void renameMenuItem_Click(object sender.

System. EventArgs e)

{

Cursor. Current — Cursors. WaitCursor;

ListViewItem lvi — listView. Items[11stView. SelectedIndices[0]]; bool isFolder = lvi. Imagelndex = 0; string s; if(isFolder) s = "папку"; else s = "файл";

NameForm nameForm ** new NameForm(this, "Переименовать " + s.

lvi. Text, new SetNameDelegate(SetRename)); if (nameForm. ShowDialogO = Dial ogResul t. OK) fillListO; listView. FocusO;

}

Сначала обрабатывается текущий выделенный элемент. Если пользо­ватель выделил папку, то для формы nameForm задается соответству­ющий заголовок Переименовать папку. Также из этой формы передает­ся в основную форму новое имя папки или файла с помощью метода Set Rename, как это показано в листинге 7.17.

Листинг 7.17

III <summary>

III Метод для переименования папки иЛи файла

Листинг 7.17 (продолжение)

III </summary>

III <рагат паше="пате">Имя папки или файла</рагаш> public void SetRename(string паше)

{

ListViewItem Iv1 =

1 і stV і ew.1terns[1 і stVі ew. Selectedlndices[0]]; bool isFolder = lvi. Imagelndex = 0; string itemName = path + lvi. Text; string destName = Path. GetDirectoryName(itemName) + Path. DirectorySeparatorChar. ToStringO + name; if(isFolder)

Directory. Move(itemName. destName); else

File. Move(itemName. destName);

}

После того как будет получена информация о выделенном элемен­те, он переименовывается. Для реализации команды Удалить исполь­зуется код, приведенный в листинге 7.18.

Листинг 7.18

private void deleteMenuItem_Click(object sender.

System. EventArgs e)

{

ListViewItem lvi =

listView. Items[listView. SelectedIndices[0]]; bool isFolder = lvi. Imagelndex = 0; string s = “Are you sure you want to delete " + lvi. Text; if(isFolder)

s ” and all its content”; s += "?";

if(MessageBox. Show(s. this. Text.

MessageBoxButtons. YesNo. MessageBoxIcon. Questі on. MessageBoxDefaultButton. Button2) — DialogResult. Yes)

{

if(isFolder)

Directory. Delete(path + lvi. Text, true): el se

File. Delete(path + lvi. Text): fillListO;

}

}

Перед удалением папки или файла запрашивается подтверждение действий пользователя. Для создания новой папки используется следующий код, приведенный в листинге 7.19.

Листинг 7.19

private void newFolderMenuItemCl ick (object sender,

System. EventArgs e)

{

Cursor. Current = Cursors. WaitCursor;

ListViewItem lvi =

1 і stV і ew. Iterns[listView. Selectedlndices[0]];

NameForm nameForm = new NameForm(this. "Новая папка".

new SetNameDelegate(SetNewName)): і f (nameForm. ShowDi alogO == DialogResult. OK) fillListO: listView. FocusO:

}

В результате действия этой функции отображается форма NameForm с заголовком Новая папка. Эта форма также передает информацию в главную форму при помощи метода SetNewName, который приведен в листинге 7.20.

Листинг 7.20

III <summary>

III Устанавливает новое иня для папки

III </summary>

III <param пате="пате">Иня для папки</рагат> public void SetNewName(string name)

{

Directory. CreateDirectory(path + name):

}

Метод создает папку с заданным именем. Как видно, код его чрез­вычайно прост.

Код для выполнения команды Свойства приведен в листинге 7.21.

Листинг 7.21

private void propertiesMenuItem_Click(object sender.

System. EventArgs e)

{

Cursor. Current — Cursors. WaitCursor;

Листинг 7.21 (продолжение)

ListViewItem Iv1 =

1 і stVi ew. Iterns[1 і stVі ew. Selectedlndices[0]]:

Filelnfo fi — new FileInfo(path + lvi. Text):

PropertiesForm propertiesForm = new PropertiesForm(this, fi, new SetNameDelegate(SetRename), new SetAttri butesDelegate(SetAttri butes)): іf(propertiesForm. ShowDialogO = DialogResult. OK) fillListO; listView. FocusO;

}

Этот код вызывает форму PropertiesForm, которая отображает атрибу­ты выбранного файла или папки. Также в этой форме пользователь может изменять атрибуты файла при помощи метода SetAttri butes, код которого приведен в листинге 7.22.

Листинг 7.22

public void SetAttributes(FileAttributes fileAttributes)

{

ListViewItem lvi — 1 і stVi ew. Items[lі stVi ew. Selectedlndi ces[0]]; bool isFolder = lvi. Imagelndex = 0; if(isFolder)

{

Directorylnfo di = new DirectoryInfo(path + lvi. Text); di. Attributes = fileAttributes;

}

el se {

Filelnfo fi = new FileInfo(path + lvi. Text); fi. Attributes = fileAttributes;

}

}

Для создания градиентной заливки соответствующего элемента ин­терфейса применяется метод, код которого приведен в листинге 7.23.

Листинг 7.23

public static void SetGradient(System. Windows. Forms. ListView listView)

{

// Новый вариант

// Для. NET Compact Framework 2.0

SendMessagedіstView. Handle. LVMSETEXTENDEDLISTVIEWSTYLE.

0.

LVS_EX_GRADIENT);

1 і stView. Ref reshO;

}

Итак, основные трудности реализации программы рассмотрены. Кроме того, в примере присутствуют вызовы функций Windows API для работы с табличным списком ListView. Эти примеры рассмат­ривались в главе 4, поэтому не стоит повторять их разбор. На са­мом деле эту программу можно улучшать до бесконечности, добав­ляя новые функциональные возможности. Надеюсь, у вас это получится. Буду рад, если вы пришлете свои варианты примеров, которые, на ваш взгляд, украсят программу.

Диспетчер задач

Но мы с вами не расстаемся с программами, написанными Кристиа­ном Форсбергом. На его сайте можно найти еще одну полезную программу, необходимую как разработчику, так и пользователю. Это Диспетчер задач (Task Manager). Программа подобного рода тоже отсутствует в стандартной поставке Windows Mobile. А ведь эта программа очень полезна в работе. Владелец смартфона под уп­равлением системы Windows Mobile может узнать много нового о своей системе после запуска этой утилиты. Диспетчер задач по­кажет все программы, которые размещаются в памяти смартфона, отбирая системные ресурсы. Диспетчер задач также позволяет уда­лять из памяти ненужные программы и процессы. Не случайно, многие производители сами снабжают свои устройства программа­ми подобного типа. Если вам не повезло и у вас нет такой програм­мы, то вы можете сами написать Диспетчер задач.

Как и предыдущий пример, оригинальная версия программы была написана на Visual Studio 2003 для смартфонов под управлением Windows Mobile 2003 на платформе. NET Compact Framework 1.0. Следуя нашей традиции, я с согласия автора конвертировал проект для Visual Studio 2005 для целевой системы Windows Mobile 5.0 и с применением. NET Compact Framework 2.0.

Графический интерфейс программы

Диспетчер задач при запуске показывает список запущенных про­грамм (рис. 7.5).

Разработка приложений

Рис. 7.5. Внешний вид программы

С помощью меню, размещенного в левой части окна, можно акти­вировать выбранное приложение. При этом сам менеджер задач закрывается. Меню, расположенное в правой части окна, предос­тавляет пользователю несколько больше возможностей. Команды этого меню приведены в следующем списке:

□ Обновить — обновляет список запущенных программ;

□ Процессы — показывает список запущенных процессов;

□ Остановить — останавливает выбранную программу;

□ Остановить все — останавливает все запущенные программы;

□ Вид — показывает информацию о процессе;

□ Убить — закрывает процесс;

□ 0 программе — выводит информацию об авторе программы;

□ Готово — закрывает программу.

Внешний вид этого меню показан на рис. 7.6.

Разработка приложений

Рис. 7.6. Команды меню для правой кнопки

Код программы

При активации основной формы Mai nForm программа получает спи­сок запущенных программ при помощи процедуры f і 1 ITaskLi st, код которой приведен в листинге 7.24.

Листинг 7.24

private void fillTaskListO {

Cursor. Current = Cursors. WaitCursor:

// Полунин список запущенных приложений windows — WindowHelper. EnumerateTopWindowsO:

// Заполняем ListView ListViewItem lvi: listView. BeginUpdateO; listView. Items. ClearO; foreach(Window w in windows)

{

lvi = new ListViewItem(w. ToStringO); listView. Items. Add(lvi);

}

1 і stVi ew. EndUpdate(); if (listView. Items. Count > 0)

{

listView. Items[0].Selected — true:

1 іstView. Items[0].Focused = true:

}

Cursor. Current = Cursors. Default;

}

Данная процедура использует класс W indowHe’Iper, который позво­ляет получить информацию о запущенных приложениях. В листин­ге 7.25 приведен код метода Enumerate! opWindows, который находит все окна запущенных в системе приложений.

Листинг 7.25

public static Window[] EnumerateTopWindowsO {

ArrayList windowList *= new ArrayListO:

IntPtr hWnd = IntPtr. Zero;

Window window = null;

// Получим первое окно

hWnd = GetActiveWindowO;

hWnd = GetWindow(hWnd, GW HWNDFIRST);

while(hWnd != IntPtr. Zero)

{

ifdsWindow(hWnd) && IsWindowVisible(hWnd))

{

IntPtr parentWin — GetParent(hWnd); if ((parentWin =» IntPtr. Zero))

{

продолжение

Листинг 7.25 (продолжение)

int length = GetWindowTextLength(hWnd): if (length > 0)

{

string s = new stringCXO’, length + 1): GetWindowText(hWnd, s, length + 1); s = s. Substring(0, s. lndex0f(‘’)); if(s!= "Tray" && s!= “Start" && s!= "Task Manager")

{

window = new WindowO; window. Handle = hWnd; window. Text = s; windowList. Add(window);

}

}

}

}

hWnd = GetWindow(hWnd, GW HWNDNEXT);

}

return (Window[])windowList. ToArray(typeof(Window));

}

В этом методе вызываются функции Windows API, с помощью ко­торых можно получить список всех открытых окон. Все обнаружен­ные окна добавляются в список, если они удовлетворяют некото­рым условиям. Добавляемые окна не должны иметь родительских окон, они должны быть видимыми и иметь заголовок. При этом сам Диспетчер задач не должен попасть в этот список. Все остальные окна записываются в массив.

Активация и закрытие приложения

Для активации запущенного приложения вызывается функция Win­dows API Set Foregrounds ndow, которая использует дескриптор окна. Для закрытия приложения используется функция SendMessage с соответ­ствующим сообщением закрытия WM CLOSE. Для закрытия сразу всех окон можно использовать функцию Windows API SHCloseApps, кото­рая закрывает все запущенные программы, кроме самого Диспетчера задач. Код, выполняющий эти действия, приведен в листинге 7.26.

Листинг 7.26

public static void ActivateWindow(IntPtr hWnd)

{

// Активируем приложение SetForegroundWindow(hWnd);

}

public static void CloseWindow(IntPtr hWnd)

{

// Закрываем приложение SendMessage(hWnd, WM CLOSE, 0, 0);

}

public static void CloseAppsO {

// Закрываем все приложения SHCloseApps(int. MaxValue):

}

Перечисление процессов

Для отображения списка процессов используется функция, код которой приведен в листинге 7.27.

Листинг 7.27

private void fillProcessListO {

Cursor. Current *» Cursors. WaitCursor;

// Получаем список запущенных процессов processes = Process. GetProcessesO;

// Заполняем ListView ListViewItem lvi;

1 іstVіew. BeginUpdate(); listView. Items. ClearO: foreach(Process p in processes)

{

lvi = new ListViewItem(p. ProcessName):

//lvi. Subitems. AddC’ID");

1 і stVi ew. Iterns. Add(1vi);

}

1 іstView. EndUpdateC); if(listView. Items. Count > 0)

{

1 іstView. Iterns[0].Selected = true; listView. Items[0].Focused = true;

}

Cursor. Current « Cursors. Default;

}

Список активных процессов извлекается при помощи класса Process. Основой класса является метод Get Processes, приведенный в листинге 7.28.

Листинг 7.28

public static ProcessC] GetProcessesO {

ArrayList procList = new ArrayListO:

IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPR0CESS, 0);

if((int)handle > 0)

{

try

{

PR0CE5SENTRY32 peCurrent;

PR0CESSENTRY32 pe32 = new PR0CESSENTRY32(): byte[] peBytes = pe32.ToByteArray(); int retval = Process32First(handle. peBytes): while(retval = 1)

{

peCurrent = new PR0CESSENTRY32(peBytes):

Process proc = new Process(new IntPtr((int)peCurrent. PID), peCurrent. Name. (і nt)peCurrent. ThreadCount.

(int)peCurrent. BaseAddress): procList. Add(proc);

retval = Process32Next(handle. peBytes):

}

}

catch(Exception ex)

{

throw new Exceptіon("Exception: " + ex. Message):

>

CloseToolheip32Snapshot(handle):

return (Process[])procList. ToArray(typeof(Process)):

}

else

{

throw new Exceptіon("Unable to get processes!"):

}

}

С помощью данного метода можно узнать детальную информацию о каждом процессе.

Закрытие процесса

Чтобы закрыть процесс, используется метод КІ 11, код которого при­веден в листинге 7.29.

Листинг 7.29

public void KillO {

IntPtr hProcess:

hProcess = OpenProcess(PROCESS_TERMINATE. false, (int) processld);

if(hProcess!= (IntPtr) INVALID_HANDLE_VALUE)

{

bool bRet;

bRet = TerminateProcess(hProcess. 0);

CloseHandle(hProcess):

}

}

Данный метод также использует вызовы функций Windows API. Функция OpenProcess получает дескриптор процесса, который затем передается функции Termi nateProcess для уничтожения процесса.

Код, отвечающий за внешний вид элемента управления ListView, полностью идентичен коду из предыдущего примера, поэтому его можно просто скопировать и не рассматривать отдельно. Теперь с помощью Диспетчера задач пользователь сможет узнать список запущенных программ и процессов и даже управлять ими.

Маленький блокнот

Однажды мой друг, далекий от программирования, попросил меня написать простенький текстовый редактор для карманного ком­пьютера. Его не совсем устраивало приложение Word Mobile, ко­торое используется для работы с текстовыми файлами в операци­онной системе Windows Mobile. Заказчик хотел получить только основные функции стандартного Блокнота из Windows ХР, то есть копирование, вырезание, вставку и удаление текста. Также он хо­тел обойтись без установки. NET Compact Framework 2.0, так как устаревшая модель его карманного компьютера обладала малой емкостью памяти.

В рамках решения поставленной задачи и была написана програм­ма Блокнотик, которая и будет рассматриваться в этом разделе главы.

Единственная сложность при написании данного текстового ре­дактора состояла в том, что библиотека. NET Compact Framework 1.0 не поддерживает работу с буфером обмена на уровне управля­емого кода. Поэтому пришлось прибегать к вызовам функций Windows API.

Данный пример можно использовать в качестве основы для тех, кто хочет написать свой текстовый редактор для. NET Compact Framework 1.0. Надо заметить, что если бы я стал писать свой при­мер с использованием. NET Compact Framework 2.0, то справиться с задачей было бы гораздо легче, так как вторая версия библиотеки поддерживает буфер обмена, который так необходим при операци­ях с текстом.

Первые шаги

После запуска Visual Studio. NET 2005 надо создать новый проект. При выборе типа проекта надо указать, что будет использоваться. NET Compact Framework 1.0. Для начала на форме следует разме­стить текстовое поле с именем txtEdi tor. Для свойства Multi 1 ine надо задать значение True, а свойство Scrol 1 Bars получит значение Both.

Так как текстовое поле обычно занимает все пространство формы, его нужно вручную растянуть до нужного размера. Учитывая, что я писал программу для конкретной модели мобильного устройства, большой ошибки в моих действиях не было. Но не будем забывать, что существуют другие устройства, размеры экрана у которых будут другими. Поэтому стоит устанавливать размеры элементов про­граммно в соответствии с текущими размерами формы.

Также на первом этапе разработки надо указать позицию текстового поля и установить в нем фокус. Соответствующий код был добавлен в обработчик события Form Load, что иллюстрирует листинг 7.30.

Листинг 7.30

private void MainForm_Load(object sender. EventArgs e)

{

// устанавливаем позицию текстового поля txtEditor. Location = new Point(0, 0);

// Приравниваем размеры текстового поля к размерам формы txtEditor. Width = this. Width; txtEditor. Height = this. Height:

// Устанавливаем фокус txtEdi tor. FocusO;

}

Если бы программа создавалась для настольного компьютера, то на­писанный код не вызывал бы никаких сомнений. Но у КПК нет внешней клавиатуры, и для ввода текста используется панель вво­да SIP Поэтому на форму надо добавить элемент inputPanel. Так как при активации панель ввода закроет часть формы, то надо на­писать код для вычисления высоты текстового поля для этого слу­чая и соответствующим образом изменить обработчик события Form_Load, как показано в листинге 7.31.

Листинг 7.31

private void МаіnForm_Load(object sender. EventArgs e)

{

// Высоту текстового поля устанавливаем в зависимости от SIP //txtEditor. Height = this. Height;

SetTextBoxHeightO;

}

// устанавливаем размеры текстового поля в зависимости от // активности SIP private void SetTextBoxHeightO {

if (SIP. Enabled)

txtEditor. Height = SIP. VisibleDesktop. Height + 2; el se

txtEditor. Height = this. Height;

}

private void SIP EnabledChanged(object sender, EventArgs e)

{

SetTextBoxHei ght();

}

Стандартные операции с текстом

На данной стадии уже создан первый прототип приложения. После запуска программы пользователь может вводить и удалять текст с по­мощью SIP. Но этого недостаточно для комфортной работы с текстом.

Пользователь должен иметь возможность манипулировать текстом, то есть копировать часть текста, вырезать его, удалять и вставлять в нужную позицию. Для этого надо создать меню при помощи эле­мента mai nMenu. В подменю Правка надо добавить стандартные коман­ды редактирования текста — Отменить, Вырезать, Копировать, Вставить. Если бы приложение создавалось для среды исполнения. NET

Compact Framework 2.0, то можно было бы использовать класс Clipboard. Но так как используется. NET Compact Framework 1.0, то придется обратиться к функциям Windows API и использовать не­управляемый код, что иллюстрирует листинг 7.32.

Листинг 7.32

// сообщения буфера обмена public const int WMCUT = 0x0300; public const int WM_C0PY = 0x0301; public const int WM PASTE = 0x0302; public const int WM CLEAR = 0x0303; public const int WM UNDO = 0x0304;

// функции API

[DllImport("coredll. dll", CharSet = CharSet. Unicode)] public static extern IntPtr GetFocusO;

[DI1 Import("coredl1.dl1")] public static extern int SendMessageCIntPtr hWnd, uint Message, uint wParam, uint IParam);

private void mnuCut Click(object sender, EventArgs e)

{

// Вырезаем текст

SendMessage(hwndEditor. WM CUT, 0, 0);

}

private void mnuUndoCl і ck( object sender, EventArgs e)

{

// Отменяем последнее действие SendMessage(hwndEditor, WM UNDO, 0, 0);

}

private void mnuCopy Clіck(object sender, EventArgs e)

{

// Копируем выделенный текст SendMessage(hwndEditor, WM_C0PY, 0, 0);

}

private void mnuPasteCl і ck (object sender. EventArgs e)

{

// Вставляєм текст из буфера обмена SendMessage(hwndEditor, WM_PASTE, 0. 0);

}

private void mnuDelete Clіck.(object sender. EventArgs e)

{

// Удаляем выделенный текст SendMessage(hwndEditor, WMCLEAR, 0, 0);

}

Теперь необходимо добавить в создаваемое приложение поддержку контекстного меню. Использование контекстного меню избавит пользователя от необходимости постоянно переводить стилус в нижнюю часть экрана для доступа к командам меню. В программу нужно добавить элемент управления ContextMenu и сделать список команд меню, который будет дублировать подпункт основного меню Правка. Созданное контекстное меню надо связать с текстовым по­лем при помощи свойства ContextMenu. Осталось только скопировать код из команд основного меню в соответствующие места для команд контекстного меню. Например, для команды контекстного меню Ко­пировать надо использовать код, приведенный в листинге 7.33.

Листинг 7.33

private void cmenuCopy_Click(object sender, EventArgs e)

{

// Копируем выделенный текст SendMessage(hwndEditor. WM_C0PY, 0. 0);

}

Мы сделали еще один шаг вперед. Теперь наш маленький блокнот умеет работать с текстом. Но приложение нужно еще немного до­работать. Например, пользователь может во время работы с блок­нотом переключиться на другую программу и скопировать в буфер обмена картинку, а затем вернуться обратно к текстовому редакто­ру. Конечно, картинку нельзя вставить в текстовое поле. Поэтому надо проверить тип содержимого в буфере обмена, и если там со­держатся не текстовые данные, то нужно заблокировать пункт меню Вставить. Для этого можно использовать функцию IsClip — boa rdFormatAvai 1 abl e, а проверку данных в буфере обмена выполнять в событии Popup, как показано в листинге 7.34.

Листинг 7.34

[Dl11mport("Coredll. dll") ]

private static extern bool IsClipboardFormatAvailable(uint uFormat);

// константа для буфера обмена

private const uint CFUNICODETEXT = 13;

public static bool IsTextO

Листинг 7.34 (продолжение) try

{

return IsClipboardFormatAvailable(CFUNICODETEXT):

}

catch (Exception ex)

{

MessageBox. ShowC’He йогу понять, что содержится в буфере обмена!"); return false;

}

}

private void mnuEdit_Popup(object sender, EventArgs e)

{

if (IsTextO)

mnuPaste. Enabled = true; el se

mnuPaste. Enabled =» false;

}

Подобные изменения надо сделать и для пунктов меню. Если пользователь не выделил часть текста, то пункты Вырезать, Копиро­вать и Удалить также должны быть заблокированы. Код, реализую­щий эту функциональность, приведен в листинге 7.35.

Листинг 7.35

//Если текст выделен

if (txtEditor. SelectionLength > 0)

{

mnuCut. Enabled = true; mnuCopy. Enabled = true; mnuDelete. Enabled = true;

}

else

{

mnuCut. Enabled = false; mnuCopy. Enabled ■ false; mnuDelete. Enabled = false;

}

Следующим шагом в развитии программы будет добавление фай­ловых операций. Работа с текстовым редактором предполагает не только правку текста, но и сохранение текста в файле, а также чте­ние данных из файла. Для этого в меню создаются соответствую­

щие команды Создать, Открыть, Сохранить и Сохранить как. Код, свя­занный с этими командами, приведен в листинге 7.36.

Листинг 7.36

private void mnuOpenCl ick (object sender. EventArgs e)

{

dlgOpenFile. Filter = "Текстовые документы (*.txt)|*.txt|Bce файлы I*.*"; dlgOpenFi1e. ShowDi al ogO; if (File. Exists(dlgOpenFile. FileName))

{

fname = dlgOpenFile. FileName:

StreamReader sr = new StreamReader(fname,

System. Text. Encodi ng. GetEncodi ng("Wi ndows-1251"). false):

txtEdi tor. Text = sr. ReadToEndO:

flag — false:

sr. CloseO:

}

private void mnuSaveAs_Click(object sender, EventArgs e)

{

SaveFileDialog dlgSaveFile = new SaveFileDialogO: dlgSaveFile. Filter — "Текстовые документы (*.txt)|*.txt|Bce файлы I*.*": dlgSaveFi1e. ShowDi alog(); fname — dlgSaveFile. FileName; savedataO:

}

private void savedataO {

if (fname — "”)

{

SaveFileDialog dlgSaveFile = new SaveFileDialogO: dlgSaveFile. Filter = "Текстовые документы (*.txt)|*.txt| Все файлы I*.*";

DialogResult res = dl gSaveFi le. ShowDi alogO; if (res — DialogResult. Cancel)

{

return:

}

fname — dlgSaveFile. FileName;

MessageBox. Show(fname);

Листинг 7.36 (продолжение)

}

StreamWriter sw = new StreamWriter(fname, false,

System. Text. Encodi ng. GetEncodi ng("Wi ndows-1251")); sw. WriteLine(txtEditor. Text): sw. FlushO; sw. CloseO; flag = false:

}

private void mnuSave_Clіck(object sender, EventArgs e)

{

savedataO:

}

private void txtEditor_TextChanged(object sender, EventArgs e)

{

flag = true:

}

Работа с файлами в. NET Compact Framework не отличается от мето­дов работы с файлами в полной версии. NET Framework, поэтому заострять внимание на этом коде не нужно. Осталось только доба­вить в программу некоторые детали, которые придают программе профессиональный вид. Нужно присоединить собственную пикто­грамму приложения, а также добавить диалоговое окно 0 программе с упоминанием автора программы и логотипом фирмы. Безусловно, вы можете наделить текстовый редактор новыми возможностями или расширить его функциональность. Например, для сохранения и от­крытия файлов я использовал стандартные диалоговые окна, кото­рые работают с файлами в пределах папки Мои документы. Но исполь­зуя код ранее созданного файлового менеджера, можно научить приложение сохранять и открывать файлы в любом месте файловой системы. Также можно доработать меню Формат, позволяющее рабо­тать с различными кодировками текста.

Распространение приложений

Даже если вы написали очень полезную программу, она не сможет обрести всемирную известность, пока вы держите ее на своем ком­пьютере. Нужно все же распространить программу и, если она не бес­платная, то и немного заработать на отпуск. Программы для настоль­ных компьютеров распространять довольно просто. Нужно лишь создать специальный проект для создания установочного пакета, ко­торый сгенерирует специальный файл установки Microsoft Installer (MSI). К сожалению, для мобильных устройств процесс создания установочных файлов немного отличается. В процессе распростра­нения программы участвуют три составляющие: настольный компь­ютер, программа синхронизации Microsoft ActiveSync и программа wceload. exe для извлечения файлов из саЬ-файлов.

Для пользователя процесс установки программы не сильно отлича­ется от привычной схемы. Сначала он скачивает программу или на­ходит ее на компакт-диске. Затем запускает установочный msi-файл. Программа Microsoft Installer с помощью специального мастера ус­тановки помогает пользователю установить программу с нужными настройками. После этого программа считается установленной, и пользователь может запускать ее.

Создание саЬ-файла

Прежде чем установочный пакет попадет в руки пользователя, нужно хорошенько поработать над его созданием. Устройства под управле­нием Windows Mobile не могут напрямую работать с файлами. msi. Вместо этого используются кабинетные файлы с расширением. cab. Таким образом, задача программиста заключается в том, чтобы соста­вить список команд для программы синхронизации ActiveSync, кото­рые позволят скопировать саЬ-файлы на устройство с учетом необхо­димых установок. Для создания удобного установочного пакета с интуитивно понятным интерфейсом вам необходимо выполнить не­хитрую последовательность действий.

1. Создать саЬ-файл для устройства.

2. Добавить в саЬ-файл дополнительные файлы, используемые программой, например изображения или файлы с данными.

3. Добавить в саЬ-файл инструкции для записи в реестр.

4. Зарегистрировать саЬ-файл с помощью ActiveSync, чтобы пользо­ватель мог установить приложение с настольного компьютера.

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

6. Упаковать все необходимые файлы в один специальный файл установки с расширением. msi.

Вы, вероятно, знаете, что кабинетный файл является специальным файлом упаковки и компрессии, с помощью которого можно ежи — мать файлы, что приведет к уменьшению их размеров. Также в этом файле могут содержаться инструкции для внесения изменений в ре­естр системы. За обработку саЬ-файлов на устройстве отвечает ути­лита wceload. exe, входящая в состав Windows Mobile.

Создание проекта

Приступим к разработке проекта для создания установочного пакета. Прежде всего нужно запустить уже существующий проект, который планируется подготовить для распространения. В качестве примера будет использоваться проект SmallNotepad. Затем нужно выполнить ко­манду меню File ► Add ► New Project. В открывшемся диалоговом окне надо перейти в раздел Other Project Types, выбрать тип Smart Device Cab Project и задать имя нового проекта DeployNotepadCab (рис. 7.7).

Atid $ ro^etfc? Xj

Разработка приложений

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

Затем надо запустить редактор File System Editor, нажав соответству­ющую кнопку в окне свойств. Нужно выбрать пункт Application Folder и в контекстном меню выбрать пункт Add ► Project Output (рис. 7.8).

Разработка приложений

Рис. 7.8. Выбор параметров проекта

В результате этого будет открыто диалоговое окно Add Project Output Group (рис. 7.9).

Разработка приложений

Рис. 7.9. Диалоговое окно Add Project Output Group

С помощью данного окна можно выбрать различные типы файлов, необходимые для программы, такие как файлы документации или, например, локализированные ресурсы. Нужно выбрать пункт Primary Output и нажать кнопке ОК. В правой части окна следует щелк­нуть правой кнопкой мыши на единственном пункте Primary output from SmallNotepad_CS и в контекстном меню выбрать пункт Create Shortcut to Primary output from SmallNotepad_CS (рис. 7.10). Это позво­лит включить пиктограмму в список файлов для распространения.

Разработка приложенийСозданный ярлык надо переместить мышью в папку Program Files Folder. Теперь можно приступать к созданию установочного файла.

Dependencies

ExdudeFiter

Outputs

Delete

Properties Window

Рис. 7.10. Создание пиктограммы приложения

В меню надо выполнить пункт Build ► Build DeployNotepadCab. После этого среда разработки создаст специальный файл с расширением. САВ. При помощи файлового менеджера его нужно найти и запом­нить его расположение.

Теперь надо установить созданный файл на эмуляторе Для этого выполняется команда меню Tools ► Device Emulator Manager. В диало­говом окне надо выбрать эмулятор. Например, Pocket PC 2003 SE Emulator. В этом же окне следует выполнить команду меню Actions ► Connect. При этом выбранный эмулятор будет активирован.

Emulator Properties

General iDtspiayj Hewortc Peripheral» j ‘

; |

————- і

С .

~~і

»•У-A • # ‘ ‘ ?.:*•

йойкву: ‘

Eight Ait

.. … p. w* Щ

‘• **- %■ *4 ?. <*- ^ wv, .. I

E:My 8ookPocketPO. Sernptes7_0’eateApp’5«ra:tttotepB<l’iD«ptoyfiot«padCabt>ebu9 f~j-

Разработка приложений

В окне эмулятора надо выполнить команду меню File ► Configure. После этого откроется окно настроек эмулятора, в котором следует перейти в раздел Shared Folder. В этом разделе надо выбрать папку, в которой находится созданный саЬ-файл (рис. 7.11). Эмулятор бу­дет считать, что данная папка является карточкой памяти.

Если открыть в эмуляторе программу File Explorer (Start ► Programs ► File Explorer) и найти папку Storage Card, то в ней можно будет увидеть ранее созданные установочные файлы.

Нужно выбрать файл DeployNotepadCab и запустить его. В результате начнется процесс установки программы на устройство. При установ­ке автоматически будет создан файл деинсталляции. Он поможет кор­ректно удалить приложение. Для этого в окне эмулятора надо выпол­нить команду меню Start ► Settings ► System ► Remove Program. В списке установленных программ надо найти ранее установленное приложе­ние, выделить его и нажать кнопку Remove (рис. 7.12).

ЛВШЯШШ ЯЯІИІІ. І1И

Remove Progrcw

Program* in storage memory;

Microsoft. NET CF 2.0 ENU-StitiQ… Mtrosoft .NET CF 2.0

I ■ •«VFW’WP-x-:

ТоЫ storage memory avalabfe: 5660k

Adfcirt memory «ІосіЦоп.

Рис. 7.12. Деинсталляция приложения

В результате этого действия будет запущен мастер удаления про­граммы, который корректно удалит все файлы, относящиеся к при­ложению. На этом изучение примера создания установочного фай­ла можно считать законченным.

Дополнительные материалы

На сайте MSDN есть очень подробная статья «Deploying. NET Compact Framework 2.0 Applications with. cab and. msi Files», в кото­рой приведены дополнительные сведения о создании и распростра­нении установочных файлов. Стоит ознакомиться с данным материа­лом, чтобы использовать все возможности установочных файлов.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Confirm that you are not a bot - select a man with raised hand: