Man kennt dieses Feature von Programmen wie Word, die sich bei ungesicherten Änderungen beim Herunterfahren bemerkbar machen.
Das kann man selbst recht leicht implementieren. Im nachfolgenden mit Kommentaren für Windows Forms.
Getestet unter Windows 8.1.
In WPF kann man die Methoden genauso aufrufen, das Herunterfahren abbrechen muss man mit dem Application.SessionEnding-Event:
http://msdn.microsoft.com/de-de/library/vstudio/system.windows.application.sessionending.aspx
Wie man an das Handle eines WPF-Fensters kommt, ist in folgendem Snippet erläutert:
http://dotnet-snippets.de/snippet/handle-eines-wpf-fensters-ermitteln/607
Das Handle muss von einem gültigem Fenster stammen, sonst geht es nicht.
Um das Herunterfahren wieder zu erlauben muss blockLogof (bzw. e.Cancel im WPF-Event) auf False gestellt werden. Sobald das Programm beendet ist, wird WndProc (bzw. das Event) nicht mehr durchlaufen, weswegen es dann keine Rolle mehr spielt.
//http://www.pinvoke.net/default.aspx/user32.shutdownblockreasoncreate
[DllImport("user32.dll")]
private extern static bool ShutdownBlockReasonCreate(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string pwszReason);//Handle des Fensters und Nachricht
//http://www.pinvoke.net/default.aspx/user32/ShutdownBlockReasonDestroy.html
[DllImport("user32.dll")]
private extern static bool ShutdownBlockReasonDestroy(IntPtr hWnd);//Handle des Fensters
//Windows Nachrichten
const int WM_QUERYENDSESSION = 0x11;
const int WM_ENDSESSION = 0x16;
const int WM_CANCELMODE = 0x1F;
bool blockLogof = false;//Auf true stellen um Herunterfahren zu blockieren.
//Empfängt alle Meldungen, die an das Fenster gesendet wurden.
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_ENDSESSION:
case WM_QUERYENDSESSION://Sitzung wird beendet
if(!blockLogof)//Herunterfahren ggf. erlauben
base.WndProc(ref m);
else
{
Message msg = new Message() { Msg = WM_CANCELMODE };//Neue Nachricht erstellen
base.WndProc(ref msg);//An Windows weiter leiten
}
return;
default:
base.WndProc(ref m);//Andere Nachrichten einfach weiter leiten
return;
}
}
private void buttonBlock_Click(object sender, EventArgs e)
{
blockLogof = true;
var result = ShutdownBlockReasonCreate(this.Handle, textBox1.Text);
// eine Benutzerdefinierte Meldung angeben
if (!result)
MessageBox.Show("Fehler beim setzen der Nachricht");
}
private void buttonAllow_Click(object sender, EventArgs e)
{
var result = ShutdownBlockReasonDestroy(this.Handle);
//Meldung wieder entfernen
if (!result)
MessageBox.Show("Fehler beim löschen der Nachricht");
blockLogof = false;
}
Kommentare zum Snippet