如何从系统服务启动屏幕保护程序

如何从系统服务启动屏幕保护程序,第1张

概述如何从系统服务启动屏幕保护程序

我有几个变种启动屏幕保护程序。 我最喜欢的是

[Dllimport("user32.dll",SetLastError = false)] private static extern IntPtr GetDesktopWindow(); [Dllimport("user32.dll",CharSet = CharSet.auto)] private static extern IntPtr SendMessage(IntPtr hWnd,UInt32 Msg,IntPtr wParam,IntPtr lParam); private voID startScreensaver() { UInt32 WM_SYSCOMMAND = 0x112; IntPtr SC_SCREENSAVE = new IntPtr(0xf140); IntPtr hWnd = GetDesktopWindow(); SendMessage(hWnd,WM_SYSCOMMAND,SC_SCREENSAVE,new IntPtr(0)); }

我的问题是,我想从系统服务启动屏幕保护程序。 如果我例如想要在会话locking后立即启动屏幕保护程序(只是为了certificate概念),我可以尝试

protected overrIDe voID OnSessionChange(SessionChangeDescription changeDescription) { base.OnSessionChange(changeDescription); if (changeDescription.Reason == SessionChangeReason.SessionLock) startScreensaver(); }

这不起作用,我认为原因是该服务与安装

ServiceProcessInstaller.Account = ServiceAccount.LocalSystem;

自动填充域用户

liNQ to sql – FROM X WHERE X =“1”SELECT Y

GUI故障:checkBox文本在windows 8中显示不完整

沙盒AppDomain中的线程安全性

孤立的存储误解

无法访问用户的会话。 我可以实现一个小程序,在用户会话中运行,由服务触发屏幕保护程序触发…但这不是一个好方法。

有什么build议么? 谢谢。

编辑:显然这个问题是关系到GetDesktopWindow(); 电话,但我不知道如何解决这个问题

更新:

根据Erics的build议,我现在迭代所有窗口站(使用Openwindowstation),然后为所有这些迭代所有桌面(使用EnumDesktops)。 然后,我使用OpenDesktop打开桌面,并将句柄存储到桌面。 我的标准windows安装产生到以下的windowstation列表:桌面:dskHandle

WinSta0:默认值:732

WinSta0:断开:760

WinSta0:Winlogon中:784

msswindowstation:mssrestricteddesk:0

我现在开始一个新的线程,其中我

[Dllimport("user32.dll",SetLastError = true)] static extern bool SetThreadDesktop(IntPtr hDesktop);

然后调用上面的startScreensaver()方法。 IntPtr hWnd = GetDesktopWindow()确实返回合理的结果,但屏幕保护程序没有启动。 在里面

[Dllimport("user32.dll")] static extern IntPtr OpenDesktop(string lpszDesktop,uint DWFlags,bool finherit,uint DWDesiredAccess);

我使用GENERIC_ALL = 0x10000000作为DWDesiredAccess。 正如Farzin所说,我查了一下

允许服务与桌面进行交互

我不是一个win32或pInvoke亲,所以我现在完全失去了。 可以解释一下所有的东西如何协同工作? 有没有更好的build议? 我想要做的就是从系统服务调用屏幕保护程序。

CoreAudio OnVolumeNotification事件订阅会导致explorer.exe中的cpu使用率过高

有没有办法检查用户是否目前闲置?

使用.NET监视windows 7中的声卡输出

.net windows服务作为状态服务器

windows WCF客户端与Internet代理服务器显示错误服务器提交协议违规。 第= ResponseStatusline

好。 我用希望帮助的链接格式化了这个帖子,然后当点击Post时得到了这个:

哎呀! 您的答案无法提交,因为:•我们很抱歉,但作为垃圾邮件防范机制,新用户最多只能发布两个超链接。 获得超过10个声望发布更多的超链接。

所以,在这里你去,完全不可读的发布….

去超链接的这个消息: http : //social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/89485c95-61e5-46ea-84c7-5d8e03081c61

