1. 程式人生 > >windows程式崩潰對話方塊和異常處理

windows程式崩潰對話方塊和異常處理

    經常碰到某些程式崩潰時彈出帶紅色叉叉的錯誤視窗或者是叫你選擇除錯或關閉的視窗,很礙眼。不過平時也沒去理它,點掉就好。


    今天客戶反映我們的程式崩潰後就起不來了,其實我們為了方便無人化管理,做了一個守護程序。如果程式異常退出就會重啟那個程式,這在linux下沒問題,程式崩潰了就直接退出返回非零值,但是window就bug了,搞不好就給你彈出個錯誤對話方塊,你不點掉其實程式就沒退出,守護程序就不知道這個程式是否崩潰,於是這個程式就永遠死在那個視窗上了。現在這不僅礙眼,還礙事!於是著手擺平之。

    先是晚上搜到可以修改登錄檔來組織程式或系統的彈出對話方塊,參考:http://technet.microsoft.com/en-us/library/cc976167.aspx。不過這不可行,我們只是希望我們的程式不會彈出對話方塊,儘量少改系統的。而且試了下發現還是會彈出來,就是那個werfault.exe程序,xp下可能不會。算了,這條路不走了。
    用程式碼肯定也有辦法解決。你看人家qq什麼的奔潰了有彈出的都是自家的溫馨提示,我們不需要溫馨提示,只要返回非零值就好。
    萬能的Google一下子就搜出結果來了。原來Microsoft對c和c++進行了擴充套件,支援異常處理,而且貌似標準c++裡的異常處理也是它的一個封裝。Microsoft的異常處理函式是__try
,__except

先試了這麼個簡單的例子
#include <windows.h>
#include <excpt.h>
#include <stdio.h>

#define  CRASH_SILENTLY 1
#if defined(_MSC_VER) && CRASH_SILENTLY
#include <excpt.h>
#define Q_TRY_BEGIN     __try {
#define Q_TRY_END       }
//EXCEPTION_EXECUTE_HANDLER
#define Q_EXCEPT        __except(EXCEPTION_EXECUTE_HANDLER) { \
    printf("Shit happens!\n");fflush(NULL); \
    return 1;}
#else
#define Q_TRY_BEGIN
#define Q_TRY_END
#define Q_EXCEPT
#endif

int main(int, char**)
{
Q_TRY_BEGIN
    int *a = 0;
    *a = 0;
Q_TRY_END
Q_EXCEPT
    printf("Exiting 0...\n");
    fflush(NULL);
    return 0;
}

    如果把CRASH_SILENTLY定義為0,那麼在程式崩潰就會彈出對話方塊,設為一就只打印Shit happens!然後就返回。
    __except的引數有三種,詳細內容見http://msdn.microsoft.com/en-us/library/s58ftw19%28v=vs.80%29.aspx,我就不抄了。
    其實為什麼系統會彈出這麼一個對話方塊呢?其實在vc執行庫中頂層函式也用了__try, __except的異常捕獲機制。不知您看了__except的引數了沒,我的示例程式裡是EXCEPTION_EXECUTE_HANDLER,表示異常被識別,就在__except後面的程式碼段進行異常處理。如果是EXCEPTION_CONTINUE_SEARCH,那麼異常會繼續被派發到外層,這最外層就是vc庫,vc庫它的處理手段就是礙眼又礙事的對話方塊!

    上面這個程式只是演示用的,很簡單。然後我就滿懷希望地對公司的程式也做了類似的處理,然後悲劇發生了,竟然編譯都通不過!編譯錯誤是C2712:cannot use __try in functions that require object unwinding。於是又google了一番。msdn真的很棒,資料豐富,這下有時msdn上的方法解決的。詳見http://msdn.microsoft.com/en-us/library/xwtb73ad%28VS.80%29.aspx
    With /EHsc, a function with structured exception handling cannot have objects that require unwinding (destruction).
    我們的程式裡出現了有解構函式的物件,同時編譯引數又有/EHsc,於是出現編譯錯誤了。可以參考下這篇文章http://se.csai.cn/ExpertEyes/No163.htm
    作為一個例子,如果我們把上面的程式改成下面的就可能出現上述問題
class Shit {
public:
    Shit() {}
    ~Shit() {}

};

