无法从 Windows 7 上的 Windows 服务启动桌面应用程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3838418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot start desktop application from Windows service on Windows 7
提问by Jovan
HI,
你好,
I have C# WCF windows service on Windows 7 logged on as user with admin rights. I am trying to start desktop application after service start. All discussions I found are about windows stations and desktops... I created a separate thread, set thread station and desktop and tried to start desktop application. Code works when I start it from VS2010 using asp.net development server but if it was started from service there are no errors but process was not started. I've tried to start process as different user and tried call of CreateProcessWithLogonW (with setting startInfo.lpDesktop to "winsta0\default"; previously). In both cases I have processId returned but cannot see desktop application. Can somebody help me to see where is a mistake?
我在 Windows 7 上有 C# WCF windows 服务,以具有管理员权限的用户身份登录。我正在尝试在服务启动后启动桌面应用程序。我发现的所有讨论都是关于 windows 站和桌面...我创建了一个单独的线程,设置线程站和桌面并尝试启动桌面应用程序。当我使用 asp.net 开发服务器从 VS2010 启动它时,代码可以工作,但如果它是从服务启动的,则没有错误,但进程未启动。我尝试以不同的用户身份启动进程并尝试调用 CreateProcessWithLogonW(之前将 startInfo.lpDesktop 设置为“winsta0\default”)。在这两种情况下,我都返回了 processId,但看不到桌面应用程序。有人可以帮我看看哪里有错误吗?
public class ExternalProcess
{
const int READ_CONTROL = 0x20000;
const int WRITE_DAC = 0x40000;
const int DESKTOP_WRITEOBJECTS = 0x80;
const int DESKTOP_READOBJECTS = 0x1;
private Process extProcess;
private string sFilePath = "";
[DllImport("user32.dll")]
private static extern bool SetThreadDesktop(IntPtr hDesktop);
[DllImport("user32.dll")]
static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags,bool fInherit, uint dwDesiredAccess);
[DllImport("user32.dll")]
private static extern IntPtr GetProcessWindowStation();
[DllImport("user32.dll")]
private static extern IntPtr OpenWindowStation(string lpszWinSta, bool fInherit, ACCESS_MASK dwDesiredAccess);
[DllImport("user32.dll")]
private static extern IntPtr SetProcessWindowStation(IntPtr hWinsta);
public bool StartProcess(string filePath)
{
sFilePath = filePath;
Thread t = new Thread(new ThreadStart(Thread_StartProcess));
t.Start();
return true;
}
private void Thread_StartProcess()
{
IntPtr hwinstaSave;
IntPtr hwinsta, hwinsta2;
IntPtr hdesk;
hwinstaSave = GetProcessWindowStation();
System.Console.WriteLine("GetProcessWindowStation Lasterror= " + Marshal.GetLastWin32Error().ToString());
System.Console.WriteLine("GetProcessWindowStation hwinstaSave= " + hwinstaSave.ToString());
//hwinsta = OpenWindowStation("winsta0", false, ACCESS_MASK.GENERIC_EXECUTE | ACCESS_MASK.DESKTOP_CREATEWINDOW | ACCESS_MASK.DESKTOP_CREATEMENU | ACCESS_MASK.DESKTOP_SWITCHDESKTOP | ACCESS_MASK.DESKTOP_WRITEOBJECTS);
hwinsta = OpenWindowStation("winsta0", false, ACCESS_MASK.WINSTA_ALL_ACCESS); // when call from windows service OpenWindowStation returns 0
System.Console.WriteLine("OpenWindowStation lasterror = " + Marshal.GetLastWin32Error().ToString());
System.Console.WriteLine("OpenWindowStation hwinsta= " + hwinsta.ToString());
hwinsta2 = SetProcessWindowStation(hwinsta);
System.Console.WriteLine("SetProcessWindowStation lasterror = " + Marshal.GetLastWin32Error().ToString());
System.Console.WriteLine("SetProcessWindowStation hwinsta2= " + hwinsta2.ToString());
hdesk = OpenDesktop("default", 0, true, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS);
System.Console.WriteLine("OpenDesktop lasterror = " + Marshal.GetLastWin32Error().ToString());
System.Console.WriteLine("OpenDesktop hdesk= " + hdesk.ToString());
bool Success = SetThreadDesktop(hdesk);
System.Console.WriteLine("SetThreadDesktop lasterror = " + Marshal.GetLastWin32Error().ToString());
System.Console.WriteLine("SetThreadDesktop Success= " + Success.ToString());
try
{
extProcess = new Process();
extProcess.StartInfo.FileName = sFilePath;
extProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
if (extProcess.Start())
System.Console.WriteLine("Process started ");
else
System.Console.WriteLine("Not started!");
}
catch (Win32Exception e)
{
System.Console.WriteLine("Start {0} failed. Error: " + e.Message);
}
}
}
回答by CoreTech
Interactive Windows Services received a security-centric makeover in Windows Vista. Services now run in the isolated "Session 0" and can not easily inject windows into interactive user sessions. Your code above will create GUI elements in Session 0, which are not shown on any user's desktop, even with the "Allow service to interact with desktop" checked.
交互式 Windows 服务在 Windows Vista 中获得了以安全为中心的改造。服务现在在隔离的“会话 0”中运行,并且无法轻松地将窗口注入交互式用户会话。您上面的代码将在会话 0 中创建 GUI 元素,这些元素不会显示在任何用户的桌面上,即使选中了“允许服务与桌面交互”。
More details on the Windows Services restrictions are in this technical document from Microsoft.
有关 Windows 服务限制的更多详细信息,请参阅Microsoft 的这份技术文档。
回答by Mario The Spoon
Perhapse this helps: http://msdn.microsoft.com/en-us/library/ms683502%28VS.85%29.aspx
也许这有帮助:http: //msdn.microsoft.com/en-us/library/ms683502%28VS.85%29.aspx
hth
第
Mario
马里奥
回答by Asim Shaikh
The application opens up in different session since windows Vista. Hence you do not see the application open and you are unable to communicate to the application. This may help
自 Windows Vista 以来,该应用程序在不同的会话中打开。因此,您看不到应用程序打开,也无法与应用程序通信。这可能有帮助
Possible to launch a process in a user's session from a service?
Asim
阿西姆
回答by Jon Clegg
I'm in the middle of this right now, I know UltraVNC does this so I would look at the code. I'm not 100% sure of the answer at this moment, when I figure it out i'll update this post.
我现在正处于中间状态,我知道 UltraVNC 会这样做,所以我会查看代码。我现在不是 100% 确定答案,当我弄清楚时,我会更新这篇文章。
The gist is that you do a CreateProcessAsUser, the process then might have to do OpenInputDesktop then a SetThreadDesktop, but like I can't get it to work yet.
要点是您执行 CreateProcessAsUser,然后该进程可能必须执行 OpenInputDesktop,然后执行 SetThreadDesktop,但就像我无法让它工作一样。