Erik,Farzin Zaker和OP,不要使用SERVICE_INteraCTIVE_PROCESS标志,也不要依赖交互式服务技术。 自windows Vista以来,这种方法已经被淘汰。 [更多]:

从微软自己的话来说:

重要服务从windows Vista开始,不能直接与用户交互。 因此,标题为“使用交互式服务”一节中提到的技术不应在新代码中使用。

所以,即使上面提到的任何方法都起作用,它们也不会成为任何“黑客”,并且可能会停止在任何新版本甚至更新windows中工作。

你最好的选择就是通过你自己提到的“ 我可以实现一个运行在用户会话中的小程序,这个程序由服务触发屏幕保护程序 ”。

相信我,我花了无数个小时试图做你想做的( 错误的方式 ),我失败了。 以下是Microsoft如何在软件中自行完成这项工作,以及您需要如何执行此 *** 作:

在你的系统服务中创建一个全局命名的自动重置事件,将其状态设置为非sginaled。 确保调整此事件的安全描述符,使其被“Everyone”读取和同步。 更多[这里]和[这里]和[这里]创建一个安全描述符。 如果您稍后不想处理ERROR_ACCESS_DENIED,则此步骤非常重要。

制作一个具有隐藏窗口的小型Win32 GUI程序。 在开始时,它将打开由上述服务创建的全局事件。 如果我用C ++写它,它会看起来像这样:OpenEvent(READ_CONTRol | SYNCHRONIZE,FALSE,_T(“Global \ Whatever_name_you_use”)); 然后创建一个工作线程,只需等待这个事件通过[同步函数]中的一个WaitFor * Object API发送信号。 当然,确保工作线程处理这个小的GUI程序关闭时的情况。

全局命名自动重置事件变为信号时,从工作线程运行以下代码。 通过wParam = SC_SCREENSAVE和lParam = 0将WM_SYSCOMMAND通知发送到主GUI线程中的窗口,或者通过从主GUI线程调用DefWindowProc()API来完成。 这应该启动GUI程序正在运行的用户的当前设置的屏幕保护程序。

如果你想开始一个特定的屏幕保护程序,那么你可以简单地使用ShellExecute和你的GUI程序中的/ s参数来运行它。 (当然,在全局命名的自动重置事件发出时,从工作线程完成。)所有的屏保通常放置在“%WINDIR% System32”文件夹中。 他们有.scr扩展名。

好的,现在如何从系统服务中激活它。

当您需要运行屏幕保护程序时,您需要确保您的小型GUI程序正在当前活动的用户会话中运行。 活跃的部分是重要的。 这里有两个应用程序。 第一。 每当用户会话变为活动状态时(通过关闭此GUI程序的副本来停止处于活动状态的活动),您可以执行此 *** 作,可以通过通过全局命名事件发出命令来关闭它,并且可以跟踪用户会话将通过捕获SERVICE_CONTRol_SESSIONCHANGE通知从系统服务和ServiceHandlerEx()中更改。)当需要激活屏幕保护程序并立即关闭时,也可以正确运行此GUI程序。 我会把它留给你选择哪种方法。 主要的一点是,你必须以某种方式在一个活动的用户会话中运行你的GUI程序,并使用全局命名的事件来与之通信。 (对于cource来说,你可以包含IPC的其他方式)在我的书中,全局事件最简单的表达布尔型或“是”和“否”类型的命令。)我需要立即告诉你,在另一个用户会话中的进程是这里最劳动密集的部分,文档记录不足,难以调试。 简而言之,您需要使用系统服务中的CreateProcessAsUser()API,但是困难的部分是准备调用该API。 不幸的是,关于如何调用它并没有明确的共识,网络上有一大堆的建议可能会有所不同。 为我工作的步骤如下:

把你的图形用户界面程序放到一个可以访问的地方(即使是最不具有特权的用户)。 由于它是系统服务的一部分,因此您可以使用“%WINDIR% System32”,但确保在不再需要时将其从中删除!

通过调用WTSEnumerateSessions()来获取当前的活动会话并查看WTSActive状态的会话。

WTSqueryUserToken()获取活动的用户会话令牌

