WinCE下应用程序错误的解决之道

简介:        这个对话框,大家应该都不陌生。程序员做开发时经常会见到,用户肯定也曾被它骚扰过。很显然,这是软件的BUG所致。软件中存在的BUG肯定是会出现的,只是时间的问题,或早或晚,有些很幸运在测试时就会被发现,那些不幸的就成了客户抱怨的缘由。
 
       这个对话框,大家应该都不陌生。程序员做开发时经常会见到,用户肯定也曾被它骚扰过。很显然,这是软件的BUG 所致。软件中存在的BUG 肯定是会出现的,只是时间的问题,或早或晚,有些很幸运在测试时就会被发现,那些不幸的就成了客户抱怨的缘由。所以,我们不能抱有侥幸心理,而应该想办法来解决这类问题。

       对于软件的BUG来说,扼杀于摇篮当然是最根本的解决办法。尽量编写没有BUG的代码,必要时主动在代码中添加一些异常处理,让程序决断如何处理。很多语言都提供了异常处理的机制,但BUG似乎只能减少,而不可消灭。在嵌入式系统中,由于硬件及工作状态的差异,有些貌似万无一失的代码也常常出现BUG。所以,编写一个完全没有BUG的软件,是我们的理想与追求,但同时也需要我们做最坏的准备。也许某个三更半夜,就会被一个莫名的BUG折腾得焦头烂额。

       产品发布之前,会有很系统的测试,包括硬件和软件。对一个产品来说,测试的重要性不言而喻。尽可能在测试阶段发现所有的问题,而不要将这些问题留给客户。前两天听开发组的同事惊呼“这个BUG也被你们发现了,你们的测试功夫实在了得”。原来是他调用一函数时用错了一个参数,测试组的同事愣是把它揪了出来。另外一个关于汉字排序出错的BUG,也被测试组发现了。但要不要改,开发组的几个人争得面红耳赤。最后老邓都有些火了,他的意思是即使BUG再不易重现,客户也许从不会碰到,但只要确实有问题,就得Fix掉。另外的人觉得Fix这个BUG,太繁琐,不值得花太多时间。最后估计还是得听老邓的,发现了的BUG一定彻底解决!但测试也只能是解决一部分问题,毕竟还有可能存在暂时没有发现的BUG。这些BUG最终会在客户手上爆发。

       产品发布之后,平静了一段时间,终于有一天,客户抱怨来了,软件有BUG,出现系统崩溃的情况。询问再三,却没有更多的有利于Debug的信息。这不是客户的责任,毕竟他们不是专业的测试人员。要重现这个BUG也非常很困难。不过,幸运的是针对这种情况,WinCE提供了类似于桌面Windows的一套错误报告系统。通过它,我们能把一些软件BUG出现时的情况记录下来,有利于分析BUG的诱因,从而解决BUG。我发现M8似乎就采用了类似的机制,在Disk目录下,会看到一些LOG文件和edb_err.txt文件。

       综上,解决软件BUG的问题,有三道关口,第一关,编写代码时,止于源头,第二关, 系统测试时,斩立决,第三关,用户发现后,须立等可取。这三点说起来简单,实际上都有很大的学问,即所谓道,是需要花大量时间,研习许多资料才能了解的。

       以上说的是正道,下面再说点旁门左道,也是我目前碰到的问题。产品发布了,有少数用户报告有BUG,甚至发来如上所示的图。系统本身是有有看门狗的,但等看门狗复位系统的时间太长,需要几分钟。由于种种原因,现在也不可能到代码中去找错,有些部分甚至是没有源码的。目前的处理机制是,出现如上所示的对话框后,点击“OK”按钮,程序会关闭,然后另外的程序会再运行该出错关闭的程序。所以,我需要做的事情就是如何跳过这个提示对话框,让出错程序直接关闭。简单分析之后,有两个想法,一个是修改WinCE内核,修改异常处理部分的代码,出现此类异常时,直接关闭对应的进程。另一个是写个应用程序,模拟用户点击“OK”按钮的操作。第一种方法似乎可行,在Windows XP中可禁用错误报告,也可禁用通知,但在WinCE下没找到该开关。所以需要修改内核代码,并重新编译,这感觉有点不妥。第二种方法,直截了当,担心的问题是系统额外的消耗。很显然这个程序得一直运行着,并检测出错窗口,一旦出错,马上将其关掉。如果这个程序的系统消耗很小,那也不失为一个缓兵之计。当然,要从根本上解决问题,还得走正道。

       简单写了个Savior.exe,在模拟器上测试了一下,系统消耗基本可以忽略,下图为证,包括了异常出现前后的两个时间段,可以看到,都在0.5%以下。如果能暂时缓解一下问题,这点消耗是完全可以接受的。 

       在模拟器中,配合Crash.exe 测试了一下,基本实现了左道的功能。Savior.exe 的源代码如下:

 

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
#include<windows.h>

