using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Uchukamen.Util
{
/// <summary>
/// Following information is based on Microsoft MSDN Library,
/// Platform SDK: Windows System Information
/// Shutting Down
/// http://msdn.microsoft.com/library/en-us/sysinfo/base/shutting_down.asp
/// See following URL for more detail about Interop
/// http://www.microsoft.com/japan/msdn/library/
/// ja/cpguide/html/cpconoutarrayofstructssample.asp
/// Shutdown 95, 98,
///
/// プラットフォーム:
/// Windows 98, Windows NT 4.0, Windows ME,
/// Windows 2000, Windows XP Home Edition, Windows XP Professional,
/// Windows .NET Server family
///
/// 動作確認プラットフォーム: Windows XP Professional
/// </summary>
public class ShutdownLibWrap
{
#region ShutdownFlag
/// EWX_FORCE
/// 上記パラメータと同時に設定します。
/// プロセスを強制的に終了させます。
/// このフラグを指定すると、システムは、現在実行されているアプリケーションへ
/// WM_QUERYENDSESSION メッセージや WM_ENDSESSION メッセージを送信しません。
/// この結果、アプリケーションがデータを失う可能性もあります。
/// したがって、このフラグは、緊急時にのみ指定してください。
public const int Force = 0x00000004;
/// EWX_FORCEIFHUNG
/// Windows 2000:プロセスが WM_QUERYENDSESSION または WM_ENDSESSION メッセージに
/// 応答しない場合、それらのプロセスを終了させます。EWX_FORCE フラグを指定すると、
/// EWX_FORCEIFHUNG フラグは無視されます。
/// </summary>
public const int ForceIfHung = 0x00000010;
/// EWX_LOGOFF
/// 呼び出し側のプロセスのセキュリティコンテキストで実行されている
/// すべてのプロセスを終了し、現在のユーザーをログオフさせます。
public const int Logoff = 0x00000000;
/// EWX_POWEROFF
/// システムをシャットダウンした後、電源を切ります。
/// システムは、パワーオフ機能をサポートしていなければなりません。
/// Windows NT/2000/XP:呼び出し側のプロセスに、SE_SHUTDOWN_NAME 特権が必要です。
public const int Poweroff = 0x00000008;
/// EWX_REBOOT
/// システムをシャットダウンした後、システムを再起動します。
/// Windows NT/2000/XP:呼び出し側のプロセスに、SE_SHUTDOWN_NAME 特権が必要です。
public const int Reboot = 0x00000002;
/// EWX_SHUTDOWN
/// システムをシャットダウンして、電源を切っても安全な状態にします。
/// すべてのバッファをディスクへフラッシュし(バッファの内容をディスクに書き込み)、
/// 動作していたすべてのプロセスを停止します。
/// Windows NT/2000/XP:呼び出し側のプロセスに、SE_SHUTDOWN_NAME 特権が必要です。
public const int Shutdown = 0x00000001;
/// <summary>
/// <param name="flag">シャットダウン操作</param>
/// <param name="reserved">予約済み</param>
/// <returns></returns>
/// </summary>
[DllImport("user32.dll", SetLastError=true) ]
private static extern bool ExitWindowsEx( int flag, int reserved );
#endregion
#region Privileges related Structures
// LUID locally unique identifier
// LUID は64bit なので、直接LUID_AND_ATTRIBUTES に long で宣言する。
/// <summary>
/// typedef struct _LUID_AND_ATTRIBUTES {
/// LUID Luid;
/// DWORD Attributes;
/// } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES;
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct LUID_AND_ATTRIBUTES
{
public long Luid;
public int Attributes;
}
/// <summary>
/// typedef struct _TOKEN_PRIVILEGES {
/// DWORD PrivilegeCount;
/// LUID_AND_ATTRIBUTES Privileges[];
/// } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
/// StructLayout の Pack=4 は必要。これにより、
/// 4byte 境界でパッキングする。
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct TOKEN_PRIVILEGES
{
public int PrivilegeCount;
public LUID_AND_ATTRIBUTES Privileges;
}
#endregion
#region Privilege related APIs
/// <summary>
/// プロセスに関連付けられているアクセストークンを開きます。
/// BOOL OpenProcessToken(
/// HANDLE ProcessHandle, // プロセスのハンドル
/// DWORD DesiredAccess, // プロセスに対して希望するアクセス権
/// PHANDLE TokenHandle // 開かれたアクセストークンのハンドルへのポインタ
/// );
/// </summary>
[DllImport("advapi32.dll", SetLastError=true) ]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle);
/// <summary>
/// 指定されたシステムで使われているローカル一意識別子(LUID)を取得し、
/// 指定された特権名をローカルで表現します。
/// BOOL LookupPrivilegeValue(
/// LPCTSTR lpSystemName, // システムを指定する文字列のアドレス
/// LPCTSTR lpName, // 特権を指定する文字列のアドレス
/// PLUID lpLuid // ローカル一意識別子のアドレス
/// );
/// </summary>
[DllImport("advapi32.dll", SetLastError=true) ]
private static extern bool LookupPrivilegeValue(
string lpSystemName,
string lpName,
ref long lpLuid );
/// <summary>
/// 指定したアクセストークン内の特権を有効または無効にします。
/// TOKEN_ADJUST_PRIVILEGES アクセス権が必要です。
/// BOOL AdjustTokenPrivileges(
/// HANDLE TokenHandle, // 特権を保持するトークンのハンドル
/// BOOL DisableAllPrivileges, // すべての特権を無効にするためのフラグ
/// PTOKEN_PRIVILEGES NewState, // 新しい特権情報へのポインタ
/// DWORD BufferLength, // PreviousState バッファのバイト単位のサイズ
/// PTOKEN_PRIVILEGES PreviousState, // 変更を加えられた特権の元の状態を受け取る
/// PDWORD ReturnLength // PreviousState バッファが必要とするサイズを受け取る
/// );
/// </summary>
[DllImport("advapi32.dll", SetLastError=true) ]
private static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
int BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength
);
#endregion
/// <summary>
/// If the function succeeds, the return value is nonzero.
/// </summary>
/// <param name="flag"></param>
/// <returns></returns>
public static bool DoExitWindows( int flag )
{
try
{
/// Windows NT/2000/XP でシャットダウンするには、
/// SE_SHUTDOWN_NAME 特権が必要なので、その特権をセットする。
if (System.Environment.OSVersion.Platform == PlatformID.Win32NT)
SetShutdownPrivilege();
/// Windows Me 以前で Force シャットダウンするには、
/// Explorer のプロセスを終了させ、
/// EWX_LOGOFF および EWX_FORCE フラグを指定して、
/// ExitWindowsEx() をコールする。
else if (System.Environment.OSVersion.Platform == PlatformID.Win32Windows &&
((flag & Force) == Force))
KillExplorer();
}
catch (Exception)
{
return false;
}
bool result = ExitWindowsEx( flag, 0 );
return result;
}
/// <summary>
/// Windows NT/2000/XP でシャットダウンするには、
/// SE_SHUTDOWN_NAME 特権が必要なので、その特権をセットする。
/// </summary>
private static void SetShutdownPrivilege()
{
const int TOKEN_QUERY = 0x00000008;
const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
const int SE_PRIVILEGE_ENABLED = 0x00000002;
// プロセスのハンドルを取得する。
IntPtr hproc = System.Diagnostics.Process.GetCurrentProcess().Handle;
// IntPtr hproc = GetCurrentProcess(); // この方法でもOK.
// Token を取得する。
IntPtr hToken = IntPtr.Zero;
if ( ! OpenProcessToken( hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref hToken ) )
throw new Exception("OpenProcessToken");
// LUID を取得する。
long luid = 0;
if ( ! LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref luid))
throw new Exception("LookupPrivilegeValue");
// 特権を設定する。
TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
tp.PrivilegeCount = 1;
tp.Privileges = new LUID_AND_ATTRIBUTES();
tp.Privileges.Luid = luid;
tp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
// 特権をセットする。
if ( ! AdjustTokenPrivileges( hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero ))
throw new Exception("AdjustTokenPrivileges");
}
//////////////////////////////////////////////////////
/// Windows Me 以前の場合
//////////////////////////////////////////////////////
private static void KillExplorer()
{
// Windows Me 以前であれば、EWX_FORCE フラグを指定して ExitWindowsEx() をコールすると、
// シェルの仕様により、ログオフに失敗します。
// プログラムによって、ユーザーを強制的にログオフさせるには、必ずExplorer のプロセスを終了させ、
// それから、EWX_LOGOFF および EWX_FORCE フラグを指定して、
// ExitWindowsEx() をコールする必要があります。
if (System.Environment.OSVersion.Platform == PlatformID.Win32Windows)
{
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
foreach(Process process in processes)
{
if(process.ProcessName.StartsWith("explorer"))
process.Kill();
}
}
}
}
}
|
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Uchukamen.Util;
namespace Shutdown2
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.CheckBox cbForceIfHung;
private System.Windows.Forms.CheckBox cbForce;
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();
//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}
/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.cbForceIfHung = new System.Windows.Forms.CheckBox();
this.cbForce = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 168);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "DoIt";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// comboBox1
//
this.comboBox1.Items.AddRange(new object[] {
"Logoff",
"Shutdown",
"Power Off",
"Reboot"});
this.comboBox1.Location = new System.Drawing.Point(16, 24);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(168, 20);
this.comboBox1.TabIndex = 1;
//
// groupBox1
//
this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
this.cbForceIfHung,
this.cbForce});
this.groupBox1.Location = new System.Drawing.Point(16, 64);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(184, 88);
this.groupBox1.TabIndex = 2;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "May the Force be with you ^ ^;";
//
// cbForceIfHung
//
this.cbForceIfHung.Location = new System.Drawing.Point(24, 56);
this.cbForceIfHung.Name = "cbForceIfHung";
this.cbForceIfHung.TabIndex = 1;
this.cbForceIfHung.Text = "Force If Hung";
this.cbForceIfHung.CheckedChanged += new System.EventHandler(this.cbForceIfHung_CheckedChanged);
//
// cbForce
//
this.cbForce.Location = new System.Drawing.Point(24, 24);
this.cbForce.Name = "cbForce";
this.cbForce.TabIndex = 2;
this.cbForce.Text = "Force";
this.cbForce.CheckedChanged += new System.EventHandler(this.cbForce_CheckedChanged);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(224, 206);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.groupBox1,
this.comboBox1,
this.button1});
this.Name = "Form1";
this.Text = "Shutdown Test";
this.Load += new System.EventHandler(this.Form1_Load);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
int flag = 0;
switch(this.comboBox1.Text)
{
case "Logoff":
flag = ShutdownLibWrap.Logoff;
break;
case "Shutdown":
flag = ShutdownLibWrap.Shutdown;
break;
case "Poweroff":
flag = ShutdownLibWrap.Poweroff;
break;
case "Reboot":
flag = ShutdownLibWrap.Reboot;
break;
default:
throw new Exception("Unknown Shutdown Flag");
}
if(this.cbForce.Checked)
flag |= ShutdownLibWrap.Force;
else if(this.cbForceIfHung.Checked)
flag |= ShutdownLibWrap.ForceIfHung;
ShutdownLibWrap.DoExitWindows( flag );
}
private string [] shutdown = {"Logoff", "Shutdown", "Poweroff", "Reboot"};
private void Form1_Load(object sender, System.EventArgs e)
{
this.comboBox1.Items.Clear();
this.comboBox1.Items.AddRange(shutdown);
this.comboBox1.SelectedIndex = 0;
// Windows Me 以前の場合、ForceIfHung はサポートされていない。
if (System.Environment.OSVersion.Platform == PlatformID.Win32Windows)
this.cbForceIfHung.Enabled = false;
}
private void cbForce_CheckedChanged(object sender, System.EventArgs e)
{
if(this.cbForce.Checked)
this.cbForceIfHung.Checked = false;
}
private void cbForceIfHung_CheckedChanged(object sender, System.EventArgs e)
{
if(this.cbForceIfHung.Checked)
this.cbForce.Checked = false;
}
}
}
|