2015-09-02 2 views
0

У меня есть служба Windows, которую я хотел бы автоматически и без проблем обновлять. Я начал использовать wyBuild для реализации этого, но имел некоторые проблемы с ним, и решил попытаться построить свой собственный. Я написал автономный exe, который можно вызвать для выполнения процедуры обновления: проверяет наличие нового zip-файла с обновлением, загружает его, распаковывает, останавливает службу Windows, копирует файлы из zip и перезапускает службу. Этот exe отлично работает, когда я запускаю его из командной строки и писать не очень сложно.Как запустить exe из .NET Windows Service для обновления службы

Однако, теперь я хотел бы, чтобы служба (тот же самый обновлялась), чтобы выложить обновление для 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) \ Компания \ 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. Все, что задавать: Как должен Я запускаю обновление exe из службы Windows, чтобы он имел права копировать файлы в c: \ Program Files?

Update

В комментариях и ответ предполагает, Process.Start может работать, но есть некоторые нюансы. Вам необходимо запустить cmd.exe и использовать для его обновления. Я также обнаружил, что не могу использовать полный путь для exater updater и что мне нужно установить 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); 
+0

Полностью с головы, но почему бы не просто создать службу для запланированной задачи за 5 секунд? Таким образом, процесс, который инициирует обновление и фактическую обработку обновления, полностью отключен –

+0

Когда это произойдет, вы можете найти имя DLL («find handle») в Process Explorer, чтобы узнать, кто еще имеет дескриптор, открытый для DLL? Или запишите такой сеанс в Process Monitor. Просто найдите настоящего преступника. Вы не знаете, будет ли более успешным запуск через 5 секунд. –

+1

Ваше 1-е решение может работать. Прочтите http://stackoverflow.com/questions/1035213/process-start-and-the-process-tree, чтобы узнать, как сохранить обновление. –

ответ

1

Я сделал это точную вещь - с помощью более простого (некоторые могут сказать, запутаны) подход. Услуга:

  1. Производит команду партии,
  2. Загрузки новых исполняемых файлов в место постановки,
  3. Запускает процесс: cmd.exe, который, в свою очередь, запускает пакетный скрипт без жду его заполнить, а затем
  4. Немедленно оканчивается.

Команда партии:

  1. Отклики 127.0.0.1 пять раз,
  2. Копии исполняемых файлов до конечного места и,
  3. перезапускает службу.

Работы как часы. Пинг - это надежная 5-секундная задержка - позволяет завершить работу перед копированием файлов.

Edit:

Просто для полноты картины - я понял, что пакетный ЦМД пинг 127.0.0.1 не 128.0.0.1, и поэтому я редактировал этот ответ, чтобы отразить это. Я полагаю, что либо работает, но 128.0.0.1 таймаут пинга, где 127.0.0.1 разрешает «мне». Поскольку я использую его только как задержку бедного человека, он служит цели в любом случае.

+0

Похоже, что здесь используется Process.Start с cmd.exe. Process.Start ("cmd.exe", "/ c updater.exe") делает то, что я хочу. Мой процесс немного отличается - вместо пакета он использует консольное приложение .net, а консольное приложение проверяет наличие обновлений, останавливает/запускает сервис и применяет обновление. Есть некоторые другие нюансы, с которыми я столкнулся - я обновлю свой вопрос с помощью кода, который я использую. – Daniel

+0

Отлично - рад, что сработало для вас. Чистое извлечение из вашего процесса делает его намного проще. – Clay