Персональный блог Игоря Антонова aka "spider_net"

Программируем под Windows Mobile 6


Рубрика: Статьи -> Журнал Хакер -> Программирование -> c#
Метки: |
Просмотров: 8246
Программируем под Windows Mobile 6

Добрые дяди из Apple привыкли решать за пользователя, какое ПО и какие опции ему нужны. Что ж, это выбор их пользователей. Мы же с тобой берем… и просто сами кодим то, что нам нужно. Старая добрая Винда была и остается другом юзеров и программистов, выбирающих свой собственный путь.

WinMobile вчера

Еще буквально несколько лет назад мобильная платформа страдала дефицитом программного обеспечения. Трудно поверить, но, чтобы найти нужную тулзу, приходилось нехило попотеть. А потом еще раз напрячься в попытках отыскать заветный крэк (Странно, а вроде все неплохо находилось, – Прим. Dr.Klouniz). Отсутствие софта обуславливалось тем, что для разработки программ под новую платформу не было удобной IDE. Да, был могучий Visual C++, в котором, если мне не изменяет память, были соответствующие мастера. Но, к сожалению, их возможностей не хватало. Когда в 2003 году я попробовал замутить первую программу для КПК, то сразу понял, что моих нервов не хватит для интимных отношений с ужасной «Visual Studio». После Delphi эта среда кажется уж больно непродуманной и непонятной. Такое чувство, что пересаживаешься с «мерса» на «Волгу».

WinMobile сегодня

Сегодня Windows Mobile сильно преобразилась. Она доросла аж до шестой версии и теперь ее можно считать действительно комфортной и удобной ОС. Это было достигнуто как за счет улучшения внешнего вида, так и за счет упрощения процесса разработки софта. Сейчас уже не составляет труда найти продвинутый почтовик или навороченный текстовый редактор. Более того, многие разработчики уже взяли за правило выпускать мобильные версии своих настольных продуктов. Для Windows Mobile уже давно появились клоны WinRAR, TotalCommander, WinZIP, MS Office и т.д. Появление большого количества программ объясняется в первую очередь развитием платформы .NET. Создавать софт на базе этой технологии чрезвычайно просто – и очень привычно для кодеров, которые выросли на таких языках как Delphi/C++ Builder. Последние версии Visual Studio словно переродились: они стали удобными и поистине функциональными. Приготовься, в рамках этой статьи мы совершим небольшой трип в волшебную и многоцветную страну WM 6.0.

Дорожный чемоданчик

Отправляясь в путешествие, нельзя забывать про вещи первой необходимости. Выброси из своего походного чемоданчика проверенный временем Delphi, в этот раз он не пригодится. Вместо него достань VisualStudio (версию выбери как можно свежее; лично я отдаю предпочтение самой последней – 2008). Помимо студии нам также потребуется SDK для работы с функциями, характерными для коммуникаторов – sms, телефония и т.д. И SDK, и саму VS ты всегда можешь слить с www.microsoft.com.

Время - деньги

Будем считать, что ты успешно скачал и установил нужный SDK, а это значит, что можно двигаться дальше. Запускай VisualStudio и создавай новый проект для Visual C# типа Smart Device. Сразу после выбора типа проекта перед тобой должно появиться окно.

В этом окне тебе надо выбрать платформу (Target platform) для которой мы планируем создавать приложение, а также версию .NET Фреймворка (.NET Compact Framework version) и шаблон приложения (Templates). Для наших примеров в качестве платформы установи Windows Mobile 5.0 Smartphone SDK (если ты качал 6-ю версию SDK, то выбирай именно ее). С ней тебе будут доступны все необходимые пространства имен для работы со специфическими функциями коммуникаторов/смартфонов. Версию Фреймворка стоит выбирать, исходя из той, которая установлена на твоем девайсе. Например, на моем коммуникаторе Toshiba Portege G900 тусуется .NET Framework 2.0, поэтому я выбрал именно эту версию.

