zoukankan      html  css  js  c++  java
  • 转载一下经典的the Forgers伪造者win32教程

    http://winprog.org/tutorial/zh/message_loop_cn.html

    好像很多人都不知道这个经典的教程,转载其中一章打打广告。

    theForger's Win32 API教程第二版(简体中文)

    主页

    基础
    1. 开始学习
    2. 一个简单的窗口
    3. 处理消息
    4. 理解消息循环
    5. 使用资源
    6. 菜单和图标
    7. 对话框
    8. 非模态对话框
    9. 标准控件
    10. 对话框常见问题
    创建一个简单应用
    1. 在运行时创建控件
    2. 文件与常用对话框
    3. 工具栏与状态栏
    4. 多文档界面
    图形设备接口
    1. 位图,设备上下文
    2. 透明位图
    3. 定时器与动画
    4. 文本,字体与顏色
    工具与文档
    1. 参考
    2. 免费的Visual C++(最新更新)
    附表
    1. 常见错误的解決方法
    2. API vs. MFC
    3. 关于资源文件的说明

    理解消息循环

      在写任何有实际价值的程序之前,都要理解整个消息循环和windows程序传递消息的结构.当前为止我们已经试了一些消息的处理,我还应该更进一步的看一下这个过程, 因为你如果不理解它们的话,后面的內容将会对你很难

    什么是消息?

      一个消息就是一个整数.如果你到头文件中看一下(了解API的好地方)你就会发现这样的內容

    #define WM_INITDIALOG                   0x0110
    #define WM_COMMAND                      0x0111
    
    #define WM_LBUTTONDOWN                  0x0201
    

    ...

    等等..消息用来进行windows系统中的所有通信,至少在基本方面是这样的.如果你想要你的窗口或是控件(其实就一种特別的窗口)做点什么你就给它发个消息. 如果另外一个窗口要你做点什么它也发给你一个消息..如果发生了用戶按动了键盘,移动了鼠标,点击了一个按钮之类的事件,系统就向相关的窗口发送消息.你要是就是那个被传至消息的窗口,你就要处理这些消息

      每个windows消息可能拥有至多两个参数,wParam和lParam.最初wParam是16bit,lParam是32bit,但在Win32平台下两者都是32bit.不是每个消息使用了这些参数,而且每个消息以不同的方式来使用.比如,WM_CLOSE不使用它们任一个,所以你应该忽略它们.WM_COMMAND消息两个都使用,wParam有两个部分,HIWORD(wParam)中含有提示消息(如果有的话),LOWORD(wParam)含有发送消息的控件或菜单的标识号.lParam含有发送消息的控件的HWND(窗口的句柄)或者为NULL,当消息不是由控件发送

      HIWORD()和LOWORD()是windows定义的两个宏,用来从一个32bit值中分离出高字(0xffff0000)和低字(0x0000ffff)的两字节.在Win32中,一个WORD是16bit,所以一个DWORD为32bit

      可以用PostMessage()或SendMessage()来发送消息.PostMessage()把消息放入消息队列再立即返回.就是说你调用了PostMessage()后消息可能被处理了,也可能还沒有被处理. SendMessage()则真接把消息送往窗口并且在窗口沒有结束处理消息之前不返回.如果我们想关闭一个窗口我们可以发送一个WM_CLOSE消息:PostMessage(hwnd,WM_CLOSE,0,0);这跟我们点击窗口顶部的 [x] 按钮一样的效果.注意wParam和lParam都为0.这是因为我们刚才说了WM_CLOSE并不用它们.

    对话框

      一旦你开始使用对话框,你将需要向此控件发送消息以与它们通信.你可以先使用GetDlgItem()来用ID得到控件的句柄然后用SendMessage(),也可以直接用SendDlgItemMessage()这个一步到位的函数.你给它一个窗口的句柄和一个子窗口的ID,它就会得到字窗口的句柄并向它发送消息.SendDlgItemMessage()和类似的API,如GetDlgItemText()可以用在所有的窗口上面,而不是仅仅在对话框上.

    什么是消息队列

      打个比方,你正在处理WM_PAINT消息,此时突然用戶在键盘上敲了一大堆的东西.这时候会怎样?你应该中止你的工作去响应键盘的输入,还是简单地把这些输入给忽略掉? 错!显然两种方式都不能接受,所以我们引入了消息队列的概念,消息被发送时就被放入队列,被处理后就从队列中删除.这就保证了你不会丟掉消息,你在处理某个的时候,另外的就在队列中等待你来取走它们.

    什么是消息循环

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    
    1. 消息循环调用了GetMessage(), 它到你的消息队列中去看.如果队列是空的你的程序就在那里等(阻塞在那里).

    2. 当一个事件发生导致一个消息加到队列中去(比如系统注冊了一次鼠标点击)GetMessage()就返回一个正值表示有一个消息待处理,并且它将我们传递的MSG结构体填充.如果遇到了WM_QUIT它就返回0,如果有错误发生就返回负值

    3. 我们拿到信号(在Msg变量中)并传给TranslateMessage(),它进行一些额外的处理,将虛键值转为字符信息.这一步其实是可有可无的,但是有些地方会依赖这个步骤

    4. 一旦上面的工作完成了我们把消息传给DispatchMessage().DispatchMessage()先看看信号是给哪个窗口的,再找到那个窗口的窗口过程. 再调用那个过程,参数为窗口的句柄,消息,wParam和lParam

    5. 在你的窗口过程中,你得到了那些参数,就可以为所欲为了.如果你沒有处理某些特定的消息,那你就调用DefWindowProc()来为你做一些默认的操作(一般就是什么都不做).

    6. 一旦你完成了对消息的处理,你的窗口过程就返回了,DispatchMessage()返回了,我们就再次循环

    这是windows程序中一个非常重要的概念..你的窗口过程并不是由系统来神奇地调用的,实际上你在DispatchMessage()中自己间接地调用了它.如果你愿意,你可以对消息调用GetWindowLong()得到它的窗口过程再直接调用它

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        WNDPROC fWndProc = (WNDPROC)GetWindowLong(Msg.hwnd, GWL_WNDPROC);
        fWndProc(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);
    }
    

      我对前面的例子用了这种方法,可以工作,但是有很多的方面这种方法沒有注意到,比如Unicode/ANSI转換,时钟回调函数等等,它很可能在我们的简单试验中可以工作.所以试下就可以了,不要在实际的代码中用它:)

      注意我们用GetWindowLong()来从窗口来查找它的窗口过程.为什么我们不直接调用WndProc()?因为我们的消息循环为我们程序中的所有窗口的消息服务,包括按钮,列表框这样拥有自己的窗口过程的窗口,所以我们要我们调用了正确的窗口过程.因为多个窗口可能使用一个窗口过程, 第一个参数(窗口的句柄)告诉窗口过程某个消息是为那个窗口的

      你可以看到,你的应用程序的主要时间就是在消息循环这里打转,你很高兴地向那些快乐的窗口发消息让他们处理.如果你要退出程序你怎么办?因为我们使用了一个while循环,如果GetMessage()返回了FLASE(就是0),循环就结束我们就可以到WinMain()的结束点.这就是PostQuitMessage()做的工作.它向队列发送一个WM_QUIT消息,GetMessage()就向Msg结构体填充数据并返回0,而不返回正的值. 这个地方,Msg的wParam成员含有你传向PostQuitMessage()的数据,你可以忽略它,也可以从WinMain()返回当这个进程的结束码.

    要点:GetMessage()遇到错误后返回-1.你要记住这点,说不定哪次你在这里会犯错...即使GetMessage()被定义为返回一个BOOL值,它还是会返回TRUE和FLASE之外的值,因为BOOL被定义为UINT(unsigned int).下面的代码可能看起来可工作,但是不能正确处理某些情況:

        while(GetMessage(&Msg, NULL, 0, 0))
    
        while(GetMessage(&Msg, NULL, 0, 0) != 0)
    
        while(GetMessage(&Msg, NULL, 0, 0) == TRUE)
    

    上面的写法都是错误的!可能你注意到我在这个教程中使用了第一个,刚刚提到了,如果GetMessage()不失败,并不会出错,你代码要是正确的话是不会出错.但是你要是在读本教程的话我并不能以此做为前提,你的代码可能有很多错误,GetMessage()会在某些点出错:)这种写法我已经更正了,如果我漏了某些地方请原谅.

        while(GetMessage(&Msg, NULL, 0, 0) > 0)
    

    应该始终使用这段拥有相同的效果的代码

      我希望你对windows消息循环有了进一步的了解,如果沒有,不用怕,你使用它们一些时间后就会更清楚了

    Copyright © 1998-2008, Brook Miles (forgey). All rights reserved.

  • 相关阅读:
    PyQt 滚动条自动到最底部
    Python 装饰器示例,计算函数或方法执行时间
    pyuic5将.ui文件转为.py文件
    Python pyinstaller 参数
    Win+R 常用命令
    CODEVS 2171 棋盘覆盖
    P3924 康娜的线段树
    P1850 换教室
    U33405 纽约
    POJ
  • 原文地址:https://www.cnblogs.com/ageane/p/forgers.html
Copyright © 2011-2022 走看看