Ответ 1
Чтобы найти местоположение папки, вы можете просто запустить приложение, открыть диспетчер задач (CTRL-SHIFT-ESC), выбрать приложение и щелкнуть правой кнопкой мыши | Открыть расположение файла.
Мне нужно написать файл в той же папке, где находится консоль ClickOnce .application
(исполняемый файл). Папка, из которой она запускается.
Я попытался использовать Application.StartupPath
и Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
но путь указывается на подпапку под c:\Documents & Settings
. Как получить путь, в котором находится .application
?
Чтобы найти местоположение папки, вы можете просто запустить приложение, открыть диспетчер задач (CTRL-SHIFT-ESC), выбрать приложение и щелкнуть правой кнопкой мыши | Открыть расположение файла.
путь указывает на подпапку в папке c:\Documents and 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
ApplicationDeployment.CurrentDeployment.ActivationUri может работать
"Строка с нулевой длиной, если свойство TrustUrlParameters в манифесте развертывания является ложным или если пользователь предоставил UNC для открытия развертывания или открыл его локально. В противном случае возвращаемое значение будет полным URL-адресом, используемым для запуска приложение, включая любые параметры."
НО, что я думаю, что вы действительно хотите, ApplicationDeployment.CurrentDeployment.DataDirectory, который дает вам папку, в которую вы можете записать данные. Когда вы все время обновляете приложение, вы потеряете то, что было в исходной папке .exe, но вы можете перенести каталог данных в новую версию приложения. Ваше приложение может писать в эту папку с любыми файлами журналов, которые у вас есть, - и я уверен, что он гарантированно доступен для записи.
Я использую Assembly.GetExecutingAssembly().Location
, чтобы получить путь к развертываемому приложению ClickOnce
в .Net 4.5.1.
Однако вы не должны писать в любую папку, где ваше приложение будет развернуто, независимо от способа развертывания (xcopy, ClickOnce, InstallShield, что-либо), поскольку они обычно читаются только для приложений, особенно в новых версиях Windows и сервере сред.
Приложение должно всегда записывать в папки, зарезервированные для таких целей. Вы можете получить нужные папки, начиная с Environment.SpecialFolder Enumeration. На странице MSDN объясняется, для каждой папки: http://msdn.microsoft.com/en-us/library/system.environment.specialfolder.aspx
т.е. для данных, журналов и других файлов можно использовать ApplicationData
(роуминг), LocalApplicationData
(локальный) или CommonApplicationData
.
Для временных файлов используйте Path.GetTempPath
или Path.GetTempFileName
.
Вышеописанная работа над серверами и рабочими столами.
EDIT:
Assembly.GetExecutingAssembly()
вызывается в основном исполняемом файле.
Приложения ClickOnce находятся в подкаталоге C:\Documents and Settings. У них нет "чистых" каталогов установки, потому что локальные файлы по существу "временно" загружаются, чтобы приложение могло запускаться на локальном ПК, а выполнение приложения контролируется с сервера ClickOnce, который они развернут, в зависимости от настроек публикации (Проверка обновлений, требований к версии и т.д.).
После некоторого исчерпывающего поиска, я наконец нашел способ найти обфускацию имен папок через реестр. Вот простой способ их извлечения:
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 =
[email protected]"{appToken.Substring(0, 8)}.{appToken.Substring(8, 3)}\{appToken.Substring(11, 8)}.{appToken.Substring(19, 3)}";
var dataDir =
[email protected]"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));
}
Вот что я нашел, что работал на то, чтобы получить локализованное расположение папки моего приложения clickonce и которое не упоминалось нигде, которое я видел в моих поисках, для моего сходного, конкретного сценария:
Вот пример моего использования:
Я не нашел ни одного из предложений в этом вопросе или их комментариях для работы в возвращении папки, в которую было развернуто приложение clickonce (чтобы я мог перемещаться относительно этой папки, чтобы найти интересующую папку). Никакой другой поиск в Интернете или связанные с ним вопросы не вызывали ответа.
Все предлагаемые свойства либо не выполнялись из-за того, что объект (например, ActivationUri) был нулевым, либо указывали на локальную папку с установленным приложением для ПК. Да, я мог бы изящно обрабатывать нулевые объекты с помощью проверки на IsNetworkDeployed - это не проблема, но удивительно, что IsNetworkDeployed возвращает false, даже несмотря на то, что на самом деле у меня есть место для развертывания сети для приложения clickonce. Это связано с тем, что приложение выполняется из локальных кешированных битов.
Решение состоит в том, чтобы посмотреть:
AppDomain.CurrentDomain.BaseDirectory
, когда приложение запускается в visual studio по мере разработки иSystem.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation
, когда он выполняется нормально. System.Deployment.Application.ApplicationDeployment.CurrentDeployment.UpdateLocation
корректно возвращает сетевой каталог, к которому во время развертывания применяется приложение clickonce. То есть, когда он запускается через:
Здесь код, который я использую при запуске приложения, чтобы получить путь к папке 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();
}
}
Если предположить, что вопрос заключается в доступе к файлам в папке приложения после того, как приложение ClickOnce (true == System.Deployment.ApplicationDeploy.IsNetworkDeployed) установлено на пользовательском ПК, это три способа получить эту папку самим приложением:
String path1 = System.AppDomain.CurrentDomain.BaseDirectory;
String path2 = System.IO.Directory.GetCurrentDirectory();
String path3 = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; //Remove the last path component, the executing assembly itself.
Они работают из VS IDE и из развернутого/установленного приложения ClickedOnce, проверка "true == System.Deployment.ApplicationDeploy.IsNetworkDeployed" не требуется. ClickOnce выбирает любые файлы, включенные в проект Visual Studio 2017, поэтому приложение может получить доступ ко всем развернутым файлам, используя относительные пути из приложения.
Это основано на Windows 10 и Visual Studio 2017