簡體   English   中英

如何從.NET Windows服務啟動exe以更新服務

[英]How to start an exe from a .NET Windows Service for updating the service

我有一個Windows服務,我希望它可以自動進行無提示更新。 我開始使用wyBuild來實現它,但是遇到了一些問題,因此決定嘗試構建自己的。 我已經編寫了一個獨立的exe文件,可以調用它來執行更新過程:檢查包含更新的新zip文件,下載該文件,解壓縮,停止Windows服務,從zip復制文件,然后重新啟動該服務。 當我從命令行運行該exe時,它運行良好,並且編寫起來並不難。

但是,現在我希望該服務(正在更新同一服務)能夠將其安裝到updater exe中進行更新。 我首先嘗試了Process.Start:

var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);

這稱為更新程序,但是當更新程序停止服務時,進程將被終止,更新程序將停止。 我做了一些搜索,聽起來解決方案是使用單獨的AppDomain。 這就是我現在所擁有的:

Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);

但是,現在出現錯誤System.IO.IOException:“該進程無法訪問文件'C:\\ Program Files(x86)\\ Company \\ Service \\ Service.dll',因為它正被另一個進程使用”復制新的Service.dll

同樣,我已經停止了該服務。 我已經通過日志記錄確認了這一點。 我無法想象Service.dll仍會鎖定,因此我添加了代碼來檢查鎖定了什么:

 public static IEnumerable<Process> GetProcessesLocking(string filePath)
    {
        var result = new List<Process>();

        result.Clear();
        var processes = Process.GetProcesses();
        foreach (Process proc in processes)
        {
            try
            {
                if (proc.HasExited) continue;
                foreach (ProcessModule module in proc.Modules)
                {
                    if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
                    {
                        result.Add(proc);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                Log(ex.ToString());
                Log("There was an error checking " + proc.ProcessName );
            }
        }
        return result;
    }

但是,此代碼表明dll上沒有任何鎖(結果為空,並且未記錄任何內容指示錯誤)。

我懷疑我遇到了某些UAC問題,這是IOException的真正原因。 Windows服務作為LocalSystem運行。 所有要問的問題:我應該如何從Windows服務運行更新exe,以便它有權復制c:\\ Program Files中的文件?

更新資料

正如評論和答案所暗示的,Process.Start可以工作,但有一些細微差別。 您必須啟動cmd.exe並使用來啟動更新程序。 我還發現我無法使用更新程序exe的完整路徑,因此需要設置UseShellExecute = false。 這是我從.NET服務啟動更新程序的最終工作代碼:

 var cmd = "/c start updater.exe";     
 var startInfo = new ProcessStartInfo("cmd.exe");
 startInfo.Arguments = cmd;
 startInfo.WorkingDirectory = AssemblyDirectory;
 startInfo.UseShellExecute = false;
 var proc = Process.Start(startInfo);

我做了這個確切的事情-使用一種更簡單的方法(有些人可能說kludgy)。 服務:

  1. 產生一個批處理命令,
  2. 將新的可執行文件下載到暫存位置,
  3. 啟動一個進程:cmd.exe,該進程依次運行不帶等待其完成的批處理腳本,然后
  4. 立即終止。

批處理命令:

  1. 五次Ping 127.0.0.1,
  2. 將可執行文件復制到最終位置,然后,
  3. 重新啟動服務。

像發條一樣工作。 ping是可靠的​​5秒延遲-讓服務在復制文件之前關閉。

編輯

只是為了完整性-我意識到按批處理ping是127.0.0.1而不是128.0.0.1,因此我編輯了此答案以反映這一點。 我想這兩個都可以-但是128.0.0.1 ping超時,其中127.0.0.1解析為“我”。 由於我只是將其用作窮人的延誤,因此無論哪種方式都可以達到目的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM