在锁定系统上渲染 3D 场景
我使用 SlimDX 用 c# 编写了一个基于 Direct3D 9 的渲染引擎。在一个新项目中,我现在需要使用 Web 服务分发已加载的 3D 场景的图片。问题是为了渲染任何东西,我需要一个 Direct3d 设备。有没有办法在用户不登录系统且桌面不被锁定的情况下创建direct3d设备?
如果这不可能,有人知道解决方法吗?最后,我需要一个可以使用某些本地用户帐户从任务规划器运行的可执行文件或一个服务,该服务定期从某些角度渲染场景的图片。
引擎分为两部分:引擎本身和渲染器。因此,如果没有其他方法,那么我还可以使用 opengl 或任何其他允许在没有可见表单的情况下进行渲染的技术来实现新的渲染器。
编辑:
到目前为止我所拥有的是:
protected override void OnContinue() {
base.OnContinue();
NativeFunctions.SafeWindowStationHandle hwinsta = NativeFunctions.WindowStation.OpenWindowStation(
"WinSta0",
true,
NativeFunctions.AccessMask.WINSTA_ALL_ACCESS);
if(hwinsta == null || hwinsta.IsClosed || hwinsta.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
if(NativeFunctions.WindowStation.SetProcessWindowStation(hwinsta.DangerousGetHandle())) {
NativeFunctions.SafeDesktopHandle ptrDesktop = NativeFunctions.WindowStation.OpenInputDesktop(
0,
true,
NativeFunctions.AccessMask.DESKTOP_CREATEWINDOW);
if(ptrDesktop.IsClosed || ptrDesktop.IsInvalid)
return;
if(!NativeFunctions.WindowStation.SetThreadDesktop(ptrDesktop.DangerousGetHandle()))
return;
Log log = Logger.Instance.CreateLog("DXService", true, true, false);
log.LogMessage("Desktop set, creating D3D-Object.", LOGMESSAGELEVEL.CRITICAL, true);
Direct3D direct3D = new Direct3D();
log.LogMessage("Direct3D object created, creating device.", LOGMESSAGELEVEL.CRITICAL, true);
if(direct3D.AdapterCount == 0) {
log.LogMessage("FATAL: direct3D.AdapterCount == 0");
}
}
}
这是最小 WindowsService 的一部分。我将重要的代码放入 OnContinue 函数中,因为它比启动代码更容易调试。我授予此服务与活动桌面交互的权利。当我作为本地系统帐户运行服务时,桌面和窗口站可以工作,但 GraphicsAdapter 的数量仍然为 0,当我使用专用用户帐户运行服务时,我什至无法打开 WindowStation。还有什么我可以尝试的或者我做错了什么吗?我正在 Windows 7 计算机上进行测试,同时我已登录,否则调试会变得非常困难。这可能是个问题吗?
谢谢
I have written a Direct3D 9 based rendering engine in c# using SlimDX. In a new project I now need to distribute pictures of a loaded 3d scene using a webservice. The problem is that in order to render anything at all I need a Direct3d device. Is there any way to create a direct3d device without a user being logged in to the system and the desktop not being locked?
If that is not possible, does anyone know of a workaround? In the end I need either an executable which can be run from the task planner using some local user account or a service, which periodically renders pictures of the scene from certain viewpoints.
The engine is split into two parts: the engine itself and the renderer. So if there's no other way then I could also implement a new renderer using opengl or any other technology which allows for rendering without having a visible form.
Edit:
What I have so far is this:
protected override void OnContinue() {
base.OnContinue();
NativeFunctions.SafeWindowStationHandle hwinsta = NativeFunctions.WindowStation.OpenWindowStation(
"WinSta0",
true,
NativeFunctions.AccessMask.WINSTA_ALL_ACCESS);
if(hwinsta == null || hwinsta.IsClosed || hwinsta.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
if(NativeFunctions.WindowStation.SetProcessWindowStation(hwinsta.DangerousGetHandle())) {
NativeFunctions.SafeDesktopHandle ptrDesktop = NativeFunctions.WindowStation.OpenInputDesktop(
0,
true,
NativeFunctions.AccessMask.DESKTOP_CREATEWINDOW);
if(ptrDesktop.IsClosed || ptrDesktop.IsInvalid)
return;
if(!NativeFunctions.WindowStation.SetThreadDesktop(ptrDesktop.DangerousGetHandle()))
return;
Log log = Logger.Instance.CreateLog("DXService", true, true, false);
log.LogMessage("Desktop set, creating D3D-Object.", LOGMESSAGELEVEL.CRITICAL, true);
Direct3D direct3D = new Direct3D();
log.LogMessage("Direct3D object created, creating device.", LOGMESSAGELEVEL.CRITICAL, true);
if(direct3D.AdapterCount == 0) {
log.LogMessage("FATAL: direct3D.AdapterCount == 0");
}
}
}
This is part of a minimal WindowsService. I put the important code into the OnContinue function because it's easier to debug than the startup code. I gave this services the right to interact with the active desktop. when I run the service as a local systemaccount getting the desktop and windowstation works but the number of GraphicsAdapters still is 0, when I run the service using a dedicated user account then I can't even open the WindowStation. Is there anything else I can try or which I'm doing wrong? I am testing this on a Windows 7 machine, while I am logged in since debugging becomes very difficult otherwise. Might this be a problem?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
早在 XP 时代,我就参与了一个项目,该项目成功地从一台机器上的服务调用 Direct3D 硬件渲染,而没有人登录控制台。我完全忘记了(巧妙的)细节,但它需要使用 “Window Station 和桌面功能”API 以某种方式获取可用的 HWND。不过,新的/服务器操作系统可能与所有新的安全内容完全不同。
如果 OpenGL 在这方面比 Direct3D 工作得更好,我会感到惊讶,尽管它可能值得一试。您可能会考虑的其他事项:
Back in the days of XP I worked on a project which successfully invoked Direct3D hardware rendering from a service on a machine with no-one logged into the console. I completely forget the (ingenious) details, but it required some use of the "Window Station and Desktop Functions" API to somehow get hold of a usable HWND. Newer/server OS are likely completely different anyway with all the new security stuff though.
I'd be surprised if OpenGL worked any better than Direct3D in this area, although it might be worth a try. Other things you might consider:
对于 OpenGL,使用 PBuffer 上下文甚至可以在锁定的桌面上获得 GPU 加速;然而,这很大程度上取决于驱动程序,它可能会将 PBuffer 设置为在锁定时永久损坏,所以 YMMV。我会尝试一下。
In the case of OpenGL using a PBuffer context might work to get GPU acceleration on even a locked desktop; however this strongly depends on the driver, which may set the PBuffer to permanently damaged while locked, so YMMV. I'd give it a shot.