2014-10-15 2 views
2

У меня есть служба Windows .net, работающая как локальная система. У меня есть другой процесс .net, который должен ждать завершения службы. Этот процесс не знает имя службы, поэтому он не может запросить диспетчер управления сервисом. Он знает идентификатор процесса обслуживания. Я могу изменить источники как службы Windows, так и другого процесса.Как подождать системного процесса из пользовательского процесса?

Когда я делаю:

process = Process.GetProcessById(processId); 
process.WaitForExit(); 

из другого процесса, я получаю:

System.ComponentModel.Win32Exception: Access is denied 

Stack trace: 
    at System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) 
    at System.Diagnostics.Process.WaitForExit(Int32 milliseconds) 

GetProcessHandle называет OpenProcess. По-видимому, целевой процесс должен позволить SYNCHRONIZE bit работать выше, что теоретически может быть установлено SetSecurityInfo из Службы Windows. Однако, похоже, нет простого способа сделать это в .NET, чтобы не вызвать несколько pinvokes для повышения, включить привилегию и, наконец, изменить безопасность.

Я пропустил простой способ ожидания на другом (системном) процессе от пользовательского процесса?

+0

Ваш процесс 32 бит и обслуживание 64 бит? IIRC есть некоторые ограничения в том, что 32-битный процесс может запросить около 64-битный процесс. –

+0

@SriramSakthivel оба скомпилированы с целевым набором в «Любой» –

+0

Какая строка выдает «Win32Exception». Это 'GetProcessById' или' WaitForExit'? –

ответ

1

Попробуйте использовать одну и ту же учетную запись для запуска службы и вашей программы. Или используйте встроенную учетную запись администратора для запуска вашей программы (Windows Vista и после нее).

Если оно по-прежнему вызывает исключение, попробуйте установить параметр DEP (Предотвращение выполнения данных) вашего компьютера.

Обновлено: Может быть, вы могли бы использовать этот дурацкий код .. это беда для получения имени службы, так как он не может так же, как Process.Name.

static ServiceController GetServiceControllerByPId(int processId) 
{ 

    string serviceName = ""; 

    string qry = "SELECT NAME FROM WIN32_SERVICE WHERE PROCESSID = " + processId.ToString(); 
    System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(qry); 
    System.Management.ManagementObjectCollection mngntObjs = searcher.Get(); 

    foreach (System.Management.ManagementObject mngntObj in mngntObjs) 
    { 
     serviceName = (string)mngntObj["NAME"]; 
    } 
    if (serviceName == "") 
    { 
     return null; 
    } 

    return System.ServiceProcess.ServiceController.GetServices().FirstOrDefault(x => x.ServiceName == serviceName); 
} 

Вызов этой функции и контролировать ServiceController.Status

+0

К сожалению, это не вариант. Служба должна запускаться как локальная система, и процесс должен запускаться под текущей учетной записью пользователя. Но спасибо за предложение. –

+0

@zespri: ответьте на обновления, надеюсь, что это вам поможет. – Harley

0

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

Process process = Process.GetProcessById(1); 
ServiceController windowsService = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName == process.ProcessName); 

//Wait until the windows service stops running 
while (windowsService.Status == ServiceControllerStatus.Running) 
{ 
    Thread.Sleep(1000); 
} 
+0

Имя службы, возможно, не совпадает с именем процесса. – Harley

+0

Возможно, вы могли бы P/Invoke QueryServiceStatusEx получить идентификатор процесса для каждой службы? –

Смежные вопросы