Overriding the Closing event
-
I have written a C# windows application. However, when the program is running, and I want to shut down windows, every program closes except my C# program; and windows does not shut down. It just waits. When I close my program manually, windows shuts down without a problem. The cause is that I have overriden the Closing event of the main form like this: private void WindowsCloserForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) { e.Cancel = true; OpenDialog(false); } I wanted this behaviour however: closing the form should not end the program, but just hide it. (Via an icon in the system tray you can close the program) If I do not override the Closing event, this problem does not occur. Can this be a bug in the framework, or am I forgetting something? Ludwig
-
I have written a C# windows application. However, when the program is running, and I want to shut down windows, every program closes except my C# program; and windows does not shut down. It just waits. When I close my program manually, windows shuts down without a problem. The cause is that I have overriden the Closing event of the main form like this: private void WindowsCloserForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) { e.Cancel = true; OpenDialog(false); } I wanted this behaviour however: closing the form should not end the program, but just hide it. (Via an icon in the system tray you can close the program) If I do not override the Closing event, this problem does not occur. Can this be a bug in the framework, or am I forgetting something? Ludwig
This thread should have an answer: Click here -- David Wengier Sonork ID: 100.14177 - Ch00k
-
This thread should have an answer: Click here -- David Wengier Sonork ID: 100.14177 - Ch00k
-
This thread should have an answer: Click here -- David Wengier Sonork ID: 100.14177 - Ch00k
Well, I tried: override protected void WndProc(ref Message m) { int message = m.Msg; if ( message == 0x0012 ) //WM_QUIT { } else if ( message == 0x0010 ) //WM_CLOSE { // Who closed the form? } base.WndProc(ref m); } but is seems that quitting windows does not raise the WM_QUIT event. It raises the WM_CLOSE event, though. But how can I check who closed the form? I don't know how to use LParam of WParam?
-
Well, I tried: override protected void WndProc(ref Message m) { int message = m.Msg; if ( message == 0x0012 ) //WM_QUIT { } else if ( message == 0x0010 ) //WM_CLOSE { // Who closed the form? } base.WndProc(ref m); } but is seems that quitting windows does not raise the WM_QUIT event. It raises the WM_CLOSE event, though. But how can I check who closed the form? I don't know how to use LParam of WParam?
I am truly at a loss... It appears that every single event that is raised to ask if the program/form should close just asks not providing any information as to why its asking. I've even fiddled with using reflection to get at some internal members, but all I get is "member not found" errors :(( Here's what I've found if you want to investigate it further Inside of the Application class is a nested type called ThreadContext. You can get the Type for this with this bit of code.
public Type GetThreadContextType() {
MemberInfo[] typesInApp = typeof(Application).FindMembers(
MemberTypes.NestedType,
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public,
new MemberFilter(memFilter), null
);return MemberInfo[0].DeclaringType;
}private bool memFilter(MemberInfo m, object filterCriteria)
{
if( m.Name.IndexOf("ThreadContext") != -1 )
return true;
else
return false;
}Now that class has a static method called "FromCurrent" which takes no arguments and returns the ThreadContext for the current application. This is retrieved by looking up a LocalDataStore on the Thread, the LocalDataStoreSlot is stored in a static field named
tlsSlot
, this slot corresponds to the thread's ThreadContext object. Once you have an instance of ThreadContext you can call the GetState method passing in the value 0x10 to see if the Thread has an AppQuit message posted or pass in 0x08 to see if the Thread has a Quit message posted. Here is the code I've been pounding out since you posted your message, if anyone can get it to work I'll buy you a beer the next time you are in the area :)Type app = typeof(Application);
MemberInfo[] typesInApp = app.FindMembers(
MemberTypes.NestedType,
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public,
new MemberFilter(memFilter), null
);Type typeThreadContext = typesInApp[0].DeclaringType;
object threadContext = Thread.GetData(
(LocalDataStoreSlot) typeThreadContext.InvokeMember(
"tlsSlot",
BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Static,
null, null, new object [] { }
)
);bool StatePostedAppQuit = (bool) typeThreadContext.InvokeMember(
"threadState",
BindingFlags.GetField | BindingFlags.NonPublic,
null, threadContext, new object[] { 0x10 }
);bool StatePostedQuit = (bool) typeThreadContext.InvokeMember(
"threadState",
BindingFlags.GetField | BindingFlags.NonPublic,
null, threadContext, new object[] { 0x08 }
); -
I am truly at a loss... It appears that every single event that is raised to ask if the program/form should close just asks not providing any information as to why its asking. I've even fiddled with using reflection to get at some internal members, but all I get is "member not found" errors :(( Here's what I've found if you want to investigate it further Inside of the Application class is a nested type called ThreadContext. You can get the Type for this with this bit of code.
public Type GetThreadContextType() {
MemberInfo[] typesInApp = typeof(Application).FindMembers(
MemberTypes.NestedType,
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public,
new MemberFilter(memFilter), null
);return MemberInfo[0].DeclaringType;
}private bool memFilter(MemberInfo m, object filterCriteria)
{
if( m.Name.IndexOf("ThreadContext") != -1 )
return true;
else
return false;
}Now that class has a static method called "FromCurrent" which takes no arguments and returns the ThreadContext for the current application. This is retrieved by looking up a LocalDataStore on the Thread, the LocalDataStoreSlot is stored in a static field named
tlsSlot
, this slot corresponds to the thread's ThreadContext object. Once you have an instance of ThreadContext you can call the GetState method passing in the value 0x10 to see if the Thread has an AppQuit message posted or pass in 0x08 to see if the Thread has a Quit message posted. Here is the code I've been pounding out since you posted your message, if anyone can get it to work I'll buy you a beer the next time you are in the area :)Type app = typeof(Application);
MemberInfo[] typesInApp = app.FindMembers(
MemberTypes.NestedType,
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public,
new MemberFilter(memFilter), null
);Type typeThreadContext = typesInApp[0].DeclaringType;
object threadContext = Thread.GetData(
(LocalDataStoreSlot) typeThreadContext.InvokeMember(
"tlsSlot",
BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Static,
null, null, new object [] { }
)
);bool StatePostedAppQuit = (bool) typeThreadContext.InvokeMember(
"threadState",
BindingFlags.GetField | BindingFlags.NonPublic,
null, threadContext, new object[] { 0x10 }
);bool StatePostedQuit = (bool) typeThreadContext.InvokeMember(
"threadState",
BindingFlags.GetField | BindingFlags.NonPublic,
null, threadContext, new object[] { 0x08 }
);Found another (rather simple solution :laugh:), like this: protected override void WndProc(ref Message m) { const int WM_SYSCOMMAND = 0x0112; const int SC_CLOSE = 0xF060; if (m.Msg == WM_SYSCOMMAND && (int) m.WParam == SC_CLOSE) { // User clicked close button OpenDialog(false); return; } base.WndProc(ref m); } Kind regards, Ludwig
-
Found another (rather simple solution :laugh:), like this: protected override void WndProc(ref Message m) { const int WM_SYSCOMMAND = 0x0112; const int SC_CLOSE = 0xF060; if (m.Msg == WM_SYSCOMMAND && (int) m.WParam == SC_CLOSE) { // User clicked close button OpenDialog(false); return; } base.WndProc(ref m); } Kind regards, Ludwig
Doh! I like your version much better :) James Sonork: Hasaki "I left there in the morning with their God tucked underneath my arm their half-assed smiles and the book of rules. So I asked this God a question and by way of firm reply, He said - I'm not the kind you have to wind up on Sundays." "Wind Up" from Aqualung, Jethro Tull 1971
-
Doh! I like your version much better :) James Sonork: Hasaki "I left there in the morning with their God tucked underneath my arm their half-assed smiles and the book of rules. So I asked this God a question and by way of firm reply, He said - I'm not the kind you have to wind up on Sundays." "Wind Up" from Aqualung, Jethro Tull 1971
Well, thanks anyway for the answer! Meanwhile I've joined this forum, because it's one of the best I've seen. Ludwig