DuplicatetokenEx(,MAXIMUM_ALLOWED,NulL,SecurityIDentification,TokenPrimary,&);

通过调用CreateEnvironmentBlock()创建环境字符串块

通过调用LoadUserProfile()来加载用户配置文件。 您可以使用以下API收集所有必要的信息:配置文件路径的NetUserGetInfo()和获取会话用户名的WTSquerySessioninformation(WTS_CURRENT_SERVER_HANDLE,WTSUsername,&,&)。

并通过调用ImpersonateLoggedOnUser()模拟该用户

此时,在您放置GUI程序的位置调用CreateProcessAsUser()。 让我再说一遍,你必须从你刚刚模拟的用户可访问的位置运行它! 这里常见的错误是从一个像这样的位置运行它:“ C: Users SomeUsername AppData Roaming ”。 这个调用可能看起来像这样:CreateProcessAsUser(hToken2,NulL,pNonConstOrStaticBufferWithPathToGUIProgram,NulL,NulL,FALSE,norMAL_PRIORITY_CLASS | CREATE_NEW_CONSolE | CREATE_UNICODE_ENVIRONMENT,pEnvironmentBlock,NulL,&pSTARTUPINFO,&pPROCESS_informatION);

总是回复imporsonation:RevertToSelf();

WaitForinputIDle()确保您的GUI进程已经启动并到达消息泵。

通过调用UnloadUserProfile(),DestroyEnvironmentBlock(),WTSFreeMemory(),CloseHandle()等进行清理。

现在你可以通过调用SetEvent()来设置你的全局命名自动重置事件来通知你的GUI进程来启动屏幕保护程序。 你完成了! 您可能还希望从GUI程序启用某种反向的反馈,以确保屏幕保护程序实际上已启动,但是我将保留给您。 请再次参考IPC的[手段]了解如何做到这一点。

作为一个结论,让我说,上述方法是通过无数的论坛发帖和搜集多个网页搜集来收集的。 而且,是的,我明白这个方法有多笨重和笨重,但是,嘿,这就是windows,不是这样:)如果你想简单的话,去OS X或iOS。 那是我最终做的…

干杯。

PS。 世界上谁在这个论坛上的格式规则? 这是最难的东西打入,并获得可读性….

去你的服务,右键点击服务,然后在logon选项卡中设置下面的项目为true:

允许服务与桌面进行交互

如果你想在安装上做到这一点:

public windowsServiceInstaller() { // This call is required by the Designer. InitializeComponent(); ServiceInstaller si = new ServiceInstaller(); si.Servicename = "windowsService1"; si.displayname = "windowsService1"; si.StartType = ServiceStartMode.Manual; this.Installers.Add(si); ServiceProcessInstaller spi = new ServiceProcessInstaller(); spi.Account = System.ServiceProcess.ServiceAccount.LocalSystem; spi.Password = null; spi.Username = null; this.Installers.Add(spi); // Here is where we set the bit on the value in the registry. // Grab the subkey to our service RegistryKey ckey = Registry.LocalMachine.OpenSubKey( @"SYstemCurrentControlSetServiceswindowsService1",true); // Good to always do error checking! if(ckey != null) { // Ok Now lets make sure the "Type" value is there,//and then do our bitwise operation on it. if(ckey.GetValue("Type") != null) { ckey.SetValue("Type",((int)ckey.GetValue("Type") | 256)); } } }

参考: http : //www.codeproject.com/KB/install/cswindowsservicedesktop.aspx

在安装时,可以使服务与桌面交互(将CreateService SERVICE_INteraCTIVE_PROCESS传递给CreateService )。 否则(可能有访问问题 – 我没有尝试过),你需要从Window Station和桌面功能开始 。

你需要做的是找到登录用户窗口站( Enumwindowstations , Openwindowstation ),桌面( EnumDesktops , OpenDesktop ),创建一个线程和SetThreadDesktop ,然后最终使用GetDesktopWindow 。

总结

以上是内存溢出为你收集整理的如何从系统服务启动屏幕保护程序全部内容,希望文章能够帮你解决如何从系统服务启动屏幕保护程序所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1280445.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存