У меня есть программа C ++, которая работает как служба на 64-разрядной машине с Windows Server 2008. Эта программа пытается запустить командный файл с помощью следующей команды:
system(C:\pathtofile\file.bat)
В 32-битной Windows Server 2003 это работало нормально (пакетный файл был выполнен), но в Windows Server 2008 пакетный файл не выполняется, и я получаю возвращаемое значение 0xC0000142 (у меня был пакетный файл, записывающий некоторый текст в файл как тест, чтобы увидеть, если он выполняется). Я на самом деле получаю то же возвращаемое значение, даже если пытаюсь выполнить то, чего не существует.
Я читал об изоляции сеанса 0 в Windows Server 2008, поэтому я использовал psexec для запуска командной строки в сеансе 0 в качестве того же пользователя домена, который указан как пользователь «Вход в систему» для службы:
psexec -i 0 -u DOMAIN\serviceuser -p passwd cmd.exe
Затем я смог успешно выполнить командный файл из командной строки.
Пользователь домена, который указан как пользователь «Вход в систему» для службы, находится в группе «Администраторы». Кроме того, если я запускаю приложение C ++ вручную (не как службу), оно запускает командный файл.
Так есть ли что-то в изоляции сеанса 0, которая делает вызов system () не работающим при работе в качестве службы? Или какое-то другое объяснение изменения поведения? Я знаю, что system () не обязательно лучший способ сделать это в любом случае, но я ищу фактическую причину, по которой это больше не работает.
Из того, что я теперь понимаю о проблеме, причина того, что вы не можете запустить командный файл из службы с помощью system () в Windows Server 2008, заключается в том, что Windows рассматривает любую попытку вызова cmd.exe (как это было бы для запуска вашего пакета). файл) как попытка запуска интерактивного сервиса. Из-за изоляции сеанса 0 это недопустимо и просто не удастся, даже если вы не думаете, что ваш командный файл является интерактивным или имеет графический интерфейс (который меня отбрасывал).
Я понял, как получить эффект, который искал, используя CreateProcess. Ключевым моментом здесь является то, что вы должны установить для параметра dwCreationFlags значение CREATE_NO_WINDOW. Так что мой (упрощенный) вызов в итоге выглядел примерно так:
CreateProcess(NULL, // No module name (use command line)
L"C:\\Windows\\System32\\cmd.exe /C myfile.bat", // Call cmd.exe with /C flag
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // Use CREATE_NO_WINDOW!!!
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
Других решений пока нет …