为系统的所有进程拍个快照吧

windows窗口程序设计学习 专栏收录该内容
1 篇文章 0 订阅

这星期终于windows课开始上机了,略兴奋。终于不止限制于对console了玩耍了~哈哈哈

那么接下来开始对系统内的所有程序拍一个快照~何为快照,照片嘛,自然是不能动的,那么,这个快照的效果就是记录下当年电脑中运行的进程的ID号,和程序名称。

既然是窗口程序,少了窗口那是万万不能的~先给自己写个头文件,声明一个建窗口的几个函数吧(表示是老师要这样在头文件里进行声明,我并不理解这有什么用,函数在CPP文件中的WinMain函数之前进行定义不也可以嘛,也可以先声明写完WinMain之后再写出具体实现嘛,东西还没拿出来就在这里先发一个问吧可怜)。


#ifndef PROCESSENUM_H
#define PROCESSENUM_H

//窗口过程函数
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

//主函数的调用的功能函数


BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);

#endif // PROCESSENUM_H

声明了即将要调用的窗口过程函数,和主函数要调用的两个功能函数。既然这些已经先声明了,那就先把主函数放出来在说这些函数都有什么用吧。


#include <windows.h>
#include "processEnum.h"

int WINAPI WinMain(HINSTANCE hinstance,             // 实例句柄
                   HINSTANCE hPrevInstance,         // 一般此参数不使用
                   LPSTR lpCmdLine,                 // 字符串,不一定在结尾处会有\0
                   int nCmdShow)                    // 显示方式
{
    if(!InitApplication(hinstance))     //应用初始化
        return false;

    if(!InitInstance(hinstance, nCmdShow))  //实例初始化
        return false;

    MSG msg;
    //消息循环,用于从消息队列中取出消息,并做相应处理
    while(GetMessage(&msg, NULL, 0, 0)){  
        // 对消息进行划分,如:区分大小写
        TranslateMessage(&msg);          
        
        // 调用窗口过程函数
        DispatchMessage(&msg);              
    }

    return (int)msg.wParam;
}

虽然上述注释已经把声明的两个函数的左右给写出来了,但还是不太懂的样子。好忧桑,所谓应用初始化和实力初始化还是不太懂,不过没关系,下面会有这两个函数的具体实现,到时候再思考这两个函数到底在干嘛。

现在来看看这个WinMain函数的返回值。

