惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
I
Intezer
T
Tenable Blog
S
Schneier on Security
Project Zero
Project Zero
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
小众软件
小众软件
Know Your Adversary
Know Your Adversary
博客园 - 司徒正美
The Cloudflare Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
News and Events Feed by Topic
博客园 - 叶小钗
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题
aimingoo的专栏
aimingoo的专栏
S
Secure Thoughts
Forbes - Security
Forbes - Security
T
The Exploit Database - CXSecurity.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 【当耐特】
罗磊的独立博客
IT之家
IT之家
H
Hacker News: Front Page
I
InfoQ
云风的 BLOG
云风的 BLOG
S
Security Affairs
M
MIT News - Artificial intelligence
GbyAI
GbyAI
Jina AI
Jina AI
Help Net Security
Help Net Security
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
L
Lohrmann on Cybersecurity
A
About on SuperTechFans
Attack and Defense Labs
Attack and Defense Labs
The Register - Security
The Register - Security
V
V2EX
G
Google Developers Blog
D
DataBreaches.Net
Apple Machine Learning Research
Apple Machine Learning Research
C
Cybersecurity and Infrastructure Security Agency CISA
J
Java Code Geeks
W
WeLiveSecurity
Cloudbric
Cloudbric
T
Tor Project blog

博客园 - eaglet

HubbleDotNet 的注册码生成器 文件名通配符匹配的代码 .net 下如何将文档文件(Word, Pdf等) 中的文本提取出来 NTCPMSG 开源高性能TCP消息发送组件 文件在不同文件系统间拷贝文件时间改变的问题 文件是否真的写入了磁盘? 如何自动延长 windows 2008 试用版的试用期 获取ALL USER 的特殊目录的类 i—比 i++ 快? 多线程环境下调用 HttpWebRequest 并发连接限制 HubbleDotNet+Mongodb 构建高性能搜索引擎--概述 HubbleDotNet 索引分词的测试方法和分词技巧 Windows 启动顺序详解 记录windows操作系统启动日志 C# 程序自动批量生成 google maps 的KML文件 通过 Windows 7 共享上网 正确理解 SqlConnection 的连接池机制 Windows 2008 server + IIS 7 设置身份模拟(ASP.NET impersonation) IIS 7.5 配置 FTP Passive 模式
C# 重启计算机的问题
eaglet · 2012-04-13 · via 博客园 - eaglet

C# 程序重启计算机的方法很多,网上也有不少这方面的文章,不过很多网上提供的方法在某些情况下无法获取重启计算机的权限导致重启失败。本文对这些方法做一些简单的讨论。

作者:eaglet

网上介绍最多的两种方法分别是:

System.Diagnostics.Process.Start("shutdown",@"/r");

    [DllImport("user32.dll")]
        static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

        [STAThread]
        static void Main(string[] args)
        {
            ExitWindowsEx(ExitWindows.LogOff, ShutdownReason.MajorOther & ShutdownReason.MinorOther);
            //这个语句将实现计算机注销操作   
         }

这两种方法在通常情况下工作是没有问题的,但在某些特殊情况下,比如桌面被其它用户锁定时就无法重启计算机。本人在实际工作中遇到过当当前屏幕被远程控制软件锁定后,我做的后台守护进程试图重启计算机,结果用上述两种方法都无法成功。分析原因,应该是远程控制软件用另外的帐号锁定了屏幕(通常应该是windows service 或者 network service),这时守护进程用当前帐号重启计算机就因为没有权限而失败。

要解决这个问题,我们必须要给进程赋予足够的权限才行,于是我在调用 ExitWindowsEx 前运行了如下代码来赋予当前进程关闭计算机权限

 
        //give current process SeShutdownPrivilege
        TokPriv1Luid tp;
 
        IntPtr hproc = GetCurrentProcess();
 
        IntPtr htok = IntPtr.Zero;
 
        if (!OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok))
        {
            throw new Exception("Open Process Token fail");
        }
 
        tp.Count = 1;
 
        tp.Luid = 0;
 
        tp.Attr = SE_PRIVILEGE_ENABLED;
 
        if (!LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid))
        {
            throw new Exception("Lookup Privilege Value fail");
        }
 
        if (!AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Exception("Adjust Token Privileges fail");
        }

上面代码为当前进程赋予了关闭计算机的权限。这里需要注意的是上述代码要执行成功同样需要足够的权限,通常当前进程需要以拥有至少是系统管理员权限的账户运行。如果没有足够权限,需要用程序模拟系统管理员权限,模拟其它帐号权限的问题不在本文讨论范围内。

加上如上代码后,在其他用户锁定机器后,重启计算机成功。

下面给出完整代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
 
public class ExitWindows
{
    #region win32 api
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
 
    private struct TokPriv1Luid
    {
 
        public int Count;
 
        public long Luid;
 
        public int Attr;
 
    }
 
    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern IntPtr GetCurrentProcess();
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
 
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
 
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
        ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
 
    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern bool ExitWindowsEx(int flg, int rea);
 
    #endregion
 
    private const int SE_PRIVILEGE_ENABLED = 0x00000002;
 
    private const int TOKEN_QUERY = 0x00000008;
 
    private const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
 
    private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
 
    #region Exit Windows Flags
    private const int EWX_LOGOFF = 0x00000000;
 
    private const int EWX_SHUTDOWN = 0x00000001;
 
    private const int EWX_REBOOT = 0x00000002;
 
    private const int EWX_FORCE = 0x00000004;
 
    private const int EWX_POWEROFF = 0x00000008;
 
    private const int EWX_FORCEIFHUNG = 0x00000010;
 
    #endregion
    
    public static void DoExitWin(int flg)
    {
 
        //give current process SeShutdownPrivilege
        TokPriv1Luid tp;
 
        IntPtr hproc = GetCurrentProcess();
 
        IntPtr htok = IntPtr.Zero;
 
        if (!OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok))
        {
            throw new Exception("Open Process Token fail");
        }
 
        tp.Count = 1;
 
        tp.Luid = 0;
 
        tp.Attr = SE_PRIVILEGE_ENABLED;
 
        if (!LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid))
        {
            throw new Exception("Lookup Privilege Value fail");
        }
 
        if (!AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
        {
            throw new Exception("Adjust Token Privileges fail");
        }
 
        //Exit windows
        if (!ExitWindowsEx(flg, 0))
        {
            throw new Exception("Exit Windows fail");
        }
    }
 
    /// <summary>
    /// Reboot computer
    /// </summary>
    /// <param name="force">force reboot</param>
    public static void Reboot(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_REBOOT | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_REBOOT | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// Reboot computer force if hung
    /// </summary>
    public static void Reboot()
    {
        Reboot(false);
    }
 
    /// <summary>
    /// Shut down computer
    /// </summary>
    /// <param name="force">force shut down</param>
    public static void Shutdown(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_SHUTDOWN | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_SHUTDOWN | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// Shut down computer force if hung
    /// </summary>
    public static void Shutdown()
    {
        Shutdown(false);
    }
 
    /// <summary>
    /// Log off
    /// </summary>
    /// <param name="force">force logoff</param>
    public static void Logoff(bool force)
    {
        if (force)
        {
            DoExitWin(EWX_LOGOFF | EWX_FORCE);
        }
        else
        {
            DoExitWin(EWX_LOGOFF | EWX_FORCEIFHUNG);
        }
    }
 
    /// <summary>
    /// logoff computer force if hung
    /// </summary>
    public static void Logoff()
    {
        Logoff(false);
    }
}