int main(int, char**)
{
Q_TRY_BEGIN
    Shit s;
    int *a = 0;
    *a = 0;
Q_TRY_END
Q_EXCEPT
    printf("Exiting 0...\n");
    fflush(NULL);
    return 0;
}
    msdn提出3種方案,允許我複製下
    Move code that requires SEH to another function.
    Rewrite functions that use SEH to avoid the use of local variables and parameters that have destructors. Do not use SEH in constructors or destructors.
    Compile without /EHsc.
    顯然前兩種辦法對程式碼改動太大了,不可取,那麼就去掉/EHsc吧。由於我是用Qt寫程式,有些編譯選項都是預設設好的,我在pro檔案裡嘗試定義QMAKE_CXXFLAGS竟然無效,不是很清楚為什麼。一般是在qmake.config和prf檔案裡裡可以找到。qmake.conf裡找到相關的兩行
    QMAKE_CXXFLAGS_STL_ON   = -EHsc
    QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc
在我們工程檔案裡直接設這兩個為空竟然可以。後來又看了下Makefile,發現生成Makefile會依賴exceptions.prf, stl.prf,而這兩個會加入上面兩個變數,比如stl.prf:
CONFIG -= stl_off
QMAKE_CFLAGS *= $QMAKE_CFLAGS_STL_ON
QMAKE_CXXFLAGS *= $QMAKE_CXXFLAGS_STL_ON

於是在工程檔案中加入
CONFIG -= exceptions stl
或者
CONFIG += exceptions_off stl_off


就解決問題了,而且比之前的方法優雅。看看Makefile裡相關程式碼變成了
$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\default CONFIG+=release -o Makefile pvplayer.pro
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\qconfig.pri:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\modules\qt_webkit_version.pri:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt_functions.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt_config.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\exclusive_builds.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\default_pre.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\default_pre.prf:
..\config.pri:
..\pvcommon\pvcommon.pri:
..\config.pri:
..\log4qt\log4qt.pri:
..\config.pri:
..\qextserialport\qextserialport.pri:
..\config.pri:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\release.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\debug_and_release.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\default_post.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\default_post.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\rtti.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\shared.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\embed_manifest_exe.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\embed_manifest_dll.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\warn_on.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\qt.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\thread.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\moc.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\windows.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\stl_off.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\win32\exceptions_off.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\resources.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\uic.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\yacc.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\lex.prf:
..\..\..\..\QtSDK\Desktop\Qt\4.7.4\msvc2008\mkspecs\features\incredibuild_xge.prf:
e:\QtSDK\Desktop\Qt\4.7.4\msvc2008\lib\qtmain.prl:
    

    好,至此已經把彈出對話方塊的問題解決了。不過還值得深入研究,目前只是做到了會用的程度。還有就是linux下或其他平臺上有無類似處理還沒調查。應該也有,因為最近linux下的thunderbird一啟動就崩潰,彈出對話方塊。有空繼續研究。

參考文獻:
http://msdn.microsoft.com/en-us/library/s58ftw19%28v=vs.80%29.aspx
http://msdn.microsoft.com/en-us/library/xwtb73ad%28VS.80%29.aspx
Use /EHa if you want to catch an exception raised with something other than a throw.
http://msdn.microsoft.com/en-us/library/1deeycx5%28VS.80%29.aspx
http://blog.csdn.net/bichenggui/article/details/4536534
http://se.csai.cn/ExpertEyes/No163.htm


相關推薦

windows程式崩潰對話方塊異常處理

    經常碰到某些程式崩潰時彈出帶紅色叉叉的錯誤視窗或者是叫你選擇除錯或關閉的視窗,很礙眼。不過平時也沒去理它,點掉就好。     今天客戶反映我們的程式崩潰後就起不來了,其實我們為了方便無人化管理,做了一個守護程序。如果程式異常退出就會重啟那個程式,這在linux下沒

程式語言中的那些異常處理錯誤——小菜

  作為一個小菜的我,雖然學業不精,但是到現在已經學習過程式語言Visual Basic、後來又利用一小點時間自學過C++、這些天接著又見識了C#……         那時候還沒有深刻的體會好好學習

多態異常處理的完美結合

iostream obi namespace cte del err size turn pre #include<iostream> using namespace std; class MyArray { public: MyArray(int m_l

八、python操作excel及網絡編程異常處理

size let finally 必須 新的 異常信息 屬性 開發 tar 一、python操作excel 1、讀excel,xlrd模塊用來讀excel # book = xlrd.open_workbook(r‘students.xlsx‘)#打開excel# prin

小議C#錯誤調試異常處理

才幹 avi blank {} sni 沒有 ng- fill back 在程序設計中不可避免地會出現各種各樣的錯誤,在編寫代碼時須要盡量避免。在處理錯誤時,首先應該分析錯 誤的類型,找出出錯的原因才幹解決錯誤。 錯誤的分類

