C# 调用 Windows API 实现关机、重启与注销

今天早睡
今天早睡
发布时间:2026-10-14 | 3人浏览过
原创

在 C# 开发中,有时需要通过程序直接控制操作系统电源状态。本文将演示如何利用 Platform Invocation Services (P/Invoke) 调用 Windows advapi32.dll 和 user32.dll 中的 API,以管理员权限安全地执行关机、重启或注销命令。

实现原理与准备工作

C# 无法直接调用底层 C/C++ API,必须通过声明外部方法(DllImport)进行桥接。实现关机的关键逻辑分为两步:

  1. 权限提升:当前进程默认没有关机权限,需要通过 AdjustTokenPrivileges 开启 SE_SHUTDOWN_NAME 特权。
  2. 执行指令:使用 ExitWindowsEx 发送具体的关机或重启标志位。

注意:以下代码包含高危系统操作。在生产环境或用户电脑上运行前,请务必确保已保存未编辑的数据,因为关机指令可能导致不可逆的后果。

第1步:定义结构体与常量

首先定义用于令牌调整的结构体以及 API 调用所需的标志位常量。原文代码中存在拼写错误(如 shoutdown),此处已修正为标准命名规范。

1. 导入动态链接库并定义辅助结构

入口:System.Runtime.InteropServices
动作:声明内存布局及外部函数签名。

using System;
using System.Runtime.InteropServices;

class PowerControl
{
    // 定义令牌权限结构,Pack=1 确保内存对齐方式正确
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
        public int Count;
        public long Luid;
        public int Attr;
    }

    // 权限属性常量
    internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
    
    // 令牌访问权限
    internal const int TOKEN_QUERY = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    
    // 关机特权名称
    internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";

    // ExitWindowsEx 的标志位定义
    internal const int EWX_LOGOFF = 0x00000000;     // 注销
    internal const int EWX_SHUTDOWN = 0x00000001;   // 关机
    internal const int EWX_REBOOT = 0x00000002;     // 重启
    internal const int EWX_FORCE = 0x00000004;      // 强制关闭(不等待应用退出)
    internal const int EWX_POWEROFF = 0x00000008;   // 断电(部分系统支持)
    internal const int EWX_FORCEIFHUNG = 0x00000010; // 如果应用无响应则强制关闭
}

2. 声明外部 API 函数

入口:kernel32.dll, advapi32.dll, user32.dll
动作:映射 Windows 底层函数到 C#。
重要参数:SetLastError=true 允许获取精确的错误代码。

    [DllImport("kernel32.dll", ExactSpelling = true)]
    internal static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
        ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

    [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool ExitWindowsEx(int flg, int rea);

第2步:封装关机逻辑

入口:PowerControl.DoExitWin
动作:组合上述 API 调用,完成权限赋予与系统指令发送。

    private static void DoExitWin(int flg)
    {
        bool ok;
        TokPriv1Luid tp;
        
        // 1. 获取当前进程句柄
        IntPtr hproc = GetCurrentProcess();
        IntPtr htok = IntPtr.Zero;
        
        // 2. 打开进程令牌,请求调整特权和查询权限
        ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
        if (!ok) return; // 若失败可在此处理错误

        // 3. 准备特权数据结构
        tp.Count = 1;
        tp.Luid = 0;
        tp.Attr = SE_PRIVILEGE_ENABLED;

        // 4. 查找并获取关机特权的本地唯一标识符 (LUID)
        ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
        
        // 5. 调整令牌特权,启用 SeShutdownPrivilege
        ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
        
        // 6. 执行指定的 Windows 操作(关机/重启/注销等)
        ok = ExitWindowsEx(flg, 0);
    }

第3步:调用执行

在主程序中调用 DoExitWin 并传入对应的标志位。例如,若要重启计算机,将参数改为 EWX_REBOOT;若要强制注销,使用 EWX_LOGOFF。

    public static void Main()
    {
        Console.WriteLine("正在关闭计算机……");
        // 示例:执行普通关机
        DoExitWin(EWX_SHUTDOWN);
        
        // 其他示例调用(取消注释即可使用):
        // DoExitWin(EWX_REBOOT);       // 重启
        // DoExitWin(EWX_LOGOFF);       // 注销当前用户
        // DoExitWin(EWX_FORCE | EWX_SHUTDOWN); // 强制关机
    }

完成判断与排错

  • 成功判断:ExitWindowsEx 返回 true,且屏幕变黑进入关机流程。
  • 常见错误:若返回 false,请检查是否以管理员权限运行该程序。非管理员账户可能无法获得 SeShutdownPrivilege,导致 AdjustTokenPrivileges 失败。
  • 版本兼容:该 API 在 Windows NT/2000/XP/Vista/7/8/10/11 均有效。

简要总结

通过 C# 调用 Windows API 实现关机是一个涉及权限管理和底层通信的典型场景。关键在于正确配置 TokPriv1Luid 结构并使用 AdjustTokenPrivileges 提权。以上就是 C# 调用 Windows API 实现关机的详细内容,更多关于 C# 系统控制方面的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表