#c_sharp #clickonce
Необходимо либо получить путь к ярлыку приложения, установленному при помощи ClickOnce, который создаётся в каталоге Environment.GetFolderPath(Environment.SpecialFolder.Programs)\PublisherName либо его создать программно. Всё что я находил либо не работает, либо не устраивает. UPD: В чем суть. При установке с помощью ClickOnce запускается ваше приложение, вы производите настройку, выходите из приложения, запускаете снова - всё ок, настройки есть. Программно получаете Application.StartupPath, этот путь закидываете в автозапуск в реестре или создаёте ярлык в Автозагрузке, но наступает фиаско, когда при включении ПК настроек нет, всё по дефолту и необходимо конфигурировать заново. И запустив приложение с ярлыка, в котором Application.StartupPath указан, мы можем получить настройки приложения отличные от тех, которые указывали запустив приложение с ярлыка созданного установщиком ClickOnce. Во как!
Ответы
Ответ 1
Самая неудачная идея для приложения с развертыванием clickonce, да и большинства приложений в принципе, это хранить конфигурационные файлы рядом с исполняемым файлом. Это вполне допустимо, если необходимые настройки можно сделать на этапе сборки релиза и менять их только в случае крайней необходимости, но если пользователь может менять их сам когда ему вздумается, лучше вынести в отдельное фиксированное расположение, не зависимое от расположения исполняемых файлов. Плюс к этому, механизм обновления clickonce построен таким образом, что ваши конфигурационные файлы могут быть перезаписаны во время обновления, если в обновленной версии они более новые, для текстовых файлов по дате последнего изменения. Причина такого поведения довольно проста, в конфигурации обновленного приложения могут быть дополнительные параметры, без которых оно не сможет нормально работать, следовательно самый простой путь - перезаписать старую конфигурацию новой. Самое грустное, что стандартные средства вроде app.config или Settings, которые можно настроить в свойствах проекта или добавить явно, предполагают хранение файла с настройками по-умолчанию рядом с исполняемым файлом. Разумеется, можно дописать недостающее в сгенерированый класс и он будет работать так как вы захотите, но по-умолчанию реализация минимальная из возможных, описание на MSDN довольно скудное, хотя при большом желании можно разобраться что и куда прописать в параметры объекта Settins, чтобы он начал себя вести хоть чуточку осмысленно (к тому же, MS сами в итоге отказались от этой идеи и по-умолчанию предлагают более легковесный и понятный app.config). Итого, нужно сделать так, чтобы ваше приложение один раз настроенное, не теряло настройки при обновлениях. переустановках и т.д. Штатные средства этого не позволяют, значит придется писать собственный менеджер (ну или допиливать заготовку Settings от MS). Зато вы можете сами выбрать удобный для вас формат хранения настроек, хоть шифрованный бинарник, если вас или заказчика мучает паранойя. В качестве возможных мест хранения конфигурации можно рассмотреть два: Реестр Windows (куст CurrentUser, чтобы не требовать права администратора) и папка %APPDATA%. В обоих случаях логика работы примерно одинакова, с поправкой на различие методов чтения/записи значений настроек: Проверяем наличие папки %APPDATA%\\ или нужного раздела реестра. Проверяете наличие нужных файлов конфигурации в папке, ключей в разделе реестра. (Опционально) Проверяем версию конфигурации. Если нужные файлы/ключи реестра обнаружены и версия подходит, загружаем настройки и работаем как обычно. Если не подходит версия, дочитываем необходимое из настроек по-умолчанию, при необходимости просим пользователя уточнить параметры. Если файлы/ключи реестра не обнаружены, создаем папку и файлы, запускаем конфигуратор для пользователя или просто стартуем с настройками по-умолчанию. Как видите, в данной схеме отсутствует упоминание "первого" и "последующих" запусков. В этом просто нет необходимости. Подобный подход не дает потерять настройки даже в результате случайного удаления и/или принудительной переустановки приложения по какой-то иной причине (при должном упорстве можно получить устойчивость и к переустановке ОС, но это уже отдельная тема). Еще один плюс данного подхода заключается в том, что данная папка, как и конечная папка размещения приложения clickonce, находятся в профиле пользователя, а это означает, что приложение и настройки будут доступны пользователю на любой машине, если у вас есть домен, машина в домене и в домене настроены перемещаемые профили пользователей. Как именно читать и сохранять настройки зависит от формата, который вы выберете. В простейшем случае можно просто скопировать *.config файлы с настройками по-умолчанию из папки с исполняемыми файлами в новое расположение и уже там их менять. Для получения дополнительных сведений о текущей установке приложения clickonce воспользуйтесь классом ApplicationDeployment. Вообще стоит повнимательнее почитать про его возможности, если решили использовать clickonce. Cсылку на приложение Environment.GetFolderPath(Environment.SpecialFolder.Programs)\PublisherName\AppName\AppName.appref-ms добавить в автозапуск любым удобным способом. При обозначенном выше способе хранения настроек, описанной вами проблемы не будет, так как они больше не привязаны к точке запуска приложения. Подобная схема хранения конфигураций прекрасно работает и с классической моделью установки, и с самописными обновляторами/инсталляторами, и, разумеется, с clickonce-приложениями. Причем конкретно у меня clickonce появился самым последним и никаких изменений для перехода не потребовалось. Ответ 2
создается сам при первом запуске но в настройках можно указать путь размещения приложенияОтвет 3
Вы неправильно регистрируете приложение в автозагрузке. ClickOnce-приложения не должны запускаться через .exe-файл Для того, чтобы запустить приложение, воспользу // Узел реестра, в котором хранятся автозапускаемые приложения using (RegistryKey rkApp = Registry.CurrentUser.OpenSubKey(@"\Microsoft\Windows\CurrentVersion\Run", true)) { // Путь к ярлыку вашего приложения string startPath; startPath = GetApplicationPath("YourPublisher", "YourSuite", "YourProduct"); startPath = GetApplicationPath("YourSuite", "YourProduct"); startPath = GetApplicationPath("YourProduct"); rkApp.SetValue("YourProduct", startPath); } private static String GetApplicationPath(String yourPublisher, String yourSuite, String yourProduct) { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), yourPublisher, yourSuite, yourProduct) + ".appref-ms"; } private static String GetApplicationPath(String yourSuite, String yourProduct) { foreach (String publisherPath in Directory.EnumerateDirectories(Environment.GetFolderPath(Environment.SpecialFolder.Programs))) { String applicationPath = Path.Combine(publisherPath, yourSuite, yourProduct) + ".appref-ms"; if (File.Exists(applicationPath)) return applicationPath; } throw new FileNotFoundException(); } private static String GetApplicationPath(String yourProduct) { return Directory.EnumerateFiles(Environment.GetFolderPath(Environment.SpecialFolder.Programs), yourProduct + ".appref-ms").First(); } Это немного модифицированное решение с англоязычной версии сайта. Поясню - ClickOnce-приложения ввиду возможности развёртывания в сети, используют в качестве хранилища персистентных данных не текущий каталог программы, а System.Deployment.Application.ApplicationDeployment.CurrentDeployment.DataDirectory. При запуске через ярлык он инициализируется. При запуске через .exe - нет.
Комментариев нет:
Отправить комментарий