windows 异常关闭处理

近日在工作中,接手一个项目,程序运行起来后偶发性间隔几个小时或几天就会出现如下(图1, 图2)的”xx程序已停止工作”的提示窗口,这时需要用户手动点击”关闭程序”按钮,进程才会退出。

图1

 

图2

 

当然最好的解决办法就是找出程序中导致”程序错误”的原因,但由于对接手的项目不是很熟悉,再加上时间紧迫,难以在短时间找到问题原因,于是给此程序添加一个”守护程序”(即: 检测到进程退出后就自动重启)。

但程序崩溃时,弹出的”xx程序已停止工作”导致程序进程无法退出,“守护程序”自然也起不到相应的作用。 

在网上查找了一番,终于找到两种解决方法:

第一种方法
运行注册表编辑器,依次定位到HKEY_CURRENT_USER\Software\Microsoft\Windows\WindowsError Reporting,在右侧窗口中找到并双击打开DontshowUI,然后在弹出的窗口中将默认值“0”修改为“1”。

那么,当程序崩溃时,就不会再出现”xx程序已停止工作”的提示框,崩溃程序进程会自动退出。

这种修改系统注册表的方法是最方便和直接的,但会对所有程序生效,如果特别注重系统的安全性,只想让指定的程序在崩溃时不出现”xx程序已停止工作”,请参考”第二种方法”。

图3

第二种方法
查看Windows任务管理器(图4)发现,程序崩溃时之所以出现”xx程序已停止”工作,是因为触发了”Windows的错误报告”机制,在我的系统(Windows 10 64位)任务管理器进程列表中会出现一个名称为”Windows问题报告”的进程,点击此进程左侧的”下拉箭头”,会出现一个窗口列表,此窗口列表就代表了当前所有弹出”xx程序已停止工作”的窗口(图5),而窗口标题就是我们崩溃程序的进程名。

图4

图5 

 

看到此,不知道你是否已经有了启发。

解决思路如下:

在”守护程序”中定期检测Windows系统进程列表中是否出现”WerFault

.exe”进程(“Windows问题报告”的进程名), 如果出现, 则查找”WerFault.exe”进程下的窗口名称是否存在”要守护程序的进程名”, 如果存在,则表示“要守护的程序崩溃并出现已停止工作”的提示框, 那么则向“WerFault.exe”进程下的“窗口”发送 WM_Close 消息,关闭此“提示窗口”,如此, “要守护的程序进程就会完全退出”, 守护程序就可以重新启动此程序了。

 

其实就是用程序模拟“用户手动关闭‘已停止工作’窗口。

#include <windows.h>
#include <tlhelp32.h> //声明快照函数文件
#include "stdio.h"
#include <cstring>
 
// 根据进程ID, 返回指定进程下"第一个"窗口的窗口句柄
// 注: 此程序还不够完善, 因为指定进程下可能有多个窗口
HWND GetWindowHandleByPID(DWORD dwProcessID)
{
    HWND h = GetTopWindow(0);
    while (h)
    {
        DWORD pid = 0;
        DWORD dwTheardId = GetWindowThreadProcessId(h, &pid);
 
        if (dwTheardId != 0)
        {
            if (pid == dwProcessID /*your process id*/)
            {
                // here h is the handle to the window
                return h;
            }
        }
 
        h = GetNextWindow(h, GW_HWNDNEXT);
    }
 
    return NULL;
}
 
int main(int argc, char *argv[])
{
    PROCESSENTRY32 pe32;
    
    //在使用这个结构之前,先设置它的大小
    pe32.dwSize = sizeof(pe32);
    
    //给系统内的所有进程拍一个快照
    HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 
    //Includes the process list in the snapshot
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        printf("CreateToolhelp32Snapshot 调用失败! n");
        return -1;
    }
 
    //遍历进程快照,轮流显示每个进程信息
    BOOL bMore = ::Process32First(hProcessSnap, &pe32);
    while (bMore)
    {
        /*printf(" 进程名称为:%s\n", pe32.szExeFile);
        printf(" 进程ID为:%u \n\n", pe32.th32ProcessID);*/
 
        if (_stricmp(pe32.szExeFile, "werfault.exe") == 0)
        {
            printf(" 进程名称为:%s\n", pe32.szExeFile);
            printf(" 进程ID为:%u \n\n", pe32.th32ProcessID);
 
            HWND hwnd = GetWindowHandleByPID(pe32.th32ProcessID);
            if (hwnd)
            {
                char szText[256] = { 0 };
                GetWindowText(hwnd, szText, 256);
                // 自己崩溃程序的"进程名"
                if (_stricmp(szText, "myProcessName.exe") == 0)
                {
                    printf("Text: %s\n\n", szText);
 
                    // 关闭"xx程序已停止"提示窗口
                    SendMessage(hwnd, WM_CLOSE, NULL, NULL);
                }
                
            }
        }
 
        //遍历下一个
        bMore = ::Process32Next(hProcessSnap, &pe32);
    }
    //清除snapshot对象
    ::CloseHandle(hProcessSnap);
    return 0;
}
 

补充
此程序还不够完善,因为对于下面方法: 

HWNDGetWindowHandleByPID(DWORD dwProcessID); 

其根据进程ID,返回指定进程下"第一个"窗口的窗口句柄,但一个进程下可能会有多个窗口(如图6)。

图6

 

但对“WerFault.exe”进程,我在测试中发现(测试系统:Windows10 64位),当有多个程序出现”已停止工作“提示窗口时(图7),每个程序会各自对应一个”WerFault.exe”进程(图8)。即: 每个WerFault.exe进程下只会出现一个“已停止工作”窗口标题。

当然其他Windows系统我没有测试是否也是这样,以后有时间再进一步完善此程序。

图7

 

图8
--------------------- 
作者:清海风缘 
来源:CSDN 
原文:https://blog.csdn.net/liuhhaiffeng/article/details/52447266/ 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值