Как получить путь к папке для приложения ClickOnce - PullRequest
150 голосов
/ 01 марта 2010

Мне нужно записать файл в ту же папку, где находится консоль ClickOnce .application (исполняемый файл). Папка, из которой он запускается.

Я пытался использовать Application.StartupPath & Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) но путь указывает на подпапку в c:\Documents & Settings. Как мне получить путь, по которому находится .application?

Ответы [ 7 ]

235 голосов
/ 23 февраля 2012

Чтобы найти расположение папки, вы можете просто запустить приложение, открыть диспетчер задач (CTRL-SHIFT-ESC), выбрать приложение и щелкнуть правой кнопкой мыши | Открыть местоположение файла.

117 голосов
/ 09 марта 2010

путь указывает на подпапку в папке c: \ Documents & Settings

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

В Windows Vista и Windows 7 вы найдете кеш ClickOnce здесь:

c:\users\username\AppData\Local\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername

В Windows XP вы найдете его здесь:

C:\Documents and Settings\username\LocalSettings\Apps\2.0\obfuscatedfoldername\obfuscatedfoldername
24 голосов
/ 04 января 2012

ApplicationDeployment.CurrentDeployment.ActivationUri может работать

"Строка нулевой длины, если свойство TrustUrlParameters в манифесте развертывания имеет значение false, или если пользователь предоставил UNC для открытия развертывания или открыл его локально. В противном случае возвращаемое значение представляет собой полный URL-адрес, используемый для запуска приложение, включая любые параметры. "


НО, я думаю, что вы действительно хотите, это ApplicationDeployment.CurrentDeployment.DataDirectory , которая дает вам папку, в которую вы можете записывать данные. В любом случае, когда вы обновите приложение, вы потеряете то, что было в исходной папке .exe, но вы можете перенести каталог данных в новую версию приложения. Ваше приложение может записывать в эту папку любые файлы журналов, которые оно имеет, и я уверен, что оно гарантированно доступно для записи.

13 голосов
/ 23 ноября 2014

Я использую Assembly.GetExecutingAssembly().Location, чтобы получить путь к развернутому приложению ClickOnce в .Net 4.5.1.

Однако вы не должны писать в какую-либо папку, в которой развернуто ваше приложение, независимо от метода развертывания (xcopy, ClickOnce, InstallShield и т. Д.), Поскольку они обычно читаются только для приложений, особенно в новых версиях Windows и на сервере. окружающая среда.

Приложение всегда должно записывать в папки, зарезервированные для таких целей. Вы можете получить нужные вам папки, начиная с Перечисления Environment.SpecialFolder. Страница MSDN объясняет, для чего каждая папка: http://msdn.microsoft.com/en-us/library/system.environment.specialfolder.aspx

т.е. для данных, журналов и других файлов можно использовать ApplicationData (роуминг), LocalApplicationData (локальный) или CommonApplicationData. Для временных файлов используйте Path.GetTempPath или Path.GetTempFileName.

Вышеописанное работает и на серверах и настольных компьютерах.

EDIT: Assembly.GetExecutingAssembly() вызывается в главном исполняемом файле.

3 голосов
/ 28 августа 2017

После тщательного поиска я наконец-то нашел способ найти запутанные имена папок через реестр. Вот простой способ их получения:

private static Tuple<string, string> GetClickonceDirectories()
{
    var appToken  = (string) Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0", "ComponentStore_RandomString", null);
    var dataToken = (string) Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0\StateManager", "StateStore_RandomString", null);

    if (string.IsNullOrWhiteSpace(appToken) || string.IsNullOrWhiteSpace(dataToken))
    {
        throw new Exception("Unable to find clickonce directories.");
    }

    var appDir =
            $@"{appToken.Substring(0, 8)}.{appToken.Substring(8, 3)}\{appToken.Substring(11, 8)}.{appToken.Substring(19, 3)}";

    var dataDir = 
            $@"Data\{dataToken.Substring(0, 8)}.{dataToken.Substring(8, 3)}\{dataToken.Substring(11, 8)}.{dataToken.Substring(19, 3)}";

    var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
    rootPath = Path.Combine(rootPath, "Apps", "2.0");

    return new Tuple<string, string>(Path.Combine(rootPath, appDir), Path.Combine(rootPath, dataDir));
}
3 голосов
/ 02 марта 2010

Приложения ClickOnce DO находятся в подкаталоге C: \ Documents & Settings. У них нет «чистых» каталогов установки, потому что локальные файлы по существу «временно» загружаются, чтобы позволить приложению запускаться на локальном ПК, а выполнение приложения контролируется с сервера ClickOnce, на котором они развернуты, в зависимости от настроек публикации (Проверка наличия обновлений, требований к версии и т. Д.).

1 голос
/ 05 июля 2017

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

  • Приложение clickonce развертывается в сетевой папке локальной сети компании.
  • Приложение clickonce доступно для работы в Интернете или в автономном режиме.
  • Мои URL-адреса установки clickonce и URL-адреса обновлений в свойствах моего проекта не указаны. То есть отдельного места для установки или обновления не существует.
  • В моих опциях публикации у меня есть ярлык на рабочем столе, созданный для приложения clickonce.
  • Папка, для которой я хочу получить путь при запуске, является папкой, к которой я хочу получить доступ в версиях приложения DEV, INT и PROD, без жесткого указания пути.

Вот изображение моего варианта использования:

enter image description here

  • Папки в синей коробке - это мои каталоги для каждого применение среды.
  • Красная коробочная папка - это каталог, для которого я хочу получить путь (для этого необходимо сначала получить местоположение развернутой папки приложения «MyClickOnceGreatApp_1_0_0_37», который совпадает с OP).

Я не нашел ни одного из предложений в этом вопросе или их комментариев для работы по возвращению папки, в которой было развернуто приложение clickonce (которую я затем переместил бы относительно этой папки, чтобы найти интересующую папку). Ни один другой поиск в Интернете или связанные с ним вопросы SO тоже не нашли ответа.

Все предложенные свойства либо не работали из-за того, что объект (например, ActivationUri) был нулевым, либо указывали на кешированную папку установленного приложения на локальном ПК. Да, я мог бы изящно обрабатывать нулевые объекты с помощью проверки IsNetworkDeployed - это не проблема - но удивительно, что IsNetworkDeployed возвращает false, даже если у меня действительно есть расположение развернутой в сети папки для приложения clickonce. Это связано с тем, что приложение запускается из локальных кэшированных битов.

Решение состоит в том, чтобы посмотреть:

  • AppDomain.CurrentDomain.BaseDirectory когда приложение запускается в Visual Studio во время разработки и
  • System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation при нормальном выполнении.

System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation правильно возвращает сетевой каталог, в котором развернуто мое приложение clickonce, во всех случаях. То есть когда он запускается через:

  • setup.exe
  • MyClickOnceGreatApp.application
  • Ярлык на рабочем столе, созданный при первой установке и запуске приложения.

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

string directoryOfInterest = "";
if (System.Diagnostics.Debugger.IsAttached)
{
    directoryOfInterest = Directory.GetParent(Directory.GetParent(Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).FullName).FullName).FullName;
}
else
{
    try
    {
        string path = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation.ToString();
        path = path.Replace("file:", "");
        path = path.Replace("/", "\\");
        directoryOfInterest = Directory.GetParent(Directory.GetParent(path).FullName).FullName;
    }
    catch (Exception ex)
    {
        directoryOfInterest = "Error getting update directory needed for relative base for finding WorkAccounts directory.\n" + ex.Message + "\n\nUpdate location directory is: " + System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation.ToString();
    }
}
...