vc 实现关机 重启 注销

vc 实现关机 重启 注销

void shutdown()
{

HANDLE   hToken;  
 TOKEN_PRIVILEGES   tkp;  
 //定义变量  
 OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken);  
 //OpenProcessToken()这个函数的作用是打开一个进程的访问令牌  
 //GetCurrentProcess()函数的作用是得到本进程的句柄  
 LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);  
 //LookupPrivilegeValue()的作用是修改进程的权限  
 tkp.PrivilegeCount =  1;    
 //赋给本进程特权  
 tkp.Privileges[0].Attributes   =   SE_PRIVILEGE_ENABLED;  
 AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);  
 //AdjustTokenPrivileges()的作用是通知Windows   NT修改本进程的权利  
   
 ExitWindowsEx(EWX_POWEROFF|EWX_FORCE,0); 
 //EWX_LOGOFF,EWX_REBOOT,EWX_SHUTDOWN

}

 

 

  可以调用ExitWindowsEx函数实现关机、重启功能,调用SetSystemPowerState API实现休眠功能。
    ExitWindowsEx函数可以注销当前用户、关闭系统和重启系统。函数原型如下:

    BOOL ExitWindowsEx(
         UINT uFlags, //shutdown operation
         DWORD dwReserved //reserved
    );
  
    第一个参数uFlags必须是下面四个值中的一个:
         EWX_LOGOFF   - 注销当前用户
         EWX_POWEROFF - 关机并关掉电源,winNT/2000 or later:调用进程必须有SE_SHUTDOWN_NAME权限。
         EWX_REBOOT   - 关机并重启,要求同上
         EWX_SHUTDOWN - 关闭系统到一个点,在这个点上关闭电源是安全的。所有的缓存数据被写入磁盘,所有的进程被停止。
                        如果系统支持关闭电源的特点,则电源也同时关闭。要求同上。


    第二个参数dwReserverd: [in] Reserved; this parameter is ignored
         EWX_FORCE       - 强制进程终止,此标志设上后系统可能丢失数据。
         EWX_FORCEIFHUNG - Windows 2000 or later: Forces processes to terminate if they do not respond to the
                           WM_QUERYENDSESSION or WM_ENDSESSION message. This flag is ignored if EWX_FORCE is used.
    备注:
    Windows 2000 or later: If the EWX_FORCEIFHUNG value is specified, the system forces hung applications to close
    and does not display the dialog box. To shut down or restart the system, the calling process must use the
    AdjustTokenPrivileges function to enable the SE_SHUTDOWN_NAME privilege. For more information about security
    privileges, see Privileges 

 

[转载]GetCurrentProcessID、OpenProcessToken、LookupPrivilegeValue、AdjustTokenPrivileges
2007-04-09 10:05

GetCurrentProcessID            得到当前进程的ID   
OpenProcessToken          得到进程的令牌句柄
LookupPrivilegeValue          查询进程的权限
AdjustTokenPrivileges          判断令牌权限  

            要对一个任意进程(包括系统安全进程和服务进程)进行指定了写相关的访问权的OpenProcess操作,只要当前进程具有SeDeDebug权限就可以了。要是一个用户是Administrator或是被给予了相应的权限,就可以具有该权限。可是,就算我们用Administrator帐号对一个系统安全进程执行OpenProcess(PROCESS_ALL_ACCESS,FALSE,          dwProcessID)还是会遇到“访问拒绝”的错误。什么原因呢?原来在默认的情况下进程的一些访问权限是没有被使能(Enabled)的,所以我们要做的首先是使能这些权限。与此相关的一些API函数有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges。我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到,函数的原型如下:

BOOL      OpenProcessToken(
           HANDLE      ProcessHandle,       //要修改访问权限的进程句柄
           DWORD      DesiredAccess,        //指定你要进行的操作类型
           PHANDLE      TokenHandle         //返回的访问令牌指针
     );

            第一参数是要修改访问权限的进程句柄;第三个参数就是返回的访问令牌指针;第二个参数指定你要进行的操作类型,如要修改令牌我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES(其它一些参数可参考Platform          SDK)。通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。接着我们可以调用AdjustTokenPrivileges对这个访问令牌进行修改。AdjustTokenPrivileges的原型如下:

BOOL AdjustTokenPrivileges(
      HANDLE TokenHandle,                        // 访问令牌的句柄
      BOOL DisableAllPrivileges,                  // 决定是进行权限修改还是除能(Disable)所有权限
      PTOKEN_PRIVILEGES NewState,        // 指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构
                                                                     的指针,该结构包含一个数组,数据组的每个项指明了权限
                                                                     的类型和要进行的操作;
      DWORD BufferLength,                         //结构PreviousState的长度,如果PreviousState为空,该参数
                                                                       应为NULL
      PTOKEN_PRIVILEGES PreviousState,  // 指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问
                                                                      权限的信息
      PDWORD ReturnLength                      //实际PreviousState结构返回的大小
);

            第一个参数是访问令牌的句柄;第二个参数决定是进行权限修改还是除能(Disable)所有权限;第三个参数指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数据组的每个项指明了权限的类型和要进行的操作;          第四个参数是结构PreviousState的长度,如果PreviousState为空,该参数应为NULL;第五个参数也是一个指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息,可空;最后一个参数为实际PreviousState结构返回的大小。在使用这个函数前再看一下TOKEN_PRIVILEGES这个结构,其声明如下:

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。第一个参数就是指权限的类型,是一个LUID的值,LUID就是指locally          unique          identifier,我想GUID大家是比较熟悉的,和GUID的要求保证全局唯一不同,LUID只要保证局部唯一,就是指在系统的每一次运行期间保证是唯一的就可以了。另外和GUID相同的一点,LUID也是一个64位的值,相信大家都看过GUID那一大串的值,我们要怎么样才能知道一个权限对应的LUID值是多少呢?这就要用到另外一个API函数LookupPrivilegevalue,其原形如下:

BOOL LookupPrivilegeValue(
      LPCTSTR lpSystemName,     //系统的名称,若为空,则在当前的sysytem查找。
      LPCTSTR lpName,                // 指明了权限的名称,如“SeDebugPrivilege”。
      PLUID lpLuid                          // 返回LUID的指针
);

            第一个参数是系统的名称,如果是本地系统只要指明为NULL就可以了,第三个参数就是返回LUID的指针,第二个参数就是指明了权限的名称,如“SeDebugPrivilege”。在Winnt.h中还定义了一些权限名称的宏,如:

#define          SE_BACKUP_NAME                        TEXT("SeBackupPrivilege")
#define          SE_RESTORE_NAME                     TEXT("SeRestorePrivilege")
#define          SE_SHUTDOWN_NAME                  TEXT("SeShutdownPrivilege")
#define          SE_DEBUG_NAME                          TEXT("SeDebugPrivilege")

这样通过这三个函数的调用,我们就可以用OpenProcess(PROCESS_ALL_ACCESS,FALSE,          dwProcessID)来打获得任意进程的句柄,并且指定了所有的访问权。

阅读更多
个人分类: MFC
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