使用ExitWindowsEx时,注销可以正常工作,但是关闭和重启不会

时间:2014-07-13 18:54:26

标签: c# winforms

当我呼叫注销时,它可以工作。但关机和重启不起作用。一切看起来确定。我查看了SO上的其他示例以及其他地方和代码在大多数地方看起来非常统一。所以我认为它可能不是代码。

我以管理员身份运行,我在没有强制标志的情况下尝试了它。

public void ShutdownComputer(ShutdownType type, bool force)
    {
        switch (type)
        {
            case ShutdownType.Shutdown:
                ExitWindowsEx(ExitWindows.ShutDown | (force ? ExitWindows.Force : ExitWindows.ForceIfHung), ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned); 
                break;
            case ShutdownType.Restart:
                ExitWindowsEx(ExitWindows.Reboot | (force ? ExitWindows.Force : ExitWindows.ForceIfHung), ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned); 
                break;
            case ShutdownType.Logoff:
                ExitWindowsEx(ExitWindows.LogOff | (force ? ExitWindows.Force : ExitWindows.ForceIfHung), ShutdownReason.MajorOther | ShutdownReason.MinorOther | ShutdownReason.FlagPlanned); 
                break;
        }
    }

[DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

    [Flags]
    public enum ExitWindows : uint
    {
        // ONE of the following five:
        LogOff = 0x00,
        ShutDown = 0x01,
        Reboot = 0x02,
        PowerOff = 0x08,
        RestartApps = 0x40,
        // plus AT MOST ONE of the following two:
        Force = 0x04,
        ForceIfHung = 0x10,
    }
    [Flags]
    enum ShutdownReason : uint
    {
        MajorApplication = 0x00040000,
        MajorHardware = 0x00010000,
        MajorLegacyApi = 0x00070000,
        MajorOperatingSystem = 0x00020000,
        MajorOther = 0x00000000,
        MajorPower = 0x00060000,
        MajorSoftware = 0x00030000,
        MajorSystem = 0x00050000,

        MinorBlueScreen = 0x0000000F,
        MinorCordUnplugged = 0x0000000b,
        MinorDisk = 0x00000007,
        MinorEnvironment = 0x0000000c,
        MinorHardwareDriver = 0x0000000d,
        MinorHotfix = 0x00000011,
        MinorHung = 0x00000005,
        MinorInstallation = 0x00000002,
        MinorMaintenance = 0x00000001,
        MinorMMC = 0x00000019,
        MinorNetworkConnectivity = 0x00000014,
        MinorNetworkCard = 0x00000009,
        MinorOther = 0x00000000,
        MinorOtherDriver = 0x0000000e,
        MinorPowerSupply = 0x0000000a,
        MinorProcessor = 0x00000008,
        MinorReconfig = 0x00000004,
        MinorSecurity = 0x00000013,
        MinorSecurityFix = 0x00000012,
        MinorSecurityFixUninstall = 0x00000018,
        MinorServicePack = 0x00000010,
        MinorServicePackUninstall = 0x00000016,
        MinorTermSrv = 0x00000020,
        MinorUnstable = 0x00000006,
        MinorUpgrade = 0x00000003,
        MinorWMI = 0x00000015,

        FlagUserDefined = 0x40000000,
        FlagPlanned = 0x80000000
    }

1 个答案:

答案 0 :(得分:10)

为了能够关闭计算机,您必须启用SeShutdown权限。完成后,您可以拨打ExitWindowEx

public static class PowerUtilities
{
    [DllImport("user32.dll", SetLastError = true)]
    private static extern int ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);

    public static bool ExitWindows(ExitWindows exitWindows, ShutdownReason reason, bool ajustToken)
    {
        if (ajustToken && !TokenAdjuster.EnablePrivilege("SeShutdownPrivilege", true))
        {
            return false;
        }


        return ExitWindowsEx(exitWindows, reason) != 0;
    }
}


[Flags]
public enum ExitWindows : uint
{
    // ONE of the following:
    LogOff = 0x00,
    ShutDown = 0x01,
    Reboot = 0x02,
    PowerOff = 0x08,
    RestartApps = 0x40,
    // plus AT MOST ONE of the following two:
    Force = 0x04,
    ForceIfHung = 0x10,
}

[Flags]
public enum ShutdownReason : uint
{
    None = 0,

    MajorApplication = 0x00040000,
    MajorHardware = 0x00010000,
    MajorLegacyApi = 0x00070000,
    MajorOperatingSystem = 0x00020000,
    MajorOther = 0x00000000,
    MajorPower = 0x00060000,
    MajorSoftware = 0x00030000,
    MajorSystem = 0x00050000,

