我想从远程服务器更新我的 exe。因此,当按钮单击我的 wpf 应用程序时,它将下载远程文件和远程 txt 文件,并替换运行 exe 的同一文件夹中的当前文件。所以它会在我的 exe 运行时覆盖当前的 txt 和 exe 文件。我怎样才能做到这一点?
远程主机就像 urlwww.mydomain.com/MyAPP.exe
wpf 应用程序,c# 4.0
我想从远程服务器更新我的 exe。因此,当按钮单击我的 wpf 应用程序时,它将下载远程文件和远程 txt 文件,并替换运行 exe 的同一文件夹中的当前文件。所以它会在我的 exe 运行时覆盖当前的 txt 和 exe 文件。我怎样才能做到这一点?
远程主机就像 urlwww.mydomain.com/MyAPP.exe
wpf 应用程序,c# 4.0
我们解决此问题的方法是创建一个 shell exe,作为最初安装并部署到客户端计算机的那个。
“真正的”可执行程序存储在这个初始应用程序的子目录中。当 shell 应用程序启动时,在它下载并安装了真实应用程序的任何更新后,它会在单独的 AppDomain 中启动真实应用程序的可执行文件。
这是从 shell 应用程序中启动的“真实”应用程序的核心:
System.AppDomainSetup oSetup = new System.AppDomainSetup();
string sApplicationFile = null;
// Use this to ensure that if the application is running when the user performs the update, that we don't run into file locking issues.
oSetup.ShadowCopyFiles = "true";
oSetup.ApplicationName = sAppName;
// Generate the name of the DLL we are going to launch
sApplicationFile = System.IO.Path.Combine(sApplicationDirectory, sAppName + ".exe");
oSetup.ApplicationBase = sApplicationDirectory;
oSetup.ConfigurationFile = sApplicationFile + ".config";
oSetup.LoaderOptimization = LoaderOptimization.MultiDomain;
// Launch the application
System.AppDomain oAppDomain = AppDomain.CreateDomain(sAppName, AppDomain.CurrentDomain.Evidence, oSetup);
oAppDomain.SetData("App", sAppName);
oAppDomain.SetData("User", sUserName);
oAppDomain.SetData("Pwd", sUserPassword);
oAppDomain.ExecuteAssembly(sApplicationFile);
// When the launched application closes, close this application as well
Application.Exit();
请注意,在我们的版本中,shell 应用程序会从用户那里收集用户名和密码,以便正确访问更新网站。SetData
然后通过AppDomain 上的方法将此数据传递给“真实”应用程序。
解决方案取决于您的具体情况。但是没有直接的解决方案,因为当程序集加载到内存并被使用时,您无法更新程序集。我可以提出 2 个解决方案:使用影子复制和使用某种辅助可执行文件。这两个我都用过。
影印。
显而易见的方法是让您的主要可执行文件被影子复制,在您的应用程序运行时替换它,然后重新启动应用程序。但是你不能让你的默认应用程序域被影子复制,只有辅助应用程序域可以。但是您仍然可以将所有代码移动到另一个程序集中(例如 MainAppLib.dll)并重写您的主应用程序可执行文件(MainApp.exe),使其仅包含“加载程序代码”。此加载器代码必须创建另一个应用程序域,将其设置为影子复制,然后在辅助应用程序域中运行您的程序逻辑。请注意不要从您的主应用程序域直接引用 MainAppLib.dll,因为这样该程序集将被加载到您的主应用程序域中,该域不会被影子复制并且程序集文件将被锁定。在大多数情况下,您可以选择AppDomain.ExecuteAssembly()方法。
助手可执行文件
这个想法是使用某种更新完成器。您的主应用程序保持不变,您只需添加少量代码,您的应用程序将下载更新,将其放入临时文件夹,然后您的主应用程序启动更新完成器(在单独的进程中)并退出。更新完成程序会等到您的应用关闭,然后将新文件从临时文件夹复制到您的应用文件夹中,替换所有文件。更新完成器不能替换它自己的可执行文件,但它可以由主应用程序在启动更新完成器之前完成。复制文件后,更新修整器运行您的应用程序。
ps我个人更喜欢前一种解决方案,因为它涉及使用应用程序域、反射、程序集等的某种巫术魔法,如果需要(例如通过MEF 框架),它可以演变为使用插件。但后者更容易理解,特别是如果您从未使用过应用程序域和手动程序集加载,它非常简单。
您可能可以使用ClickOnce(根据您上面的评论,您将准备让另一个程序集获取 exe ......因为其他海报提到您无法替换正在运行的程序集)。您可以将其配置为在不同时间(例如在启动时)检查新版本并自动下载它们。它是一个非常强大的解决方案,您可以使用部署程序集做很多事情。