先看WINAPI这个奇奇怪怪的东西,函数的返回值类型是int,函数名是WinMain,那么加在这之间的这个WINAPI,是个什么呢,Google了一下,WINAPI是__stdcall的宏定义,表明WinMain()是__stdcall调用方式,区别于默认的__cdecl,__stdcall调用方式。windows平台下的STDCALL函数调用约定,调用时,参数从右到左压栈,调用完后函数自己平衡堆栈。那么到底是什么东西可以放在函数的返回值类型和函数名之间呢?因为以前这种东西是绝对看不到的,那么解答我上个问题的地方同样解答了我这个问题,能放在返回值类型和函数名的就之后只有调用约定,其他的就不能再加了。而能添加的调用约定有__cdecl   /   __clrcall  /  __stdcall  /  __fastcall  /  __thiscall 。(详情参见http://bbs.csdn.net/topics/320046920)。

再看WinMain到底返回了一个什么东西 (int)msg.wParam,又要说说MSG.wParam的属性了可怜原谅我这个菜B又只能去Google了。

1、在WinMain主函数中,最后的返回值是msg.wParam,这个参数是传递给void PostQuitMessage(int nExitCode);这个函数的参数nExitCode的。

2、nExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数。

3、总之,当接收到一个WM_QUIT消息时,程序就中止。这时,WinMain函数应退出应用程序,并且返回传递给WM_QUIT消息的wParam参数的值。如果由于调用PostQuitMessage函数而接收到WM_QUIT消息,此时WM_QUIT消息的wParam的值即是PostQuiMessage函数的nExitCode的值。nExitCode一般为0。(引用地址http://blog.csdn.net/setflvet/article/details/6983224

好,终于将WinMain这个函数搞定了(尴尬算是搞定了吧,我自己是没什么想法了,希望大家能有什么深层次的东西能给小弟指点一下,感激不尽)。接下来看在头文件中定义的那两个由WinMain函数调用的函数。


BOOL InitApplication(HINSTANCE hInstance){      //应用初始化程序

    WNDCLASS wc;                                //windows类的数据结构

    wc.style           = CS_HREDRAW | CS_VREDRAW;         // UINT 窗口的分布
    // WNDPROC Name of the Window Function 函数指针
    wc.lpfnWndProc     = (WNDPROC)MainWndProc;            
    wc.cbClsExtra      = 0;                               // int
    wc.cbWndExtra      = 0;                               // int
    wc.hInstance       = hInstance;                       // HINSTANCE WinMain函数的第一个参数、
    wc.hIcon           = LoadIcon(NULL, IDI_APPLICATION); // HICON 图表
    wc.hCursor         = LoadCursor(NULL, IDC_ARROW);     // HCURSOR 光标
    wc.hbrBackground   = (HBRUSH)GetStockObject(WHITE_BRUSH);  // HBRUSH 客户区用什么颜色
    wc.lpszMenuName    = NULL;                            // LPCTSTR 菜单
    //此处的TEXT("")中存放的东西必须是window class的名字,否则程序跑不了!
    wc.lpszClassName   = TEXT("processEnum");             // LPCTSTR
    return RegisterClass(&wc);
}

//***************************************************************************************

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){
    HWND hWnd = CreateWindow(TEXT("processEnum"),       // Name of the window class
                             TEXT("processEnumApp"),    // Title of the window
                             WS_OVERLAPPEDWINDOW,       // 窗口可以叠在上面
                             CW_USEDEFAULT,             // initial x position
                             CW_USEDEFAULT,             // initial y position
                             CW_USEDEFAULT,             // initial x size
                             CW_USEDEFAULT,             // initial y size
                             NULL,                      // 没有父窗口
                             NULL,                      // window menu handle
                             hInstance,                 // 句柄语句
                             NULL);                     // creation parameters
    if(!hWnd)
        return FALSE;                                   // 大写对应于BOOL变量
    // 显示窗口, 产生 WM_SIZE消息 和 WM_SHOWWINDOW消息
    ShowWindow(hWnd, nCmdShow);
    // 更新窗口,产生WM_PAINT消息
    UpdateWindow(hWnd);

    return TRUE;
}

有一些编码中遇见的问题都写在代码的注释中去了,不过还是想特意提出一下,InitApplication函数中的这句:wc.lpszClassName   = TEXT("processEnum"); 这里面字符串中的东西必须和 InitInstance函数中的CreateWindow函数里面的第一个参数中写的名字要相同!不然程序跑不了哭还真是除了文件打开处理,第一次遇见这种情况,字符串常量居然能影响程序的运行。(居然没Google出来大哭

再看这句:wc.lpszClassName   = TEXT("processEnum");  这里面的TEXT函数在做什么呢,听老师说了一下,是将字符串进行编码的改编,TEXT不是个函数,是一个宏(T-T,宏到底是什么玩意,#define出来的是宏,怎么现在还有函数形式的宏?这个真心求解),这个宏会自动匹配应用工程的编码方式,将该字符串的编码转换成ANSI或者UNICODE。下面还有一个关于这个宏的问题,下面遇到了再说。


下面要开始处理消息实现功能了,窗口过程函数:

#include <tlhelp32.h>           // 声明快照函数的头文件

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;                            // dc结构体的句柄,用于操作dc结构体

    LPCTSTR wrong = TEXT("CreateToolhelp32Snapshot调用失败!");      // 显示快照失败的内容


    int X = 10, Y = 40;                   // 记录屏幕上的x, y的坐标变化

     PROCESSENTRY32 pe32;

     // 给系统内的所有进程拍快照
     HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

     // 在使用这个结构之前,先设置它的大小
     pe32.dwSize = sizeof(pe32);


    switch (message){
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);    // 绘图时必须调用的函数

        if(hProcessSnap == INVALID_HANDLE_VALUE){
            //hdc = BeginPaint(hWnd, &ps);
            //这句话千万不能重复调用,不然一句都打不出来的,再一次绘图中只能开关一次
            TextOut(hdc, X, 10, wrong, lstrlen(wrong));
            EndPaint(hWnd, &ps);

            //句柄有开就有关嘛,不能忘记清除snapshot对象
            ::CloseHandle(hProcessSnap);
            return -1;
        }

        else{
            LPCTSTR title = TEXT("   进程ID    模块名");
            LPTSTR szBuffer  = new TCHAR[100];
            BOOL bMore = Process32First(hProcessSnap, &pe32);

            TextOut(hdc, X, 10, title, lstrlen(title));

            while(bMore){
                wsprintf(szBuffer, TEXT("   %05x     %s"), pe32.th32ProcessID, pe32.szExeFile);
                //hdc = BeginPaint(hWnd, &ps);
                TextOut(hdc, X, Y, szBuffer, lstrlen(szBuffer));
                if(Y > 600){
                    X += 350;
                    Y = 40;
                    TextOut(hdc, X, 10, title, lstrlen(title));
                }
                else
                    Y += 30;
                bMore = Process32Next(hProcessSnap, &pe32);
            }
            EndPaint(hWnd, &ps);

            delete[] szBuffer;
            break;
        }


    case WM_DESTROY:                //  窗口关闭

        PostQuitMessage(0);

        break;

    default:

        ::CloseHandle(hProcessSnap);
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

    ::CloseHandle(hProcessSnap);
    return 0;
}

根据上文所说,这个CALLBACK那又是一种调用约定啦,这个是按从右至左的顺序压参数入栈。(我找了一下关于调用约定的东西,大家有兴趣就去看下吧,现在网上的资源真是大好http://bbs.ecjtu.org/thread-30113-1-1.html

给系统的所有进程拍快照的话自然调用API函数来进行搞定啦:

HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

这一句给系统内所有进程拍一个快照。好奇怪的说,这一句不能写进switch语句中,会出现错误,这到底是个什么错误?就是不能写在case WM_PAINT:下面,这是个什么问题,求教一下。

BOOL bMore = Process32First(hProcessSnap, &pe32);

bMore = Process32Next(hProcessSnap, &pe32);

这两句可以实现遍历进程快照。然后在函数返回之前,要记得将snapshot对象清除掉。


还有就是这句了wsprintf(szBuffer, TEXT("   %05x     %s"), pe32.th32ProcessID, pe32.szExeFile);

在console中可以用printf函数轻易实现的东西到了窗口打印却行不通了,那就只能换个方法啦(英文不太好,在这附上MSDN的官方说明http://msdn.microsoft.com/en-us/library/windows/desktop/ms647550(v=vs.85).aspx,大家自己去看一下吧),对这个函数不明觉厉,那就先说说自己的看法吧:wsprintf(缓冲区,格式,要格式化的值);
第一个参数是字符缓冲区,后面是格式字符串,wsprintf不是将格式化结果写到标准输出,而是将其写入缓冲区中,

该函数返回该字符串的长度。这么一来像以前console中的格式控制符什么的又都可以用了~但是有一点不明白就

是在这里面微软给的解释是这个函数的第二个参数是LPCTSTR,我自己用出来的感觉就是我把这个参数写成这样"   %05x     %s"是不可以的,编译器给的理由是这个参数是LPCTSTR而不是const char*虽然觉得可能确实是与上面说到的编码方式有关,但还是不太清楚这两个格式有什么却别,Google了一下结果看到了这么个玩意LPCTSTR:常量的TCHAR指针。定义为:typedef const char* LPCTSTR(参见http://blog.sina.com.cn/s/blog_5b09aac301016hx2.html然后就更晕了,在这求个指教吧,谢谢!

最后还有一点就是这两句了hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps);这两句话在一次绘图中是千万不能重复调用的,不然就打印不出来,忧桑的故事,为了这个错误逮着电脑看了一个多小时。恩~这次的收获大概就这些吧,终于写完了。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值