自动关机&初试多线程(6月28日)

感觉要搞个定时关机的小软件方便点,比如说晚上要开着下BT,电驴什么的,有时候可以预测一两个小时候就可以下好,所以不想机器整晚开着。但是它本身不提供这个功能,于是今天抽了一下午和晚上的时间才给弄了出来,我晕(本以为一两小时就可以搞定的)。

原因是这样的,本来打算用设置定时器SetTimer来不断的和系统时间比较,如果系统时间超过了我设定的时间就让它执行关机的代码。但是我忽然想起来以前看《windows 核心编程》的时候提到过一个函数:SetWaitableTimer,这个函数可以当其设定的时间(当然是在其参数里面设置,第二个参数)到了后就执行其第四个参数所设定的回调函数。

  • 提到回调函数要记住一点,回调函数的参数一般都是固定的,不要修改。比如说这里的回调函数PCshutdown(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue),当然,函数名是可以随意取的,我用的这个回调函数的原型是MSDN里面的TimerAPCProc。还有比如说创建线程的_beginthreadex,我设定的回调函数是waitableThreadFunc(void* pArguments),当然其参数是在MSDN里面就规定好了的,这可以看_beginthreadex的相关参数即可。

但是既然已经这么想了,我就想试试用这个函数,练练手,反正那个SetTimer用的很熟了。现在想起来,其实还是SetTimer简单点,因为毕竟不需要用多线程。不过也好,给了我一个机会去自己动手写第一个多线程函数,而且并不复杂,适合我这样的多线程编程初学者。下面具体的来说说这个程序。

于我而言,这里的难点有一个,就是关机的关键代码是什么,这个很简单,网上一搜一大把的。但是做到后来发现用我的这个SetWaitableTimer还有第二个难点,就是多线程问题。从来没有自己写过,接触过一点,感觉比较容易出错,所以对这个东东有点后怕。

1. 关机的关键代码

其实真正其关机的就是一个函数:ExitWindowsEx(EWX_SHUTDOWN|EWX_POWEROFF,0);但是我们看到了,去查MSDN,会发现EWX_SHUTDOWN要求进程有SE_SHUTDOWN_NAME权限。所以如何取得这个权限是个问题。关键代码如下所示:

 

其步骤是清晰的:先获取访问令牌--再查询并复制到结构体TOKEN_PRIVILEGES tkp中--修改该结构体---重新使访问令牌权限生效。但是依然不是很清晰的是该结构体的具体含义是什么(希望有达人来指教和讨论),现在只能从网络上找到点具体例子和不完整的介绍贴到这里,如下:

 typedef   struct   _TOKEN_PRIVILEGES   {    
            DWORD   PrivilegeCount;    
            LUID_AND_ATTRIBUTES   Privileges[];    
  }   TOKEN_PRIVILEGES,   *PTOKEN_PRIVILEGES;    
  PrivilegeCount
指的数组原素的个数,接着是一个LUID_AND_ATTRIBUTES类型的数组,再来看一下LUID_AND_ATTRIBUTES这个结构的内容,声明如下:  
   
  typedef   struct   _LUID_AND_ATTRIBUTES   {    
            LUID       Luid;    
            DWORD     Attributes;    
  }   LUID_AND_ATTRIBUTES,   *PLUID_AND_ATTRIBUTES  

   
  第二个参数就指明了我们要进行的操作类型,有三个可选项:   SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、SE_PRIVILEGE_USED_FOR_ACCESS。要使能一个权限就指定Attributes为SE_PRIVILEGE_ENABLED

2.多线程的原因

  hTimer=CreateWaitableTimer(NULL,FALSE,NULL);
  SetWaitableTimer(hTimer,&liUTC,0,PCshutdown,NULL,FALSE);
  SleepEx(INFINITE,TRUE);
//第二个参数一定要设为TRUE,否则只有设定的时间值到了后函数才会返回,而这里设置的是无限

看一下这个代码,你会发现,当我执行完第二句后,接着执行第三句,即创建该等待计时器内核对象的线程被挂起,这意味着一旦用户设定好时间并按下确认要关机的按钮后该对话框就无法再用了。因为这里创建该线程和创建该主窗口是同一个,即主线程。所以就需要把以上的代码放到另外一个线程里面去执行,这样当执行 SleepEx,线程就挂起来,但是我程序界面主窗口还是可以正常响应的。

3.多线程的流程

创建线程,使用_beginthreadex,一般在C++里面就用这个函数,当然也可以用_beginthread,和MFC中的AfxBeginThread

结束线程,使用_endthreadex。这里这些相关函数的参数使用依然不是很清楚,只是仿照MSDN里面的例子使用,相信还要经过好多次的练习才行。

 

最后再说下遇到的问题,首先是如果不用多线程那么就会出现点击按钮后,程序就挂起来了,界面上的任何一个东西都无法响应;其次遇到错误提示“非法的本地函数”,这是由于少些了大括号的原因(一般这个错误都是这个原因);最后,那个多线程的地方为什么要把返回值作为HANDLE类型然后再close掉,原因不是很清楚,不是已经在其回调函数中已经调用_endthreadex(0);了吗?具体的以后想明白了再回来修改

HANDLE hThread=(HANDLE)_beginthreadex(NULL,0,&waitableThreadFunc,NULL,0,&threadID);CloseHandle(hThread);

好了,今天就这样吧。(更加具体的代码见E:/c++/Projects/AutoShutDown)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值