Should work, anyway herewith a complete sample illustrating how to enable
privileges and shutdown a system. Hope you take some time to understand the
details.
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security;
namespace Willys
{
sealed class Win32TokenPrivileges
{
internal const uint SE_PRIVILEGE_DISABLED = 0x00000000;
internal const uint SE_PRIVILEGE_ENABLED = 0x00000002;
[StructLayout(LayoutKind.Sequential)]
internal struct LUID {
internal uint LowPart;
internal uint HighPart;
}
[StructLayout(LayoutKind.Sequential)]
internal struct LUID_AND_ATTRIBUTES {
internal LUID Luid;
internal uint Attributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct TOKEN_PRIVILEGE {
internal uint PrivilegeCount;
internal LUID_AND_ATTRIBUTES Privilege;
}
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool LookupPrivilegeValue(string lpSystemName,
string lpName, [In, Out] ref LUID Luid);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AdjustTokenPrivileges(IntPtr tokenHndl,
bool diasableAll, [In] ref TOKEN_PRIVILEGE newTokenState, int length,
ref TOKEN_PRIVILEGE prevTokenState, ref uint retLength);
[DllImport("advapi32.dll",EntryPoint="InitiateSystemShutdown", CharSet =
CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)] // Explicit marshaling
directive required here! (BOOL in Windows is a DWORD, bool in C# is a byte
value)
internal static extern bool InitiateSystemShutdown(string lpMachineName,
string lpMessage,
int dwTimeout,
[MarshalAs(UnmanagedType.Bool)] bool bForceAppsClosed,
[MarshalAs(UnmanagedType.Bool)] bool bRebootAfterShutdown);
}
sealed class Program
{
static void Main()
{
IntPtr tokenHandle = WindowsIdentity.GetCurrent().Token; // consider
using a safehandle here
Win32TokenPrivileges.LUID luid = new Win32TokenPrivileges.LUID();
bool ret = Win32TokenPrivileges.LookupPrivilegeValue ("",
"SeShutdownPrivilege", ref luid);
if(ret == true)
{
Win32TokenPrivileges.TOKEN_PRIVILEGE tokenPriv = new
Win32TokenPrivileges.TOKEN_PRIVILEGE();
Win32TokenPrivileges.TOKEN_PRIVILEGE prevToken = new
Win32TokenPrivileges.TOKEN_PRIVILEGE();
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privilege.Luid = luid;
tokenPriv.Privilege.Attributes =
Win32TokenPrivileges.SE_PRIVILEGE_ENABLED;
uint retlen = 0;
ret = Win32TokenPrivileges.AdjustTokenPrivileges (tokenHandle, false,
ref tokenPriv, Marshal.SizeOf(tokenPriv), ref prevToken, ref retlen);
if(ret == false)
{
Console.WriteLine("AdjustTokenPrivileges error {0}",
Marshal.GetLastWin32Error());
Environment.Exit(1);
}
ret = Win32TokenPrivileges.InitiateSystemShutdown("", "System shutdown
requested .... ", 30, true, true);
if(ret == false)
{
Console.WriteLine("InitiateSystemShutdown error {0}",
Marshal.GetLastWin32Error());
Environment.Exit(1);
}
}
}
}
}
Willy.
greatbarrier86 said:
Willy, I used the GetLastWin32Error and it returned "The Parameter is
Incorrect." I'm a little confused.
Willy Denoyette said:
1) Change the DllImport declaration such that it returns an int value
like:
public static extern int InitiateSystemShutdownA(string....
assign the return value to a variable like this:
int ret = InitiateSystemShutdownA(null,null, 30, 1, 1);
2) Make sure the GetLastError returns something meaningful, by setting
the
SetLastError to true.
[DllImport("advapi32.dll",EntryPoint="InitiateSystemShutdown",SetLastError=true)]
3) Check what "InitiateSystemShutdown" can possibly return (in MSDN) and
take appropriate actions when the return is an error value.
if(ret == 0)
{
// Failed, most (but not all) Win32 API's return 0 on failure
// Call Marshall.GetLastWin32Error to get the Win32 error code
}
else
// success.
Note that your code will most probably return error code 5, which means
"Access Denied". The reason for this is that you need to enable the
SE_SHUTDOWN_NAME privileges. This again has to be done using native API
calls as this is not covered by the Framework classes.
That said, calling into Win32 through PInvoke is not something you should
start without reading the API description in the docs.
Willy.
message
Heh...like i said, i'm a noob
How do i check the return value?
:
message
I've already got the code written but for some reason, when i click
the
button, nothing occurs. Here is the code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
[DllImport("advapi32.dll",EntryPoint="InitiateSystemShutdown")]
public static extern bool InitiateSystemShutdownA(string
lpMachineName, string lpMessage, int dwTimeout, int
bForceAppsClosed,
int
bRebootAfterShutdown);
private void button1_Click(object sender, System.EventArgs e)
{
InitiateSystemShutdownA(null,null, 30, 1, 1);
}
It compiles fine, but when i click button1, nothing happens. Any
ideas?
How do you know the call succeeded when you don't check the return
value
of
the API call?
Willy.