我正在尝试从我创建的C#服务中执行Shell命令。但是,该命令似乎没有执行。作为标准控制台应用程序,它可以完美运行,因此我知道命令本身或在代码中如何执行命令都没有问题。谁能告诉我为什么这行不通?请记住,我是C#的新手,所以这可能只是我的经验不足。以下是来自服务本身的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
namespace AdapterDisableTest
{
class Program : ServiceBase
{
//private static Timer workTimer;
static void Main(string[] args)
{
ServiceBase.Run(new Program());
}
public Program()
{
this.ServiceName = "AdapterDisableTest";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
Process myProcess = new Process();
myProcess.StartInfo.FileName = @"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe";
myProcess.StartInfo.Arguments = "controlvm test setlinkstate1 off";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
}
如果它是需要桌面的Windows应用程序,那么您几乎是SOL。如果它是标准控制台应用程序,则需要重定向标准输入,标准输出和标准错误。您还需要将ProcessStartInfo
的UseShellExecute
属性设置为false
:您的服务无法启动OS Shell(cmd.exe
),因为这需要访问桌面...而且,您可以t将该属性设置为true
的标准输入重定向。
标准输入通常连接到键盘。您的服务无权使用键盘。通常将标准输出和标准错误连接到cmd.exe
控制台窗口。
一旦您将标准输出和标准错误重定向,就需要将处理程序连接到这些Process
对象事件:
Exited
。在过程结束时引发。OutputDataReceived
。在该过程中将数据写入标准输出时引发(实际上,当刷新输出流上的任何缓冲区时发生,因此它可能滞后于实际的写入操作)。ErrorDataReceived
。将数据写入标准错误时引发。我倾向于将标准输出和标准错误重定向到同一流,并确保该流没有缓冲。相当于cmd.exe
咒语
some-command 2>&1
将stdout和stderr重定向到同一文件句柄。
事实证明,此操作不起作用的原因是由于Application Compatibility - Session 0 Isolation。本质上,该服务按预期启动了该过程,但由于它是在会话0内启动的,因此对用户隐藏了,因此用户无法与其进行交互。
为了解决这个限制,我能够遵循PeroMatić编写的指南Subverting Vista UAC in Both 32 and 64 bit Architectures。这份简短的指南使我能够从当前登录的用户会话内而不是会话0内的服务中生成进程。可悲的是,我不再具有用来使它作为我正在使用的项目工作的完整代码。它已被取消。