【问题标题】:Start an offline ClickOnce Application and wait for Exit启动离线 ClickOnce 应用程序并等待退出
【发布时间】:2014-02-04 14:55:01
【问题描述】:

我已经部署了一个 ClickOnce Windows 窗体应用程序(应用程序 A)

另一个应用程序(应用程序 B)以文件名作为参数启动应用程序 A。 我用这段代码做到这一点

var basePath = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var location = String.Format(@"{0}\{1}\{2}\{3}",
    basePath, "MyCompany", "MyProduct", "MyApp.appref-ms");

var fileName = @"c:\temp\somefile.ext";
var uri = new Uri(fileName).ToString();

Process.Start(location, uri);

App A 从AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0] 获取文件名并显示内容。

这就像一个魅力。但是,现在我希望 App B 等待 App A 退出。 但是对Process.WaitForExit() 的调用会立即返回。

有没有办法打开 ClickOnce 应用程序并等待它退出?如有必要,我可以更改应用程序的打开方式,但要求是我需要将应用程序作为 ClickOnce 应用程序运行(我知道在我的用户配置文件 AppData\Local\Apps\2.0\ 文件夹中的某处,exe 存在并且可以直接启动但如果我这样做,ApplicationDeployment.IsNetworkDeployedfalse 并且 ApplicationDeployment.CurrentDeployment 是空的。这样我就失去了 ClickOnce 更新功能。

【问题讨论】:

  • 我认为这是正确的行为。如果您将 ClickOnce 称为“可执行文件”,它将检查更新。但是这种行为 - 据我所知 - 位于生成的引导程序内部。然后它将调用真正的可执行文件。我想稍后再看看这种行为。一个想法:抓住“真正的”进程并等待它退出?
  • @Herdo - 使用System.Reflection.Assembly.GetEntryAssembly().Location; 很容易实现这一点并且可以工作。但是,我的应用程序设计为从另一个应用程序调用,不会直接启动。如果我这样做,我将失去自我更新功能,这是此应用使用 click once 的主要原因。

标签: c# .net vb.net winforms clickonce


【解决方案1】:

我的建议是在 App A 中使用Mutex,让 App B 检查并等待它。从我的角度来看,这是最干净的方式。

App A 在启动时会这样做:

    private static Mutex mutex;

    public static void Main()
    {
        // if you want your app to be limited to a single instance
        // across ALL SESSIONS (multiple users & terminal services), then use the following line instead:
        // string mutexName = string.Format("Global\\{0}", ProgramInfo.AssemblyGuid);
        var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
        mutex = new Mutex(true, mutexName, out singleInstance);

        if (singleInstance == false)
        {

           // that means your app has more than one instance running
           // you need to decide what to do here.
        }

        // rest of initialization code

        Application.Run();

        // release the mutex so App B can continue
        mutex.ReleaseMutex();
    }

而应用 B 只是等待互斥锁被释放:

Process.Start(location, uri);
Thread.Sleep(5000);  // give it 5 seconds or so to check for updates and start
var mutexName = string.Format("Local\\{0}", SOME_SHARED_GUID);
mutex = new Mutex(false, mutexName);
mutex.WaitOne();

【讨论】:

  • 这似乎是一个很好的解决方案,我可以使用new FileInfo(fileName).FullName 作为互斥体名称。这将允许我从多个 App B 实例启动多个 App A 实例。即使 App A 崩溃,这也不是问题,因为我已经在 App B 中实现了 Waiting for App A... Cancel 对话框
  • 我猜clickonce应用不是我自己开发的情况下这个方案是不能适用的吧?
【解决方案2】:

问题在于,启动 appref-ms 进程并没有真正启动应用程序,而是启动部署清单,然后启动应用程序本身,因此您正在启动的进程立即退出。

如果您知道名称(我假设您知道),您可以添加一个检查以查看您的应用程序何时启动:

string myAppName = "YourAppName";
DateTime startTime = DateTime.Now;
int newProcessId = 0;
List<int> runningProcessIds = new List<int>();

//find all the running processes and record their Ids
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
    proc = proc_loopVariable;
    runningProcessIds.Add(proc.Id);
}

//start the new process
Process.Start(location);

//wait for the new application to be started
while (!(Process.GetProcessesByName(myAppName).Count != runningProcessIds.Count)) {
    //timeout if we have not seen the application start
    if ((DateTime.Now - startTime).TotalSeconds > 30)
        break; 
}

//loop through all the running processes again to find the id of the one that has just started
foreach (void proc_loopVariable in Process.GetProcessesByName(myAppName)) {
    proc = proc_loopVariable;
    if (!runningProcessIds.Contains(proc.Id)) {
        newProcessId = proc.Id;
        break; 
    }
}

//wait for the application to finish
Process.GetProcessById(newProcessId).WaitForExit();

Debug.WriteLine("Finished");

【讨论】:

  • 你说得对,我缩短了示例代码,它应该是 var process = Process.Start(location, uri); process.WaitForExit(); 问题与 ClickOnce 相关,因为我没有启动一个 exe,而是一个 appref-ms 文档和 process.HasExited 是真的.带有 exe 的相同代码真的会等待进程退出。
  • 这可以工作,但我还必须从 MyApp 中找到特定实例,因为它可以运行多次。我可以在运行Process.Start(...) 之前和之后调用GetProcessByName 并找出哪个是新的或使用Process.StartTime 来找到正确的实例。
  • 好的,我已经更新了我的答案,包括如何实现这一点
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多