Wednesday, August 6, 2008

Портирование приложений СSharp на mono

Начальные действия.

Написано на основе опыта полученного при портировании толстого клиента, так как портирование еще не завершено(приостановлено), то опыт не полный.

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

Определить, где хранятся основные файлы приложения и важность именно такого расположения файлов и конфигураций. Хранение данных в реестре и использование установочных пакетов удобно в Wiondows, при запуске под Linux второе не используется, а для первого нужно самому внести все данные в реестр. В моем случае это было не критично так как в реестре храниться только версия установленного приложения в системе. И как следствие приложение не сможет себя автоматически обновить.

Для определения соответствия путей можно воспользоваться расположенным ниже списком:

  1. Environment.SpecialFolder.ApplicationData===домашний каталог/.config
  2. Environment.SpecialFolder.CommonApplicationData===/usr/share
  3. Environment.SpecialFolder.CommonProgramFiles===пустое значение
  4. Environment.SpecialFolder.Cookies===пустое значение
  5. Environment.SpecialFolder.Desktop===домашний каталог/Desktop
  6. Environment.SpecialFolder.DesktopDirectory===домашний каталог/Desktop
  7. Environment.SpecialFolder.Favorites===пустое значение
  8. Environment.SpecialFolder.History===пустое значение
  9. Environment.SpecialFolder.InternetCache===пустое значение
  10. Environment.SpecialFolder.LocalApplicationData===домашний каталог/.local/share
  11. Environment.SpecialFolder.MyComputer===пустое значение
  12. Environment.SpecialFolder.MyDocuments===домашний каталог
  13. Environment.SpecialFolder.MyMusic===домашний каталог/Music
  14. Environment.SpecialFolder.MyPictures===домашний каталог/Pictures
  15. Environment.SpecialFolder.Personal===домашний каталог
  16. Environment.SpecialFolder.ProgramFiles===пустое значение
  17. Environment.SpecialFolder.Programs===пустое значение
  18. Environment.SpecialFolder.Recent===пустое значение
  19. Environment.SpecialFolder.SendTo===пустое значение
  20. Environment.SpecialFolder.StartMenu===пустое значение
  21. Environment.SpecialFolder.Startup===пустое значение
  22. Environment.SpecialFolder.System===пустое значение
  23. Environment.SpecialFolder.Templates===пустое значение
Все не установленные пути лучше не использовать так как результат будет зависеть от текущей папки(обычно это папка где запустили) и возможны неприятные неожиданности.

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

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

Установить последнюю версию mono и monodevelop - последнюю - так как скорее всего, именно в ней будет реализовано максимум возможностей из .Net. Если есть ограничение на дистрибутив максимально свежую из доступных в нем.

Сделать копию описания проекта и назвать его как нибудь на подобии проект_под_VS. После этого открыть проект под VS в monodevelop - при открытии, если был установочных проект, то среда сообщит, что он не передерживается. Это нормальная реакция системы после этого проект будет уже сохранен без не поддерживающихся частей и в результате для создания установочного пакета нужно будет использовать копию проекта сделанную ранее. В остальном проект можно использовать в на обоих платформах.

При компиляции возникает 2 типа ошибок(возможен и третий но очень редко.):

  1. Не корректно по мнению компилятора написанный код - возможно прийдеться раставить в местах ошибок дополнительные скобки чтобы исправить неоднозначности кода.
  2. Не корректная кодировка файла - самая подлая ошибка:-) Для избежания ее нужно все файлы используемые в проекте перевести из cp1251 в utf8. Ее симптомы компилятор ругается на нормальный на вид код и приложение работает неправильно , идет не по тем путям куда должно было. В моем случае некоторые элементы имели русское название и отображались не те формы или не те компоненты и не срабатывали нужные реакции.
  3. Не реализованы какие-то функции вообще никак, отсутствие некоторых свойств - очень редкое событие, но вполне возможно. Единственный метод решения этой проблемы не использовать этот код.
После выполнения всех этих шагов мы должны получить код который компилируется и запускается, но еше не работает.

Запускаем приложение

Основная проблема возникающая при работе: это отсутствие отладчика в monodevelop. И всю отладку скорее всего нужно проводить методом отладочных печатей и логов.

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

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

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

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


       /// 
/// Запущены под моно
///

/// нужно урезать объем отображения
public static bool IsRunningOnMono()
{
return Type.GetType("Mono.Runtime") != null;
}

///
/// Запущена не под XP(Считаем ее самой распространенной пользовательской системой)
///

///
public static bool IsTerminalServer()
{
return !(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1);
}

///
/// Запущены под юникс
///

/// нужно запретить специфичные для виндоус операции
public static bool IsUnix()
{
return Environment.OSVersion.Platform == PlatformID.Unix;
}
После выполнения этих шагов мы получаем приложение(альфа версия), которое работает с урезанным функционалом, но выглядит очень странно:-)

Исправление внешнего вида

Эта стадия еще не завершено мной, в новой версии mono 2.0 все компоненты выглядят очень похожими на оригинальный , но лучше все таки проверить.

На этом шаге нужно изменить размеры всех элементов которые по каким-то причинам съехали или расползлись. Эта часть скорее относиться к дизайну, а не к функционалу. Но если ее не выполнить приложение будет очень не удобно использовать.

Как результат мы получим приложение которое можно тестировать(бета версия).

Исправление функционала

После того как мы получаем версию с нормальным отображение компонентов можно уже искать ошибки в приложении связанные с особенностями архитектур и платформ.

Зачем это все надо

При портировании и использование другого компилятора мы получаем ряд преимуществ:

  1. При компиляции мы можем обнаружит части кода которые по каким-то причинам были не завершены или сделаны не качественно - присутствуют не используемые переменные, не проверяются ответы от функций и параметры функций не проверяются на корректность.
  2. Приложение, когда это потребуется, можно будет портировать, и затратить на это меньше времени.
  3. И как следствие предыдущего факта при смене версии ос даже на одной платформе (XP -> Vista) с большей вероятностью будет работать.

No comments: