Автоматический запуск приложений в Windows Phone Classic

Автор: Topol Суббота, Май 5th, 2012 Нет комментариев

Рубрика: Операционные системы

Моя недавняя тема про фоновые службы в Windows Phone Classic (на базе управляемого кода) дала повод поразмышлять на тему автоматического запуска любых приложений для Windows Phone  Classic (кстати, почему вы задаете вопросы по e-mail, а не в комментариях к записи?).

Существует два главных способа заставить приложение запускаться при загрузке операционной системы:

  • добавить соответствующий ключ в реестр;
  • создать ярлык в папке автозагрузки.

Кроме того, есть варианты запускать приложения:

  • при вставке карты памяти;
  • в определенное время по таймеру;
  • при наступлении каких-либо событий.

Используем реестр Windows
По аналогии с настольной версией Windows, запускать приложения автоматически можно просто разместив информацию о них в специальной ветке реестра. Для этого используется секция «HKEY_LOCAL_MACHINEInit». Для каждого отдельного приложения здесь создается отдельный ключ, имя которого «LaunchXX», где XX — номер загрузки для приложения. Этот ключ должен содержать строковое значение — путь до приложения. Также можно создать второй, опциональный ключ с именем «DependXX». В нем указывается номер приложения, которого следует ожидать до запуска данного приложения.

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

Код:
private void Register()
{
using (var key = Registry.LocalMachine.OpenSubKey(«init», true))
{
var values = key.GetValueNames();
int keyIndex;
for (keyIndex = 100; keyIndex < 199; keyIndex++)
{
if (values.Contains(«Launch» + keyIndex) == false)
{
break;
}
}

key.SetValue(«Launch» + keyIndex, @»path»);
}
}

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

Код:
public static bool IsServiceRegistered
{
get
{
var serviceFullPath = «path».ToLower();

using (var key = Registry.LocalMachine.OpenSubKey(«init», true))
{
if (key != null)
{
return key.GetValueNames()
.Where(k => (key.GetValue(k, String.Empty) ?? String.Empty).ToString()== serviceFullPath)
.Count() > 0;
}
}

return false;
}
}

public static void UnRegister()
{

var serviceFullPath = «path».ToLower();

using (var key = Registry.LocalMachine.OpenSubKey(«init», true))
{
if (key != null)
{
var keyVaues = key.GetValueNames().Where(
k => (key.GetValue(k, String.Empty) ?? String.Empty).ToString().ToLower() == serviceFullPath)
.Select(k => k).
ToArray();

foreach (var keyVaue in keyVaues)
{
key.DeleteValue(keyVaue, false);
}
}
}
}

После запуска приложения в автоматическом режиме следует уведомить операционную систему о том, что запуск произошел успешно. Для этого в «coredll.dll» содержится функция «SignalStarted». Поскольку в данном случае мы имеем дело с приложением .NET Compact Framework, то следует использовать P/Invoke. При запуске приложения в автоматическом режиме приложению передается аргумент — так можно отличить автозапуск от обычного старта приложения. Этот аргумент следует передать в виде параметра функции «SignalStarted».

Код:
static class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
SignalStarted(uint.Parse(args[0]));
}

// запуск приложения
}

[DllImport("coredll")]
public extern static void SignalStarted(uint dword);
}

Теперь при загрузке операционной системы наше приложение будет успешно запускаться.

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

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

Все ярлыки для автозапуска должны располагаться в папке «WindowsStartUp». Однако, полный путь зависит в т.ч. от локализации устройства, например, для русской версии ОС путь будет выглядеть как «WindowsАвтозагрузка». Тем не менее, это — не проблема, используя метод GetFolderPath объекта Environment мы можем получить путь к служебным папкам устройства, среди которых есть и папка автозагрузки. Поэтому путь до нашего ярлыка автозапуска можно определить так:

Код:
string _shortcutPath = Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.Startup), «myapp.lnk»);

Теперь, для того, чтобы автоматически загружать наше приложение, следует создать ярлык по этому пути. Этот файл имеет обычное текстовое содержимое вида «XX#path», где XX — количество символов в части «path», а path — путь до исполняемого файла. Однако, для создания ярлыка можно воспользоваться более правильным способом, а именно использовать функцию «SHCreateShortcut» из библиотеки «coredll.dll». При вызове этой функции следует указать путь, где необходимо разместить ярлык (в папке автозагрузки) и путь до исполняемого файла.

Код:
[DllImport("coredll.dll")]
public static extern void SHCreateShortcut(
string target,
string shortcut);

private static string _shortcutPath =
Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.Startup), «myapp.lnk»);

private void Register()
{
if (File.Exists(_shortcutPath) == true)
{
File.Delete(_shortcutPath);
}

SHCreateShortcut(_shortcutPath, «path»);
}

Удаление приложения из автозагрузки или проверка наличия его там сводится к работе с этим файлом (ярлыком).

Код:
private static string _shortcutPath =
Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.Startup), «myapp.lnk»);

public static bool IsServiceRegistered
{
get
{
return File.Exists(_shortcutPath);
}
}

public static void UnRegister()
{
if (File.Exists(_shortcutPath) == true)
{
File.Delete(_shortcutPath);
}
}

Установка карты памяти в устройство
При вставке карты памяти операционная система автоматически сканирует ее на наличие приложения «Autorun.exe» в папке «/2577″, если приложение найдено, то оно запускается автоматически. На самом деле имя папки зависит от типа процессора и для некоторых моделей может быть иным. Однако, «/2577″ подходит для большинства устройств Windows Phone Classic.

В приведенном примере приложение должно находится на карте памяти в строго определенном месте. Если приложение находится по другому пути на карте памяти, то можно создать приложение «Autorun.exe», которое будет запускать приложение по другому указанному пути.

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

Запуск в определенное время
Операционная система позволяет задать таймер для запуска приложения. Для этих целей существует функция «CeRunApAtTime» в библиотеке «coredll.dll». Поскольку библиотека работает на основе неуправляемого кода, следует использовать P/Invoke для вызова функции. Перед этим следует определить структуру SystemTime, которая понадобится при вызове функций.

Код:
[StructLayout(LayoutKind.Sequential)]
public class SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}

Для вызова функций следует сделать обертку над ними.

Код:
public static class TimeLuanchHelper
{
[DllImport("coredll.dll")]
public static extern int CeRunAppAtTime(string application, SystemTime startTime);

[DllImport("coredll.dll")]
public static extern int FileTimeToSystemTime(ref long lpFileTime, SystemTime lpSystemTime);
[DllImport("coredll.dll")]
public static extern int FileTimeToLocalFileTime(ref long lpFileTime, ref long lpLocalFileTime);
}

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

Код:
public static class TimeLuanchHelper
{
[DllImport("coredll.dll")]
public static extern int CeRunAppAtTime(string application, SystemTime startTime);

[DllImport("coredll.dll")]
public static extern int FileTimeToSystemTime(ref long lpFileTime, SystemTime lpSystemTime);
[DllImport("coredll.dll")]
public static extern int FileTimeToLocalFileTime(ref long lpFileTime, ref long lpLocalFileTime);

public static void ScheduleRun(string application, DateTime startTime)
{
long fileTimeUTC = startTime.ToFileTime();
long fileTimeLocal = 0;
SystemTime timeToStart = new SystemTime();
FileTimeToLocalFileTime(ref fileTimeUTC, ref fileTimeLocal);
FileTimeToSystemTime(ref fileTimeLocal, timeToStart);
CeRunAppAtTime(application, timeToStart);

}

public static void ScheduleRun(string application, TimeSpan timeDisplacement)
{
var timeToStart = DateTime.Now + timeDisplacement;
ScheduleRun(application, timeToStart);
}
}

Теперь мы можем вызвать метод ScheduleRun и указать абсолютное или относительное время для запуска приложения.

Запуск приложения при наступлении внешних событий
Операционная система дает возможность запускать приложения при наступлении различных событий в системе. Например, можно запускать приложения в момент восстановления устройства из режима сна, в момент подключения или отключения от сети или после окончания синхронизации устройства через ActiveSync (полный список — ниже).

Для определения событий используется функция «CeRunAppAtEvent» библиотеки «coredll.dll». В параметрах этой библиотеки следует передать путь до приложения и идентификатор события для срабатывания. Создадим для этой функции небольшую обертку.

Код:
public static class EventLuanchHelper
{
[DllImport("coredll.dll")]
public static extern int CeRunAppAtEvent(string application, int EventID);
}

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

Код:
public enum EventId
{
NOTIFICATION_EVENT_NONE = 0,
NOTIFICATION_EVENT_TIME_CHANGE = 1,
NOTIFICATION_EVENT_SYNC_END = 2,
NOTIFICATION_EVENT_ON_AC_POWER = 3,
NOTIFICATION_EVENT_OFF_AC_POWER = 4,
NOTIFICATION_EVENT_NET_CONNECT = 5,
NOTIFICATION_EVENT_NET_DISCONNECT = 6,
NOTIFICATION_EVENT_DEVICE_CHANGE = 7,
NOTIFICATION_EVENT_IR_DISCOVERED = 8,
NOTIFICATION_EVENT_RS232_DETECTED = 9,
NOTIFICATION_EVENT_RESTORE_END = 10,
NOTIFICATION_EVENT_WAKEUP = 11,
NOTIFICATION_EVENT_TZ_CHANGE = 12,
NOTIFICATION_EVENT_MACHINE_NAME_CHANGE = 13
};

Теперь мы можем вызвать метод CeRunAppAtEvent и указать нужное событие.

Код:
EventLuanchHelper.CeRunAppAtEvent(«path», (int) EventId.NOTIFICATION_EVENT_ON_AC_POWER);

Если необходимо отменить поведение запуска приложение на срабатывание события, то нужно вызвать метод с параметром NOTIFICATION_EVENT_NONE.

Код:
EventLuanchHelper.CeRunAppAtEvent(«path», (int)EventId.NOTIFICATION_EVENT_NONE);

Список доступных событий:

  • NOTIFICATION_EVENT_TIME_CHANGE — изменение времени;
  • NOTIFICATION_EVENT_SYNC_END — завершение синхронизации через ActiveSync;
  • NOTIFICATION_EVENT_ON_AC_POWER — подключение внешнего источника питания;
  • NOTIFICATION_EVENT_OFF_AC_POWER — отключение внешнего источника питания;
  • NOTIFICATION_EVENT_NET_CONNECT — подключение к сети;
  • NOTIFICATION_EVENT_NET_DISCONNECT — отключение от сети;
  • NOTIFICATION_EVENT_DEVICE_CHANGE — подключено устройство (например, вставлена карта памяти);
  • NOTIFICATION_EVENT_IR_DISCOVERED — соединение по ИК-порту;
  • NOTIFICATION_EVENT_RS232_DETECTED — соединение по интерфейсу RS-232;
  • NOTIFICATION_EVENT_WAKEUP — выход из режима сна;
  • NOTIFICATION_EVENT_TZ_CHANGE — изменение временной зоны;
  • NOTIFICATION_EVENT_MACHINE_NAME_CHANGE — изменение имени устройства.

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты