打包的 WPF 应用程序在用作新进程的参数时返回错误的 AppData 路径

Posted

技术标签:

【中文标题】打包的 WPF 应用程序在用作新进程的参数时返回错误的 AppData 路径【英文标题】:Packaged WPF app returns wrong AppData path when used as argument for a new process 【发布时间】:2021-07-16 17:05:24 【问题描述】:

我有一个打包为 MSIX 应用的 WPF .NET Core 3.1 应用。该应用程序将一些资产从 S3 下载到 AppData 文件夹,并在某个时候启动另一个进程(另一个应用程序),其中一个参数是下载的资产之一的路径(一个 Settings.xml 文件)。

我面临两个问题:

    应用有时会将资产下载到“真实”AppData 路径 (C:\Users\my_user\AppData\Local\some_created_folder),有时会下载到虚拟化路径 (C:\Users\my_user\AppData\Local\Packages\package_id\LocalCache\Local\some_created_folder)。我最近才在 3 个不同的版本(3 个连续版本)中注意到后者:第一个使用“真实”,第二个使用虚拟化,第三个再次使用“真实”。我很确定没有可能导致这种情况的代码更改。

    我正在使用Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) 编写下载路径。当资产被下载到虚拟化路径时,第二个应用程序没有正确启动,因为在启动过程时设置为参数的设置文件路径指向“真实”路径(总是!)。不会抛出异常或错误!

var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var settingsFilePath = Path.Combine(appData, "Settings", "Settings.xml");

...

var settingsFile = new FileInfo(settingsFilePath);
if (settingsFile.Exists)

    var arguments = $"-l \"settingsFile.FullName\"";
    var fileInfo = new FileInfo(_options.ExePath);
    var process = new Process
    
        StartInfo = new ProcessStartInfo
        
             FileName = fileInfo.FullName,
             WorkingDirectory = fileInfo.DirectoryName ?? string.Empty,
             Arguments = arguments
        
    ;

    if (process.Start())
    
        process.WaitForInputIdle();
    

     _logger.LogDebug("Started name arguments", fileInfo.FullName, arguments);

else

     throw new FileNotFoundException($"Settings file not found at path 'settingsFile.FullName'!", Path.GetFileName(settingsFile.Name));

我阅读了this,但我不明白为什么该应用会表现得如此不可预测。还是我错过了什么?包清单文件具有EntryPoint="Windows.FullTrustApplication"。我也知道 UWP 桌面桥虚拟化了一些文件系统路径,但我希望它是可预测的。

问题

    如何确保我下载的资产始终位于同一路径上,无论是“真实”的还是虚拟的? 如何将第二个应用的参数设置为始终指向文件真正存在的位置(“真实”与虚拟化)?

【问题讨论】:

【参考方案1】:

我还没有答案,但我需要您提供更多详细信息来进一步调查:

    您确定“真实”appdata 文件夹下的文件不是您在从 VS 调试应用时意外创建的吗?

据我所知,打包的应用程序在打开已存在于该位置的文件夹或文件时使用普通、真实的 AppData 资源和路径。如果 Appdata 文件夹/文件是从头开始创建的,那么它应该使用虚拟化位置。

从 MSI 迁移到 MSIX 时,此行为非常有用,直到用户选择卸载 MSI 版本,MSI 和 MSIX 变体可以并行使用,两者都可以访问相同的 AppData 文件。

再说一次,如果这不是您的应用程序的第一个版本,并且您之前已将其作为 MSI 部署给您的用户,那么在从内部运行时,您将无法确定您正在使用哪个 AppData 文件夹容器。

C:\Users\my_user\AppData\Local\some_created_folder

但是,在研究这一点时,我发现您也可以使用 Windows.Storage.ApplicationData.Current.LocalFolder.Path 来编写您的应用程序数据。也许这会起作用?

Windows.Storage.ApplicationData.Current.LocalFolder.Path changes the path during normal debug and a test
    第二个应用程序是来自同一 MSIX 包的 EXE 还是来自机器的另一个单独的应用程序(使用其自己的 MSI/MSIX 部署)? 我可能错了,但如果没记错的话,虚拟化 AppData 文件夹只能在您的应用容器内访问,因此机器上的其他应用无法访问这些文件。

如果是这种情况,您可以尝试将数据保存在 CommonApplicationData 文件夹中,如果这不是用户特定的数据。

相关问题:

How to allow for editable .Net generated config files with MSIX?

【讨论】:

感谢您的回答。 1. 是的,我确信情况并非如此。我只能在从商店安装应用程序的 PROD 环境中重现该问题。我们只有MSIX版本,之前没有MSI。 2. 它是一个单独的 EXE 应用程序(没有 MSIX)。 正如我在下面的链接中所说并且受到 MSFT 支持,AppData 文件夹不适合与其他应用程序共享信息,因为它仅对您的应用程序容器是私有的:docs.microsoft.com/en-us/windows/msix/desktop/… 尝试使用CommonApplicationData 文件夹或其他未虚拟化的文件夹,但首先确保您的包中没有任何文件应安装在 CommonApplicationData 中,否则该文件夹也会被虚拟化,如上面链接的同一篇文章中所述。

以上是关于打包的 WPF 应用程序在用作新进程的参数时返回错误的 AppData 路径的主要内容,如果未能解决你的问题,请参考以下文章

如何返回地理位置响应对象以用作另一个函数的参数

将 MS Access 用作 Winform 或 WPF 的后端时如何避免损坏 MS Access

WPF:仅将使用“AddFontMemResourceEx”安装的字体用于进程

wpf进程间通讯

从打包为Store应用程序的WPF应用程序启动URI

WPF MVVM里,当用户在新窗口执行完后如何返回原窗口,并刷新