当前位置: 首页 > 编程语言 > C#

让用户在C#中有空闲时间?分享

时间:2023-04-10 15:47:10 C#

让用户在C#中腾出时间?我找到了一个教程,介绍如何获取用户空闲时间的空闲时间。问题在于它仅在应用程序在用户上运行时才有效。我的应用程序在SYSTEM上运行。我怎样才能得到空闲时间?或者如果PC空闲?据我所知,您可以使用GetLastInputInfo函数的结果。因此,我提出以下建议。现在,假设您有可执行文件A在本地系统帐户下运行。创建可执行文件B,它将收集相关的系统信息(在GetLastInputInfo的帮助下)。接下来,使用此类使用CreateProcessAsUser函数和记录的用户令牌从可执行文件A运行可执行文件B(不幸的是,我找不到发布它的stackoverflow问题):usingSystem;使用系统诊断;使用系统.Runtime.InteropServices;namespaceHelpers{[StructLayout(LayoutKind.Sequential)]internalstructPROCESS_INFORMATION{publicIntPtrhProcess;公共IntPtrhThread;publicuintdwProcessId;publicuintdwThreadId;}[StructLayout(LayoutKind.Sequential)]internalstructSECURITY_ATTRIBUTES{publicuintnLength;公共IntPtrlpSecurityDescriptor;公共布尔bInheritHandle;}[StructLayout(LayoutKind.Sequential)]publicstructSTARTUPINFO{publicuintcb;公共字符串lpReserved;公共字符串lpDesktop;公共单位dwYSize;公共uintdwXCountChars;publicuintdwYCountChars;公共uintdwFillAttribute;公共单位dwFlags;公共短wShowWindow;公共短cbReserved2;吨;公共IntPtrhStdOutput;公共IntPtrhStdError;}内部枚举SECURITY_IMPERSONATION_LEVEL{SecurityAnonymous,SecurityIdentification,SecurityImpersonation,SecurityDelegation}内部枚举TOKEN_TYPE{TokenPrimary=1,TokenImpersonation}publicclassImpersonateProcessAsLoggedUser{privateconstshortSW_SHOW=5;私有结构TOKEN_QUERY=0x0008;私有结构TOKEN_DUPLICATE=0x0002;私有结构TOKEN_ASSIGN_PRIMARY=0x0001;私有常量intGENERIC_ALL_ACCESS=0x10000000;私有常量STARTF_USESHOWWINDOW=0x00000001;私有常量STARTF_FORCEONFEEDBACK=0x00000040;私有构造CREATE_UNICODE_ENVIRONMENT=0x00000400;[DllImport("advapi32.dll",SetLastError=true)]privatestaticexternboolCreateProcessAsUser(IntPtrhToken,stringlpApplicationName,stringlpCommandLine,refSECURITY_ATTRIBUTESlpProcessAttributes,refSECURITY_ATTRIBUTESlpThreadAttributes,boolbInheritHandles,uintdwCreationFlags,IntPtrlpEnvironment,stringlpCurrentDirectory,refSTARTUPINFOlpStartupInfo,outPROCESS_INFORMATIONlpProcessInformation);[DllImport("advapi32.dll",EntryPoint="DuplicateTokenEx",SetLastError=true)]privatestaticexternboolDuplicateTokenEx(IntPtrhExistingToken,uintdwDesiredAccess,refSECURITY_ATTRIBUTESlpThreadAttributes,Int32ImpersonationLevel,Int32dwTokenType,refIntPtrphNewToken);[DllImport("advapi32.dll",SetLastError=true)]privatestaticexternboolOpenProcessToken(IntPtrProcessHandle,UInt32DesiredAccess,refIntPtrTokenHandle);[DllImport("userenv.dll",SetLastError=true)]privatestaticexternboolCreateEnvironmentBlock(refIntPtrlpEnvironment,IntPtrhToken,boolbInherit);[DllImport("userenv.dll",SetLastError=true)]privatestaticexternboolDestroyEnvironmentBlock(IntPtrlpEnvironment);[DllImport("kernel32.dll",SetLastError=true)]privatestaticexternboolCloseHandle(IntPtrhObject);privatestaticboolLaunchProcessAsUser(stringcmdLine,IntPtrtoken,IntPtrenvBlock){boolresult=false;varpi=newPROCESS_INFORMATION();varsaProcess=newSECURITY_ATTRIBUTES();varsaThread=newSECURITY_ATTRIBUTES();saProcess.nLength=(uint)Marshal.SizeOf(saProcess);saThread.nLength=(uint)Marshal.SizeOf(saThread);varsi=newSTARTUPINFO();si.cb=(uint)Marshal.SizeOf(si);//如果该成员为NULL,新进程继承其父进程的桌面//窗口站。//如果该成员为空字符串,则进程不继承其父进程的桌面和//窗口站;相反,系统//确定是否需要创建新的桌面和窗口站。//如果模拟用户已有桌面,系统将使用//现有桌面。si.lpDesktop=@"WinSta0Default";//根据需要修改si.dwFlags=STARTF_USESHOWWINDOW|STARTF_FORCEONFEEDBACK;si.wShowWindow=SW_SHOW;//根据需要设置其他si属性。结果=CreateProcessAsUser(令牌,null,cmdLine,refsaProcess,refsaThread,false,CREATE_UNICODE_ENVIRONMENT,envBlock,null,refsi,outpi);如果(结果==false){interror=Marshal.GetLastWin32Error();stringmessage=String.Format("CreateProcessAsUser错误:{0}",error);Debug.WriteLine(消息);}返回结果;}privatestaticIntPtrGetPrimaryToken(intprocessId){IntPtrtoken=IntPtr.Zero;IntPtrprimaryToken=IntPtr.Zero;布尔retVal=假;进程p=null;尝试{p=Process.GetProcessById(processId);}catch(ArgumentException){stringdetails=String.Format("ProcessID{0}NotAvailable",processId);调试.WriteLine(细节);扔;}//获取模拟令牌retVal=OpenProcessToken(p.Handle,TOKEN_DUPLICATE,reftoken);if(retVal){varsa=newSECURITY_ATTRIBUTES();sa.nLength=(uint)Marshal.SizeOf(sa);//将模拟token转换为PrimarytokenretVal=DuplicateTokenEx(token,TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE|TOKEN_QUERY,refsa,(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,(int)TOKEN_TYPE.TokenPrimary,refprimaryToken);//关闭之前打开的Token。关闭句柄(令牌);if(retVal==false){stringmessage=String.Format("DuplicateTokenEx错误:{0}",Marshal.GetLastWin32Error());Debug.WriteLine(消息);}}else{stringmessage=String.Format("OpenProcessTokenError:{0}",Marshal.GetLastWin32Error());Debug.WriteLine(消息);}//我们将在使用后关闭此令牌。返回主令牌;}privatestaticIntPtrGetEnvironmentBlock(IntPtrtoken){IntPtrenvBlock=IntPtr.Zero;boolretVal=CreateEnvironmentBlock(refenvBlock,token,false);if(retVal==false){//环境块,比如我的文档的通用路径等。//如果为“false”则不会创建//它不应该不利地影响CreateProcessAsUser。字符串消息=String.Format("CreateEnvironmentBlock错误:{0}",Marshal.GetLastWin32Error());Debug.WriteLine(消息);}返回环境块;}publicstaticboolLaunch(stringappCmdLine/*,intprocessId*/){boolret=false;//要么显式指定进程ID//要么尝试从用户拥有的进程中获取它。//在这种情况下,假设只有一个explorer.exeProcess[]ps=Process.GetProcessesByName("explorer");intprocessId=-1;//=processIdif(ps.Length>0){processId=ps[0].Id;}if(processId>1){IntPtrtoken=GetPrimaryToken(processId);if(token!=IntPtr.Zero){IntPtrenvBlock=GetEnvironmentBlock(token);ret=LaunchProcessAsUser(appCmdLine,token,envBlock);如果(envBlock!=IntPtr.Zero)DestroyEnvironmentBlock(envBlock);关闭句柄(令牌);}}返回ret;接下来,您需要找到一种方法将收集到的信息从可执行文件B发送到可执行文件A。有很多方法可以做到这一点,其中之一是.NetRemoting。但是,您可以创建中间XML甚至文本文件。也许这不是解决您问题的最佳方法,但如果您需要更多本地系统记录用户交互,则可以遵循这种模式。我知道这个答案已经被接受,但我只是想补充一下,以防人们想在终端服务环境中做同样的事情。Cassia是一个开源库,它在Windows终端服务API上放置了一个.NET包装器。我已经将它用于我的服务器管理,并且效果很好。您可以通过调用ITerminalServicesSession.LastInputTime获取任何会话的空闲时间。推荐的方法是运行一个单独的应用程序,将用户会话数据传递给服务。您可以在用户会话开始时配置应用程序,方法是将它们添加到HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRun下的注册表中。您可以在以下知识库文章http://support.microsoft.com/kb/308403中阅读有关此方法的更多详细信息上面是C#学习教程:让用户在C#中有空闲时间?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:

最新推荐
猜你喜欢