当前位置:C++技术网 > 精选软件 > win32模拟程序空闲时执行病毒扫描代码实现

win32模拟程序空闲时执行病毒扫描代码实现

更新时间:2015-12-26 20:50:27浏览次数:1+次

    很多时候,我们希望利用程序空闲的时候做一些事情,比如杀毒扫描木马、磁盘碎片整理、后台统计处理大量的数据。在程序界面操作忙的时候,就不要做这些事情了。因为做这些事情很耗时而且可能很耗CPU或者硬盘,就会导致操作的卡顿。所以我们更倾向于将这些事情在程序空闲时来处理。这样在用户操作的时候就不处理,这样用户体验也好些。反正这些事情都不是很紧急,也不是一下子做的完的,那么利用程序空闲时做也能提高CPU的利用效率,一举两得。
    那么我们首先要知道什么是程序空闲。或者说,程序空闲的状态是什么状态呢?我们先来解释这个概念。
    win32是基于消息的处理系统,所以,程序在忙的时候就是在处理各种各样的消息。而程序空闲时,自然就是没有消息处理咯。那么,没有消息处理的时候,程序在干嘛呢?
    win32的主函数中就有一个消息循环,代码如下:
while (GetMessage(&msg,NULL,0,0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
    GetMessage函数如果从消息队列中获取的消息是WM_QUIT就表示程序退出,就返回0,这样whille循环就结束,然后主程序就执行完毕而退出,程序就退出了。
    而程序空闲时就是消息队列中没有消息,此时并不是表示程序退出了哦。而是表示,GetMessage取不到消息而已。取不到消息并不会让函数返回0的。GetMessage只会在取到WM_QUIT时才会返回0,其他情况都是返回非零值。所以,即使消息队列没有消息,循环还在继续,这样程序还是在运转着。
    而操作系统可能会对这样的没事干的程序挂起来,挂在“天花板”上,不让它占用CPU了。等程序的消息队列中有消息的时候,系统才会再将它从“天花板”放下来处理消息。
    当然,并不是说程序一空闲就被挂起来了的。实际上,程序处理消息是极快的,大部分时间都在休息的。然而不能一休息就挂起来吧。这样还不把系统累死。系统一般是给程序一定时间,如果长时间的不干活(处理消息)的话,才会把他挂起来。至于多久空闲挂起来,就和系统执行的策略有关了。我们这里就不必关心这个问题了,有兴趣可以看看Windows操作系统实现相关的书吧。
    既然程序的空闲是这么的多,不利用起来真是有点浪费。而且对于一些不紧急的而且很耗时间的事情,给程序空闲时处理是非常不错的想法。这样用户在使用的时候可以及时响应用户,体验也很好。
    所以,我们要利用程序空闲时间,就从消息循环着手了。自然,如果还是使用GetMessage你是无法下手的。程序空闲的时候,也就是消息队列没有消息的时候,而没有消息的话,GetMessage就不会返回。也就是程序的控制一直在GetMessage函数内部。GetMessage会一直等待消息,拿不到消息绝不回来的。而你的程序正好就是空闲的时候,是不可能有消息的。如此一来,就杠上了。GetMessage不回来,也就是CPU控制权你无法得到,你的代码就无法在GetMessage后面执行。那么你还如何利用空闲时间?因为你连执行代码的机会都没有。只要程序空闲着,就相当于卡在了GetMessage函数里。而这个函数是系统API函数,你是无法干涉它内部的执行的。
    这么一来,你就得使用另外的函数了。那就是PeekMessage,这个函数就是去巡视下消息队列。不管消息队列有没有消息,都会返回来,让你的代码继续往后执行。如果PeekMessage返回的值告诉你,消息队列没有消息了。也就表示,程序现在是空闲的,你可以开始执行空闲处理代码了。如果消息队列有消息,那么返回值就是非零,如果消息队列没有任何消息,就返回0。
    那么我们可以判断PeekMessage的返回值,就知道程序是否空闲了。如果不是空闲就执行原来正常的消息处理流程,否则就执行我们的代码。下面是代码逻辑:
while (TRUE)
{
    if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    {
        if (msg.message==WM_QUIT)
        {
            break;//退出循环,结束程序
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else
    {
        //执行空闲处理代码
    }
}
    PeekMessage函数的前面四个参数和GetMessage的一样,最后一个是指明是否移除消息。因为PeekMessage是去查看消息,查看的话不一定要处理。如果你只是查看而不处理当前的消息,就使用PM_NOREMOVE。如果你要和GetMessage函数一样处理的话,就要指定PM_REMOVE。然而,PeekMessage的返回值只代表消息队列是否有消息,所以对于WM_QUIT没有特别的待遇了。WM_QUIT就是其中一个消息而已。然而它实际上却代表了退出程序的意思。所以我们要单独来处理WM_QUIT,处理的方式就是退出循环即可。
    然后分析到此处,我们就是要说到执行空闲代码的时候了。这里的代码要执行什么,那就是你要做的事情了。整个逻辑思路都分析完了。
    不过为了完整性,我们这里就还是用一个动态提示的效果来作为空闲处理。对于动态提示文字效果本身的分析,请阅读《win32使用计时器实现动态的等待提示字符效果大全(组图) 》和《win32不使用计时器实现动态文字提示的效果》。
    我们这里就是利用延时和让窗口客户区重绘擦除背景来显示动态的效果。而持续的输出提示文字,则是PeekMessage每次取消息的结果促使文字输出的。因为空闲是大量的状态,所以这个提示也就持续不断的输出了。通过这个程序,你可以发现,程序竟然基本都是空闲的哦!希望本文的分析,会让你对win32的消息机制有更加深入的理解哦。

    下面看看我们利用空闲来输出的提示的效果:

程序空闲时间的输出动态提示效果

【程序空闲时间的输出动态提示效果】
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    TCHAR Info[100]=_T("【C++技术网http://www.cjjjs.com】");
    PAINTSTRUCT ps;
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass)) return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,600,500,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (TRUE)
    {
        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
            if (msg.message==WM_QUIT)
            {
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            #define COUNT 8
            static int iCount=0;
            static TCHAR Dot[COUNT][10]={_T("→"),_T("↘"),_T("↓"),_T("↙"),_T("←"),_T("↖"),_T("↑"),_T("↗")};
                    
            //空闲扫面
            HDC hdc = GetDC(hwnd);
            SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
            TCHAR Tip[100]=_T("");
            wsprintf(Tip,_T("正在执行空闲时扫描病毒%s"),Dot[iCount++%COUNT]);
            RECT rect;
            GetClientRect(hwnd,&rect);
            TextOut(hdc,rect.right/4,rect.bottom/3,Tip,lstrlen(Tip));
            ReleaseDC(hwnd,hdc);
            Sleep(150);
            InvalidateRect(hwnd,NULL,TRUE);
        }
    }
    return msg.wParam;
}