Внимание! Если на твоем устройстве до сих пор установлена первая версия .NET Framework, то бегом на microsoft.com и скачивай хотя бы вторую. Первая уж больно сильно урезана в плане функционала. Все, теперь остается только выбрать шаблон для нашего приложения. Для сегодняшних примеров нам вполне подойдет Device Application. Клацай «Ок» – и VisualStudio сгенерирует новый пустой проект.

По умолчанию VS создает чистый проект для мобильных устройств со скином в виде этого самого девайса. По правде говоря, «дизайнить» форму в таком виде не очень удобно, поэтому потрудись сразу отключить отображение скина. Сделать это можно, кликнув правой клавишей мыши по форме и выбрав в контекстном меню «Show Skin». После этого нехитрого действия ты увидишь более-менее привычный вид формы.

Пустой проект готов и настало время привести его в рабочий вид. Готовь мышку, сейчас мы будем раскидывать элементы управления. Сегодня мы разберем не один, а сразу несколько примеров. Для такого «проекта» нужна соответствующая форма. Кстати, варианта формы с кучей закладок я для себя не нашел. Поэтому советую тебе не заморачиваться и пойти тем же путем, что и я – бросить и растянуть по всей форме компонент TabControl, а затем создать в нем пять закладок:

  • Отправка SMS;
  • Процессы;
  • Файловый менеджер;
  • Dialer;
  • Полезности.
  • Думаю, назначение закладок пояснять не нужно. Все и так очевидно по их названиям… Что? Тебе интересно, что это за закладка «Полезности»? OК, сейчас объясню. Здесь расположено несколько кнопок, которые выполняют некоторые полезные для пользователя или западлостроителя действия: поворот экрана, выключение/перезагрузка системы.

    Напишите письмецо…

    С дизайном формы покончено, пора переходить к кодингу. Первое, чему мы сегодня научимся – отправлять SMS. Этими короткими сообщениями пользуется каждый из нас, а раз так, неплохо бы научиться отправлять их программно. Зачем? Цели могут быть разными. Например, некоторые на основе полученных знаний смогут закодить простенькую программку, которая будет транслитерировать весь кириллический текст, тем самым, позволяя сэкономить свои кровные на отправке SMS. Другие могут через sms «выводить» с вражеской территории различную полезную информацию. Итак, создай обработчик события для одной единственной кнопки с надписью «отправить» и напиши в нем следующий код:

    if (textBox1.Text != "")
    {
    SmsMessage mymessage = new SmsMessage();
    //вот здесь можно добавлять кучу получателей
    mymessage.To.Add(new Recipient(textBox1.Text));
    mymessage.RequestDeliveryReport = cbReport.Checked;
    mymessage.Body = textBox2.Text;
    try
    {
    mymessage.Send();
    MessageBox.Show("Сообщение успешно отправлено!", 
    "Информация!");
    }
    catch
    {
    MessageBox.Show("При отправке сообщения 
    возникла ошибка!", "Ошибка!");
    }
    }

    Кода немного, так что быстренько переписывай и возвращайся сюда за разъяснениями. В самой первой строчке я проверяю, заполнено ли поле с получателем (если нет, то делать ничего не нужно). Учти, что для демонстрационного примера такой проверки вполне достаточно, но для создания реального приложения ее будет маловато. Если ты решишь в будущем закодить тулзу для отправки сообщений, то я рекомендую тебе проверять номер получателя с помощью регулярных выражений. Только так можно быть уверенным, что это действительно номер, а не чехарда из букв и цифр. Проверив номер получателя, можно переходить непосредственно к отправке. Для отправки SMS в SDK есть готовый класс – SmsMessage. Как и полагается, перед тем как начать работать с классом, нужно создать его экземпляр. Именно это я и делаю во второй строчке кода. Инициализировав класс, нужно не теряться, а сразу начать заполнять его свойства. К счастью, их немного:

  • TO – коллекция получателей. В этом свойстве ты можешь установить как одного, так и нескольких получателей.
  • RequestDeliveryReport – отчет о доставке. Если в этом свойстве true, то после отправки сообщения будет запрошен отчет.
  • Body – текст сообщения.
  • Разобравшись со свойствами, можно переходить к методам, а методов всего один – Send(). В примере вызов метода Send() я заключаю в блок операторов исключительных ситуаций. Это делается на случай неожиданных ошибок. Попробуй сейчас сохранить внесенные изменения и собрать проект. Не спеши паниковать, если VS нервно матерится. Просто добавь новое пространство имен (Microsoft.WindowsMobile.PocketOutlook) – и опять попытайся собрать проект. Что, не хочет? Ok, don’t worry. Зайди в меню Project -> Add Reference. В появившемся окне выбери нужную сборку и нажми «ОК». Теперь проект должен успешно собраться. Можешь уже сейчас залить свежеиспеченную прогу в свой девайс и протестировать. А я начну разбирать следующий пример.

    Мониторим процессы

    На мой взгляд, один из главных минусов WinMobile – это отсутствие встроенных средств для просмотра списка активных задач или процессов. В написании такой тулзы нет ничего сложного, но почему-то многие программисты пытаются неплохо заработать на подобных программах. Мне на глаза попадался продвинутый диспетчер задач с кучей разных ненужных функций по цене $30. Нехило? Лично для меня это много, и свои честно заработанные денежки я предпочитаю тратить на что-нибудь другое. Итак, создавай обработчик события Clicлk() для кнопки «Обновить», расположенной на второй закладке. Напиши здесь всего одну строчку кода:

    GetProcList();

    Код самой процедуры ты можешь найти на соответствующей врезке. Начинай его переписывать, а я потружусь объяснить, что в нем происходит.

    private void GetProcList()
    {
    Cursor.Current = Cursors.WaitCursor;
    lvProcessList.Items.Clear();
    process_list = TaskManager.Process.GetProcesses();
    foreach (TaskManager.Process proc in process_list)
    {
    ListViewItem NewItem = new ListViewItem
    (proc.ProcessId.ToString());
    NewItem.SubItems.Add(proc.ProcessName);
    NewItem.SubItems.Add(proc.ThreadCount.ToString());
    lvProcessList.Items.Add(NewItem);
    }
    Cursor.Current = Cursors.Default;
    }

    Взглянув на листинг, ты наверняка удивился – для получения списка процессов потребовалась всего одна строчка (перебор и добавление каждого из них в ListView не считаем). Если ты хоть раз пробовал кодить «диспетчер процессов» под Win32 (конечно кодил; ][акер уже не раз писал об этом), то наверняка помнишь, что для получения списка активных процессов приходилось вызывать кучу API-функций и совершать много телодвижений, – а тут все как-то просто и быстро. Но не так просто, как кажется на первый взгляд!

    Строка «process_list = TaskManager.Process.GetProcesses()» говорит о том, что получение процессов происходит посредством вызова метода GetProcess() класса Process. Класс Process является разработкой Cristian Forsberg и, благодаря ему, работа с процессами превращается в сплошное удовольствие. Точнее, в одну строку. Все, что нам требуется, – это получить список всех процессов посредством вызова всего-навсего одного метода – GetProcess() . После этого остается только запустить перебор в цикле и вытащить информацию о каждом из них. Всю эту информацию (количество потоков, имя процесса, pid) я и добавляю в ListView. Остальную черную работу делает хорошо продуманный класс. Кстати, модуль с классом ты можешь взять с нашего диска, а после выхода журнала в свет и на www.vr-online.ru будет доступен немного переработанный вариант этого класса, с возможностью получать путь к файлу процесса. Будем считать, что список процессов у нас получен. Теперь нужно научиться им управлять – убивать лишние. Для решения этой нетрудной задачки у класса Process есть метод Kill(). Реализация процесса завершения – ниже:

    TaskManager.Process proc;
    proc = process_list[lvProcessList.SelectedIndices[0]];
    proc.Kill();

    Силами этого нехитрого кода я выковыриваю выделенный процесс и просто вызываю вышеозвученный метод. Просто до безобразия!

    Файловый менеджер

    Файловый менеджер – тулза, без которой я не могу представить ни одного своего рабочего дня. На «большом» компе я комфортно юзаю бесплатный UnrealCommander (практически клон TotalCommander’a). С недавнего времени необходимость в функциональном файловом менеджере появилась и при работе на коммуникаторе. Опять же, я не стал заморачиваться с Resco Explorer и его маленькими друзьями, а решил попробовать закодить все самостоятельно. Создай пустую функцию FileList и наполни ее тело (Хе-хе, – прим. Dr.Klouniz) кодом из соответствующей врезки. Как обычно, возвращайся за разъяснениями.

    В самом начале я меняю вид курсора. Получение списка файлов – дело небыстрое, особенно на мобильных девайсах. Поэтому, чтобы лишний раз не смущать пользователя, лучше выбрать привычный курсор для тормозных операций и спать спокойно. После такой хитрой подготовки (нервной системы пользователя) ничто не помешает нам перейти непосредственно к получению списка файлов. Сначала получим список директорий (пусть они будут сверху, как и принято во всех файловых менеджерах,) а уже после этого пробежимся по файлам. Для получения директорий я использую класс Directory. У этого класса есть метод GetDirectories(), позволяющий получить список папок по переданному в качестве единственного параметра пути. Получив список папок, их обязательно нужно добавить в контейнер-коллекцию, чтобы потом их можно было удобно отсортировать (foldersList.Sort();).

    Отсортировав список директорий, можно приступать к добавлению найденных папок в ListView. После добавления папок я приступаю к получению файлов. Алгоритм получения списка файлов точно такой же, поэтому я не стану заострять на нем внимание. Теперь создай обработчик события Click() для кнопки «Перейти». По ее нажатию мы будем запрашивать содержимое конкретной папки. Все, что нам требуется написать в этом обработчике – вызов функции FileList(). Если сейчас запустить пример, то уже реально начать путешествие по файловой системе. Набери в поле для ввода пути любой адрес (например, My Documents) и нажми на кнопку «Перейти». Если при переписывании листинга ты не допустил ошибок, то через мгновение ListView должен заполниться списком файлов (рисунок 8).

    Итак, теперь наш менеджер умеет отображать список файлов, но кое-чего ему явно не хватает: какой может быть файловый менеджер без возможности выполнения стандартных операций (создание папок, копирование и удаление файлов, запуска программы)? Поэтому нам волей не волей, но придется расширять функционал. OК, начнем с удаления файлов. Удалить файл не проблема (гораздо труднее его восстановить:)). От нас требуется лишь вызвать метод Delete() класса File. В качестве одного единственного параметра метод принимает полный путь к тому файлу, который должен быть удален. Список файлов у нас в ListView. Есть у нас и путь к папке, в которой мы работаем (tbPath). Значит, все, что нам нужно – это прибавить имя файла к полному пути к папке, в которой мы сейчас находимся, и выполнить метод Delete():

    File.Delete(tbPath.Text+listView1.Items[listView1.SelectedIndices[0]].Text);

    Копирование файла реализуется аналогичным способом, но с одним отличием – здесь требуется вызывать не метод Delete(), а метод Copy(), которому нужно передать два параметра:

  • Полный путь к файлу источнику;
  • Полный путь к файлу приемнику.
  • Определить файл-источник можно таким же способом, как и при удалении, поэтому еще раз приводить код я не буду. Папки создаются посредством вызова метода CreateDirectory(). Метод принимает всего один параметр – путь к создаваемой папке. Как видишь, встроенные классы существенно упрощают работу с файлами и папками, позволяя совершенно забыть о неудобном использовании Windows API. Совсем другая история с запуском файлов.

    Так уж получилось, но разработчики C# не снабдили нас удобным классом для запуска внешних программ. Печально, но не смертельно. Уже известный нам Cristian Forsberg, помимо класса для работы с процессами, любезно предоставил на суд общественности класс ShellExecute, позволяющий стартовать программы. Подключи модуль с классом к своему проекту и, вызвав метод Start(), передай ему путь к запускаемому файлу. Дальнейшее – работа класса. Я не стану приводить пример кода запуска, так как в нем ничего нет трудного. В крайнем случае, на DVD тебя ждет полный исходник со всеми рассмотренными классами.

    Позвони мне, позвони

    Мы уже познакомились с отправкой SMS, получением процессов, выполнением операций с файлами… дошел черед и до телефонии! Я специально оставил это на закуску, ведь благодаря классам работать с ней просто и писать кучу кода не понадобится. Не буду многословным, просто взгляни на этот код:

    Phone NewPhone;
    NewPhone = new Phone();
    NewPhone.Talk(tbTellNumber.Text, false);

    Этих трех строчек достаточно, чтобы совершить звонок по номеру (конечно, платному! :)), введенному в поле tbTellNumber. Второй параметр (false) метода Talk говорит о том, что номер нужно набирать сразу же, не ожидая разрешений.

    The End

    Программировать для Windows Mobile, используя технологию .NET, чрезвычайно быстро и удобно. Сегодняшние примеры – лишнее тому подтверждение. Обрати внимание, мы рассматривали только демонстрационные примеры, но на их основе вполне реально написать настоящие хакерские тулзы. Например, ты без труда сможешь отправлять с девайса владельца всю нужную тебе инфу посредством sms или устроить самую настоящую прослушку средь бела дня (автоматически набрал нужный номер в нужное время и...). И пускай потом жертва вспоминает, как его телефон смог позвонить, стоя на блокировке. На этой славной ноте я хочу закончить свою сказку и попрощаться с тобой. Удачи в нелегких кодерских делах! Как обычно, все твои вопросы я жду на мыло.

    Метод получает список файлов

    private void FileList()
    {
    Cursor.Current = Cursors.WaitCursor;
    listView1.Items.Clear();
    listView1.BeginUpdate();
    string[] folders = Directory.GetDirectories
    (tbPath.Text);
    ArrayList foldersList= new ArrayList(folders.Length);
    ListViewItem NewListView;
    int i = 0;
    for (i = 0; i < folders.Length; i++)
    foldersList.Add(folders[i]);
    foldersList.Sort();
    foreach (string directory in foldersList)
    {
    NewListView = new ListViewItem
    (Path.GetFileName(directory));
    NewListView.SubItems.Add("Dir");
    listView1.Items.Add(NewListView);
    }
    string[] files = Directory.GetFiles(tbPath.Text);
    foldersList = new ArrayList(files.Length);
    for (i = 0; i < files.Length; i++)
    foldersList.Add(files[i]);
    foldersList.Sort();
    foreach (string file in foldersList)
    {
    NewListView = new ListViewItem(Path.GetFileName
    (file));
    NewListView.SubItems.Add ("File");
    listView1.Items.Add(NewListView);
    }
    if (tbPath.Text[tbPath.Text.Length - 1].
    ToString() != "\\")
    {
    tbPath.Text = tbPath.Text + "\\";
    }
    listView1.EndUpdate();
    Cursor.Current = Cursors.Default;
    }

    Статья опубликована в журнале "Хакер" (http://xakep.ru). Сентябрь 2008 г.

    Ссылка на журнал: http://goo.gl/YTLMNp

    P.S. Друзья, перед тем как писать комментарии в стиле "Автор, на дворе 2014 год, на фиг нам Windows Mobile", обрати внимание на дату статьи - сентябрь 2008. На блоге я собираю все свои статьи, которые писал для журналов. Увы, некоторые из них утратили актуальность.

    Оставьте комментарий!
    comments powered by HyperComments