Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
342 views
in Technique[技术] by (71.8m points)

c# - When using ExitWindowsEx, logoff works, but shutdown and restart do not

When I call logoff, it works. But shutdown and restart don't work. Everything looks OK. I looked at other examples on SO and else where and the code looks pretty uniform across most places. So I'm thinking it might be something other than the code.

I'm running as admin and I tried it without the force flag.

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
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In order to be able to shutdown the computer you have to enable the SeShutdown privilege. Once this is done you can call 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;
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...