@pcinfogmach עכשיו אני מבין ששאלת שאלה חזקה.
כמה מחשבות שעולות לי:
סתם מחשבה: העניין הזה שהתוכנה נסגרת בלי לנקות אחריו עלול לקרות גם ב-"production". אי אפשר לסמוך על זה שהתוכנה לא תקרוס או מאיזה סיבה אחרת תיסגר בצורה "לא נקיה". אם כן כדאי לתת את הדעת על איך התוכנה תוכל להתמודד עם מצב זה בצורה אוטומטית עד כמה שאפשר.
ℹ לידיעה (להבין את תהליך המחשבה שלי בנושא): מה קרה לתוכנה כאשר ה-UI "תקוע"?
הלב הפועם של כל תוכנה גרפית בווינדוס הוא ה-message loop. זה "לולאה קיומית" שכל תוכנה גרפית נמצא בו כל הזמן, הלולאה מקבלת "אירועים" ממערכת ההפעלה (לדוגמה לחיצות מקשים ותזוזות עכבר וכו') ומטפלת בהם. בד"כ הלולאה רצה על הת'רד הראשי. תוכנה שתקועה, הכוונה שהלולאה הראשית הפסיקה לטפל באירועים, בד"כ כי הוא אוחז באמצע פעולה ארוכה או תקועה.
כל אינטראקציה עם תוכנה גרפית שולחת אירוע ללולאה, אם הלולאה תקועה, התוכנה לא תגיב. לכן אי אפשר לסגור אותה עם האיקס האדום כי זה פועל על ידי שליחת אירוע ל-message loop
המחשבה הבאה שלי היתה שאפשר לסגור תוכנה שלא מגיבה על ידי קריאת פונקציה בחלון ה-Immediate Window
לשם בדיקת הצעה זו יצרתי פרוייקט WPF (לפי ההיסטוריה שלך אני מניח שגם התוכנה שלך WPF) והוספתי Sleep ארוך בת'רד הראשי, ואז ניסיתי לסגור את התוכנה באמצעות ה-Immediate Window
הקוד שניסיתי:
Application.Current.Shutdown()
התוצאה בתמונה:
ee73c8c1-3183-4057-a1b3-9c967941be63-image.png
בשלב הראשון קיבלתי את ההודעה הראשונה, אחרי חיפושים פתרתי אותה על ידי ההגדרה Tools > Options... > Debugging > General > Suppress JIT optimization on module load
ואז קיבלתי את ההודעה השניה
בשלב הזה התייאשתי מכיוון זה
ייתכן שיש מקרים של תקיעה שבהם זה כן יכול לעבוד
כיוון נוסף שחשבתי:
הצורה שווינדוס מטפלת באירוע ctrl+c בקונסול, שונה מהטיפול באירועיים "גרפיים". בקונסול כאשר לוחצים ctrl+c, ווינדוס יוצרת ת'רד חדש בתהליך ובתוך הת'רד החדש קורא למטפל באירוע.
(מתועד פה: https://learn.microsoft.com/en-us/windows/console/handlerroutine)
אם ככה, גם תהליך שלא מגיב לאירועים גרפיים אמור להגיב ל-ctrl+c בקונסול!
יצרתי פרוייקט נסיון
החלקים הרלוונטיים:
בקובץ ה-csproj הוספתי ככה (כתבתי את זה ידני, לא מצאתי דרך לעשות את זה ב-UI)
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputType>Exe</OutputType>
</PropertyGroup>
כלומר: במצב דיבוג - תיצור תוכנת קונסול (ההשלכה היחידה שאני מכיר הוא שזה פותח חלון שחור של קונסול במקביל לחלון הרגיל - ועוד הבדל טכני עדין שלא נוגע פה, בקיצור זה לא אמור להזיק לכלום)
בקובץ app.xaml.cs:
public void App_Startup(object sender, StartupEventArgs e)
{
#if DEBUG
Console.CancelKeyPress += (s, e) =>
{
// Do cleanup
};
#endif
}
}
ניסיתי את הקוד ונראה שזה פועל כרצוי
⚠ אבל שים לב: מכיון שהקוד ב-CancelKeyPress רץ בת'רד נפרד, ייתכנו השלכות לא צפויות! ראה הוזהרת!
נ.ב בהתחלה חשבתי שאוכל לכתוב בתוך ה-CancelKeyPress רק את השורה Application.Current.Shutdown ואז להסתמך על אירוע Exit לעשות את הנקיון, אבל מתברר שאירוע Exit מטופל על ידי הת'רד הראשי, ואם הוא תקוע זה לא יתבצע
נהניתי מחקירת הנושא
אשמח להערות רעיונות ושיפורים