Head First Python 學習筆記-Chapter3:文件讀取異常處理

獲取 for循環 文件 處理 pyhton find ont ren app 第三章中主要介紹了簡單的文件讀取和簡單的異常處理操作。 首先建立文件文件夾:HeadFirstPython\chapter3,在Head First Pythong官方站

Java語言中的----多態異常處理

java語言中的----多態和異常處理day13 Java語言中的----多態和異常處理一、概述: 學習Java語言就要理解Java中的面向對象的四大特征:分別是封裝、抽象、繼承、多態。前面三個我們已經學完了,下面我們來學一下多態。什麽是多態?不明思議就是具有兩種形態性,一個方法可以定義兩種形態,這就是

簡述PHP7的error異常處理

continue final ret new span 數值 cti php 報告 看看 try catch 的作用,try的作用就等同於運行,如果try裏面的代碼運行正常沒用報錯的話,將不會觸發catch代碼塊,如果有的話(如下面的$x為0的時候,函數沒有return回數

兄弟連學Python 錯誤異常處理

嘗試 dex 訪問 port def post 推薦 log 出現 #常見的異常 class Human: #屬性 sex = ‘man‘ age = 18 #方法 def run(self): print(‘跑

PHP錯誤處理異常處理

php 分享 log 9.png 51cto tex process images sha 一、錯誤處理: 代碼: 輸出:二、異常處理: 代碼: 輸出: PHP錯誤處理和異常處理

Python學習(十二)文件操作異常處理以及使用json存儲數據

ice 情況 dataset visio 獲取 大致 一個 百萬 能夠 Python 文件操作和異常處理 Python 文件操作 文件操作步驟 打開文件,打開方式(讀寫) open(file_name) 操作文件(增刪改查) 關閉文件, file_name.cl

錯誤異常處理(7)

為什麽 nbsp 實現 str ron strong 指令 異常處理 處理 配置指令 錯誤日誌 異常處理 為什麽異常處理很方便 PHP的異常處理實現 SPL異常 錯誤和異常處理(7)

Python基礎語法介紹 - 面向對象(下)異常處理

Python3.6.5 面向對象 概述: 上一節主要介紹了面向對象的一些基本概念:類,類的組成元素“方法和屬性”,類的特性“繼承,多態和封裝”。這一節課分為兩部分:(一)類方法及調用,靜態方法及調用,單例類(二)異常處理 第一部分:類方法、靜態方法和單例類 類方法及調用 (1)使用@classmet

Python學習——文件操作異常處理

not ret lease ext title eas err turn with # title = "Alice in Wonderland"# print(title.split())def count_words(filename): ‘‘‘ count ho

Oracle 事務異常處理

回滾 設置 插入 insert set others point exe str Oracle 的異常和回滾 DECLARE dept_no NUMBER (2) := 70; BEGIN --開始事務 INSERT INTO dept

約束異常處理 20

asi acl clas ror logging模塊 多文件 約束 inf con 異常處理(處理,拋出異常,自定義異常)   1. 產生異常, raise 異常類(), 拋出異常   2.處理異常:    try:       xxxx # 嘗試執行的代碼    exce

錯誤異常處理

選項 般的 out err 語法糖 stop 請求 特性 rect Python有兩種錯誤很容易辨認:語法錯誤和異常。 1 什麽是異常? 異常即是一個事件,該事件會在程序執行過程中發生,影響了程序的正常執行。 一般情況下,在Python無法正常處理程序

模式對話方塊非模式對話方塊、accept()函式、exec()函式,Accepted訊號區別

一.非模式對話方塊   非模式對話方塊是和同一個程式中其它視窗操作無關的對話方塊。在字處理軟體中查詢和替換對話方塊通常是非模式的來允許同時與應用程式主視窗和對話方塊進行互動。呼叫show()來顯示非模式對話方塊。show()立即返回,這樣呼叫程式碼中的控制流將會繼續。   非模式

Python異常異常處理

Python異常和異常處理2017年12月20日 22:17:08 Megustas_JJC 閱讀數:114 標籤: python 異常處理 更多 個人分類: Python 版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/Megustas_JJC/arti

IO流(二)異常處理

IO流(二) 1. 流的分類 1.1 按流的流向分類 輸入流和輸出流 輸入流是從其他地方(硬碟、外部儲存、網路等)往記憶體中讀取資料。 輸出流是從記憶體往其他地方(硬碟、外部儲存、網路等)寫入資料。 輸入和輸出流的方向是相對於記憶體而言的 1.2 按流的傳輸單位分類 位元