    MinorBlueScreen = 0x0000000F,
    MinorCordUnplugged = 0x0000000b,
    MinorDisk = 0x00000007,
    MinorEnvironment = 0x0000000c,
    MinorHardwareDriver = 0x0000000d,
    MinorHotfix = 0x00000011,
    MinorHung = 0x00000005,
    MinorInstallation = 0x00000002,
    MinorMaintenance = 0x00000001,
    MinorMMC = 0x00000019,
    MinorNetworkConnectivity = 0x00000014,
    MinorNetworkCard = 0x00000009,
    MinorOther = 0x00000000,
    MinorOtherDriver = 0x0000000e,
    MinorPowerSupply = 0x0000000a,
    MinorProcessor = 0x00000008,
    MinorReconfig = 0x00000004,
    MinorSecurity = 0x00000013,
    MinorSecurityFix = 0x00000012,
    MinorSecurityFixUninstall = 0x00000018,
    MinorServicePack = 0x00000010,
    MinorServicePackUninstall = 0x00000016,
    MinorTermSrv = 0x00000020,
    MinorUnstable = 0x00000006,
    MinorUpgrade = 0x00000003,
    MinorWMI = 0x00000015,

    FlagUserDefined = 0x40000000,
    FlagPlanned = 0x80000000
}

public sealed class TokenAdjuster
{
    // PInvoke stuff required to set/enable security privileges
    private const int SE_PRIVILEGE_ENABLED = 0x00000002;
    private const int TOKEN_ADJUST_PRIVILEGES = 0X00000020;
    private const int TOKEN_QUERY = 0X00000008;
    private const int TOKEN_ALL_ACCESS = 0X001f01ff;
    private const int PROCESS_QUERY_INFORMATION = 0X00000400;

    [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity]
    private static extern int OpenProcessToken(
        IntPtr ProcessHandle, // handle to process
        int DesiredAccess, // desired access to process
        ref IntPtr TokenHandle // handle to open access token
        );

    [DllImport("kernel32", SetLastError = true),
     SuppressUnmanagedCodeSecurity]
    private static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int AdjustTokenPrivileges(
        IntPtr TokenHandle,
        int DisableAllPrivileges,
        IntPtr NewState,
        int BufferLength,
        IntPtr PreviousState,
        ref int ReturnLength);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool LookupPrivilegeValue(
        string lpSystemName,
        string lpName,
        ref LUID lpLuid);

    public static bool EnablePrivilege(string lpszPrivilege, bool bEnablePrivilege)
    {
        bool retval = false;
        int ltkpOld = 0;
        IntPtr hToken = IntPtr.Zero;
        TOKEN_PRIVILEGES tkp = new TOKEN_PRIVILEGES();
        tkp.Privileges = new int[3];
        TOKEN_PRIVILEGES tkpOld = new TOKEN_PRIVILEGES();
        tkpOld.Privileges = new int[3];
        LUID tLUID = new LUID();
        tkp.PrivilegeCount = 1;
        if (bEnablePrivilege)
            tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
        else
            tkp.Privileges[2] = 0;
        if (LookupPrivilegeValue(null, lpszPrivilege, ref tLUID))
        {
            Process proc = Process.GetCurrentProcess();
            if (proc.Handle != IntPtr.Zero)
            {
                if (OpenProcessToken(proc.Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                    ref hToken) != 0)
                {
                    tkp.PrivilegeCount = 1;
                    tkp.Privileges[2] = SE_PRIVILEGE_ENABLED;
                    tkp.Privileges[1] = tLUID.HighPart;
                    tkp.Privileges[0] = tLUID.LowPart;
                    const int bufLength = 256;
                    IntPtr tu = Marshal.AllocHGlobal(bufLength);
                    Marshal.StructureToPtr(tkp, tu, true);
                    if (AdjustTokenPrivileges(hToken, 0, tu, bufLength, IntPtr.Zero, ref ltkpOld) != 0)
                    {
                        // successful AdjustTokenPrivileges doesn't mean privilege could be changed
                        if (Marshal.GetLastWin32Error() == 0)
                        {
                            retval = true; // Token changed
                        }
                    }
                    TOKEN_PRIVILEGES tokp = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(tu, typeof(TOKEN_PRIVILEGES));
                    Marshal.FreeHGlobal(tu);
                }
            }
        }
        if (hToken != IntPtr.Zero)
        {
            CloseHandle(hToken);
        }
        return retval;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct LUID
    {
        internal int LowPart;
        internal int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LUID_AND_ATTRIBUTES
    {
        private LUID Luid;
        private int Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct TOKEN_PRIVILEGES
    {
        internal int PrivilegeCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
        internal int[] Privileges;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct _PRIVILEGE_SET
    {
        private int PrivilegeCount;
        private int Control;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // ANYSIZE_ARRAY = 1
        private LUID_AND_ATTRIBUTES[] Privileges;
    }
}