//定义出错类型,列举所有出错提示框的信息
const TCHAR *szErrorInfo[] = 
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
    _T(
"致命的应用程序错误"),
    _T(
"应用程序错误"),
    _T(
"Fatal Application Error"),
    _T(
"Application Error"),
    NULL,
}
;

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   
int       nCmdShow)
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
    HANDLE hMutex 
= CreateMutex(NULL,FALSE,_T("SAVIOR"));
    
if (hMutex)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        
if(ERROR_ALREADY_EXISTS == GetLastError())
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
{
            
return FALSE;
        }

    }


    TCHAR szPath[
256];
    
while (1)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        HWND hWnd 
= NULL;        
        
for (int i = 0;szErrorInfo[i];i++)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
{
            
if (szErrorInfo[i])
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
{
                hWnd 
= FindWindow(NULL,szErrorInfo[i]);
                
if (hWnd)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                
{
                    
//查找到出错提示对话框
                    DWORD dwProcessID;
                    
                    
//获取出错进程ID
                    GetWindowThreadProcessId(hWnd,&dwProcessID);
                    
                    
//获取出错进程句柄
                    HMODULE hProc = (HMODULE)OpenProcess(0,FALSE,dwProcessID);
                    
if (hProc)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
{
                        
//获取出错进程对应的EXE
                        GetModuleFileName(hProc,szPath,255);
                    }

                    
                    
//关闭出错提示对话框
                    SendMessage(hWnd,WM_CLOSE, 00);
                    Sleep(
3000);

                    
//重新启动出错应用程序
                    PROCESS_INFORMATION pi;    
                    
if (CreateProcess(szPath,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&pi))
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
{
                        CloseHandle(pi.hProcess);
                    }

                }

            }

            Sleep(
100);
        }
        
        Sleep(
1500);
    }

    
return TRUE;
}

      由于Crash.exe 是一启动就出错的程序,所以,两个程序一起测试时,会陷入一个循环,出错重启,还出错还重启。在实际的项目中应该避免该情况,可以增加一个黑名单的功能,如果重启次数超过5 次,就将该程序列入黑名单,关闭后不再重启。另外,针对出错信息形形色色,可以将其写入到文件或注册表中,便于后续增加错误信息的定义。左道的实际效果如何,还需拿到真机上测试。在某些无头设备中,用户没有办法点击弹出的出错提示框时,左道也能发挥作用,似乎还有些不可替代。

       WinCE下应用程序错误的解决之道,漫漫,可正,可邪,须上下求索。

目录
相关文章
|
12月前
|
存储 缓存 定位技术
分享5款会带来意想不到效果的软件
有时候一些小工具,能给你带来一些意想不到的效果,我们来看看下面这5款工具,你又用过其中几款呢?
76 0
|
安全 Linux 编译器
linux下c语言内存检测神器asan,专治各种疑难杂症
linux下c语言内存检测神器asan,专治各种疑难杂症
linux下c语言内存检测神器asan,专治各种疑难杂症
|
数据安全/隐私保护
分享五款没什么名气却意外好用的软件
噔噔噔噔,作为一个黑科技软件爱好者,电脑里肯定是不会缺少这方面的东西,今天的5款优质软件闪亮登场了。
162 0
分享五款没什么名气却意外好用的软件
|
缓存 小程序 安全
小程序逆向分析 (二) 跑起来
小程序逆向分析 (二) 跑起来
小程序逆向分析 (二) 跑起来
|
小程序 JavaScript 安全
小程序逆向分析 (一)
小程序逆向分析 (一)
小程序逆向分析 (一)
|
程序员 C语言 Windows
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在
98 0
Win知识 - 程序是怎样跑起来的——要意识到操作系统的存在
|
存储 SQL Web App开发
你们的系统真的安全吗?你们系统是不是也有这种诡异的情况呢?
这个文章来源灵感是公司的项目在安全检查的时候,发现了很多 SQL 注入的一些问题还有一些 XSS 攻击问题,SQL 注入我们都是比较了解的,那么什么是 XSS 攻击呢?测试反馈给我的时候我是一脸懵逼呀,现在我们就来说一下什么是 XSS 攻击,以及我们怎么防止它的出现。