新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → WIN32入门-----[转帖] 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 11308 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: WIN32入门-----[转帖] 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客楼主
    发贴心情 WIN32入门-----[转帖]

    较为详细的介绍了WIN32的入门编程,全文如下:

    石磬 著

    By Shi Qing

    Email: shiqingstudio@yahoo.com.cn

    QQ: 16398943

    http://blog.csdn.net/ronaldo17/


    1.1编程环境

    这里要说的编程环境不是我们的生活环境,不是象论坛里面每天讨论的程序员的工资,也不是政府给软件业的大环境,更不是世界软件的何去何从,这里要说的是我们所用的开发工具和软件接口.这里所有讲到的编译器和图形接口都是用得微软的东东.也就是我将向大家讲述的所有游戏编程内容都是基于visual studio.net2003和direct7.

    1.1.1 编译器

          我们以后用的开发工具全是基于visual studio.net2003,所以我先来说说这个编译器的一些基本使用方法(不要BS我^_^).首先启动vc.net(然后等,无休止的等,微软的东西慢的很^_^), 会看见一个"起始页",点击"新建项目"一栏,并在出现的窗口选择"Visual C++ 项目"一栏中的"Win32 控制台项目",填好"名称"和"位置",按"确定",这时会出现一个"Win32 应用程序向导"。此时需要在"附加选项"一栏把"空项目"前的方框勾上,以防VC.net在工程中加入一些无意义的垃圾. 最后按"Finish"就完成了工程的创建。

        然后大家就建立完一个工程了,这个时候编译环境实际上已经达建好了,如果你是一个老鸟,你还可以修改一些你自己习惯的设置,让它用起来更顺手. 大家会注意到现在工程还没有文件,所以接下去我们需要学习如何新建一个文件,如果你想新建的文件是C++程序文件(.cpp),那么应该在"源文件"上按右键,选择"添加" --- "添加新项",在出现的窗口中选择"C++ 文件",定好名字,再按"开始"即可(假如你加入的文件叫"star.cpp",将象下图所示);如果你想新建的文件是头文件(现在先不要管头文件是什么),在"头文件"按右键,也选择"添加" --- "添加新项",在出现的窗口中选择"头文件",也定好名字并按"开始"就行了。

        最后我们来看看一个重要的操作,即如何把LIB文件(现在也不要管LIB文件是什么…)加入工程中:首先在"解决方案"窗口中找到工程名,然后在上面按右键并选择"属性",在出现的窗口中选择"连接器" --- "输入" --- "添加依附项",最后填上要加入的LIB文件名即可。在这里,由于我们主要是研究游戏的编程,所以为了告诉编译器我们需要使用DirectDraw,我们要在程序文件中加入#include <ddraw.h>,并把"ddraw.lib"和"dxguid.lib"加入工程,记住,做完了这些工作后DirectDraw程序才能被正常编译。

    1.1.2 图形接口

    什么是图形接口? DirectX就是一个图形接口,DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染、交互式音乐和环境音效等高要求应用开发服务的;Direct X是微软公司专为PC游戏开发的API(应用程序接口),特点是:比较容易控制,可令显卡发挥不同的功能,与Windows 95和Windows NT兼容性较好。在Direct X 5.0中共分六个部分:DirectDraw—管理游戏的视频输出、Direct 3D—管理游戏的3D图形、DirectPlay—管理游戏的网络通讯、DirectSound—管理游戏的声音输出、DirectInput—管理游戏摇杆控制、Direct Setup—管理游戏的安装。以上这些都是微软给我们的解释,简单的说,它终究都是一些微软给我们封装好了的API函数,我们通过对这些函数的调用和操作可以达到直接对硬件的操作,包括加速,显卡的显示,游戏手柄的使用,声卡的使用………,既然可以对显卡和声卡以及手柄进行操作,自然而然我们就可以编写游戏.所以我们游戏的开发都是基于direct编程.

    1.2 win32编程

    现在的所以编程都是面相对象编程,在大学里面头发花白的老头就不断的给我们灌输这个思想,什么是对象呢,所有的窗体,组件,包括封装的类,他们都是对象,然而现在我们家庭软件绝大多数都是windows的窗体程序,所以可以说我们现在的编程都是基于窗体的win32编程,就是windows下的32位编程(听说下一代64位机有望在今年面试,不过走入家庭不知道又是什么时候了),自然容纳我们的游戏的容器就是windows窗体,所以这一章的重点就是下面的窗体的建立,只有建立了这个容器,我们才能在上面编制其他的程序,无论是游戏或者其他的什么东西.

    1.2.1 消息机制

    win32编程的核心思想就是消息机制,每一个程序员都必须了解它,它也是最低层的东西了,不知道看本文的朋友有没有看过候捷大师的《深入浅出MFC》和李维老师的《VCL构架剖析》(没有听说过?你不会是火星来的吧^_^),如果没有,强烈建议你去买来看看,两本书讲的不是同一个编译器,(一个是micosoft的,一个是borland),不是同一种语言(一个是c,一个是pascl),前一本出来的时间比较早,现在俨然成为华人地区程序员的圣经,后一本书是昨年才出来的,但是两本书讲的东西都是一样的,想学好编程一定要看看这两本书,他们旁博引证,引经论典,丝丝入扣,给我的启发颇深,看来也是显而易懂(怎么觉得想在给两个老师作宣传J),看完以后你就知道我们平时看着简单的程序到底是怎么运行的,他们在后台是怎么样实现的.由于我的表达能力有限,所以在这里只能尽量把我的理解大概讲讲,讲的不好,不要拿砖头砸我啊.

    我想先谈一下Dos与Windows驱动机制的区别:

    DOS程序主要使用顺序的,过程驱动的程序设计方法。顺序的,过程驱动的程序有一个明显的开始,明显的过程及一个明显的结束,因此程序能直接控制程序事件或过程的顺序。虽然在顺序的过程驱动的程序中也有很多处理异常的方法,但这样的异常处理也仍然是顺序的,过程驱动的结构。

    而Windows的驱动方式是事件驱动,就是不由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程序员,在你编写程序时,你并不知道用户先按哪个按纽,也不知道程序先触发哪个消息。你的任务就是对正在开发的应用程序要发出或要接收的消息进行排序和管理。事件驱动程序设计是密切围绕消息的产生与处理而展开的,一条消息是关于发生的事件的消息。

    1.2.2 窗体的注册和初始化


        了解了消息机制以后,我们可以创建窗体了.创建窗体前我们看看windows程序的流程,大致流程图如下:


        了解了消息机制以后,我们可以创建窗体了.创建窗体前我们看看windows程序的流程,大致流程图如下:
    在这之后,我们可以创建Windows窗体了

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

    //函数:WinMain( )

    //功能:Windows程序入口函数。创建主窗口,处理消息循环

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

    int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

    {

    MSG msg;                                     //消息结构

    InitWindow(hInstance,nCmdShow);              //初始化窗体



    while(1)                                     //消息循环

    {

      if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

      {

       if (msg.message==WM_QUIT)                  //退出消息循环

        break;

       TranslateMessage(&msg);                    //得到消息,处理回调函数

       DispatchMessage(&msg);

      }

    }

    return msg.wParam;

    }WinMain( )函数的原型如下:
      int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                          LPSTR lpCmdLine, int nCmdShow)
    第一个参数hInstance是标识该应用程序的句柄。不过句柄又是什么呢?其实就是一个指向该程序所占据的内存区域的指针,它唯一地代表了该应用程序,Windows使用它管理内存中的各种对象。
    第二个参数是hPrevInstance,应用程序的前一个实例句柄,别管它,对于Win32位而言,它一般是NULL.
    第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。比如说我们运行"test hello",则此参数指向的字符串为"hello"。
    最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。它告诉应用程序如何初始化窗口,如最大化,最小化等状态。

    创建以后我们还不能直接调用它,我还必须得和其他应用软件一样,对它进行注册(为什么微软的东西都要注册啊,真是麻烦),而且还要自己设置窗体的其他属性.


    //*********************************************************
    //函数:InitWindow( )
    //功能:创建窗口
    //*********************************************************
    static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
    {
    WNDCLASS wc;
    wc.style = NULL;                    //窗口类风格
    wc.lpfnWndProc = (WNDPROC)WinProc; //指向窗口过程函数的指针
    wc.cbClsExtra = 0;                  //窗口类附加数据
    wc.cbWndExtra = 0;                   //窗口类附加数据
    wc.hInstance = hInstance;            //拥有窗口类的实例句柄
    wc.hIcon = NULL;                     //最小窗口图标
    wc.hCursor = NULL;                    //窗口内使用的光标
    wc.hbrBackground = NULL;             //用来着色窗口背景的刷子
    wc.lpszMenuName = NULL;              //指向菜单资源名的指针
    wc.lpszClassName = "menpao_RPG_DEMO";// 指向窗口类名的指针
    RegisterClass(&wc);                  //注册窗口
    hwnd=CreateWindow("menpao_RPG_DEMO","menpao_RPG_DEMO",WS_POPUP|WS_MAXIMIZE,0,0,GetSystemMetrics( SM_CXSCREEN ),GetSystemMetrics( SM_CYSCREEN ), NULL,NULL,hInstance,NULL);
    if( !hwnd ) return FALSE;
    ShowWindow(hwnd,nCmdShow);           //显示窗口
    UpdateWindow(hwnd);                  //刷新窗口
    return TRUE;
    }
    (1)第一个参数:成员style控制窗口样式的某些重要特性,在WINDOWS.H中定义了一些前缀为CS的常量,在程序中可组合使用这些常量.

    (2)第二个参数:lpfnWndProc,给它消息处理函数的函数名称即可,必要时应该进行强制类型转换,将其转换成WNDPROC型。
    (3)第三,四个参数:cbWndExtra域指定用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。这般来讲,你只要把它们设为0就行了,不必过多考虑。
    (4)第五个参数:hInstance成员,给它的值是窗口所对应的应用程序的句柄,表明该窗口与此应用程序是相关联的。
    (5)第六个参数:成员hIcon被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用以表示程序仍驻留在内存中。Windows提供了一些默认图标,我们也可定义自己的图标,VC里面专有一个制作图标的工具。
    (6)第七个参数: hCursor域定义该窗口产生的光标形状。LoadCursor可返回固有光标句柄或者应用程序定义的光标句柄。IDC_ARROW表示箭头光标.
    (7)第八个参数:hbrBackground成员用来定义窗口的背景色。这里设为NULL。
    (8)第九个参数:lpszMenuName用来指定菜单名,本程序中没有定义菜单,所以为NULL。
    (9)第十个参数:lpszClassName指定了本窗口的类名。本程序命名为“menpao_RPG_DEMO”。
    当对WNDCLASS结构域一一赋值后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的API函数是RegisterClass,注册失败的话,就会出现一个对话框如程序所示,函数RegisterClass返回0值,也只能返回0值,因为注册不成功,程序已经不能再进行下去了。
    注册完了以后,就是创建该窗体,一般我们一时调用API函数中的CreatWindows()函数完成的
    以上面注册的这个窗体为例
    hwnd = CreateWindow(
    "menpao_RPG_DEMO",                //创建的这个窗体类的名称
    "menpao_RPG_DEMO",               //窗口标题
    WS_POPUP|WS_MAXIMIZE,            //窗口风格,全部风格见后表
    0,                               //窗口位置x坐标
    0,                               //窗口位置y坐标
    GetSystemMetrics(SM_CXSCREEN ),  //窗口高度,这里是全屏
    GetSystemMetrics( SM_CYSCREEN ),//窗口高度,这里是全屏
    NULL,                               //父窗口句柄
    NULL,                              //菜单句柄
    hInstance,                        //应用程序句柄
    NULL);                            //最后一个参数是附加数据,一般都是0
    参数1:登记的窗口类名,这个类名刚才咱们在注册窗口时已经定义过了。
    参数2:用来表明窗口的标题。可以和第一个参数一样。
    参数3: 用来表明窗口的风格,如有无最大化,最小化按纽啊什么的。

    在DirectX编程中,我们一般使用的是WS_POPUP | WS_MAXIMIZE,用这个标志创建的窗口没有标题栏和系统菜单且窗口为最大化,可以充分满足DirectX编程的需要。
    参数4,5: 用来表明程序运行后窗口在屏幕中的坐标值。
    参数6,7: 用来表明窗口初始化时(即程序初运行时)窗口的大小,即长度与宽度。
    参数8: 在创建窗口时可以指定其父窗口,这里没有父窗口则参数值为0。
    参数9: 用以指明窗口的菜单,菜单以后会讲,这里暂时为0。
    最后一个参数是附加数据,一般都是0。
    如果窗口创建成功,CreateWindow( )返回新窗口的句柄,否则返回NULL。
    不要以为创建和注册完了以后就大功告成,这样的话你是在屏幕上什么也看不见,我们必须要调用另外一个API函数才能看见窗体就是ShowWindow,他的原型是:
    ShowWindow (hwnd, iCmdShow)
    其第一个参数是窗口句柄,告诉ShowWindow()显示哪一个窗口,而第二个参数则告诉它如何显示这个窗口。

    WinMain()调用完ShowWindow后,还需要调用函数UpdateWindow,最终把窗口显示了出来。调用函数UpdateWindow将产生一个WM_PAINT消息,这个消息将使窗口重画,即使窗口得到更新.

    1.2.3 回调函数

    看了上面这么多内容以后,你一定很疑惑了(我们知道了windows程序是怎么样运行的了,也知道了窗体是怎么样建立的,可是我们怎么通过消息让窗体触发事件的呢),这个问题很关键,对,我们就是通过回调函数来实现用消息触发事件的.下面我们来看看什么是回调函数.

    windows就是一个大的消息循环程序,当遇到外部有其他命令时,就会暂停这个大循环,而进行外部给的命令的事件,而外部命令的这个函数就是回调函数(winproc()),他是通过句柄(hwnd)来确定这个命令触发的窗体。同样我们先写回调函数的原型。在这个函数中,不同的消息将被switch语句分配到不同的处理程序中去。Windows的消息处理函数的原型是这样定义的:

    LRESULT CALLBACK WindowProc(

    HWND hwnd, //接收消息窗口的句柄

    UINT uMsg, //主消息值

    WPARAM wParam, //副消息值1

    LPARAM lParam //副消息值2

    );

    消息处理函数必须按照上面的这个样式来定义,当然函数名称可以随便取。

    举个例说明一下,我们要实现分别点击鼠标左右键在窗体里面分别弹出"left button!"和"right button!"的功能.



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

    //函数:WinProc( )

    //功能:处理主窗口消息

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

    LRESULT CALLBACK q( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )

    {

        switch( message )

        {

        case WM_KEYDOWN://击键消息

           switch( wParam )

           {

           case VK_ESCAPE:

               MessageBox(hWnd,"quit!","Keyboard",MB_OK);

               PostQuitMessage( 0 );//退出

               break;

           }

           return 0;



        case WM_LBUTTONDOWN:

           MessageBox(hWnd,"left button!","Mouse",MB_OK);

           return 0;

        case WM_RBUTTONDOWN:

           MessageBox(hwnd,"right button!","mouse",MB_OK);

           return 0;

        case WM_MBUTTONDBLCLK:

           MessageBox(hwnd,"the other!","mouse",MB_OK);

           return 0;

        case WM_DESTROY:

           PostQuitMessage( 0 );

           return 0;

        }

        return DefWindowProc(hWnd, message, wParam, lParam); //调用缺省消息处理过程

    }

    看明白没有啊?case后面就是触发的消息,当不同的击键产生的时候会触发不同的消息,于是就通过这个回调函数结束前面的循环,产生消息事件,事件完成以后再回到消息循环里面.(哦,天啊,多么怀念当年的vb编程啊,IDE为我们封装了所有的事件和方法,只是调用就是了),同时我们更加应该感到庆幸,因为我们终于明白了windows的运行机制.



    2.3 编后语

    win32编程是一个博大精深的知识,我这里只是肤浅的介绍了一下我对于基础的消息机制的运行原理的理解,再次建议想要进入程序员行业的朋友一定要看看我开始推荐的两本书,(绝对不是书托呀^_^).他里面除了包含最基础的消息机制以外,还有包含所以基础类和派生类的原理,以及com的构架,以及Interface的运作机制,还有更为重要的就是当前流行的.net框架的基础Framework的运行机制和构架设计.这才是这两年编程的命脉,象医生一样,只有把握了命脉,才能把握编程环境的大方向,我们初学者才可以有地放失的学习对自己有用的技术,学习起来效果将会事半功倍.从下一章开始,我们就完全进入游戏编程的介绍了.

    最后用候捷老师的话作为这章的结束语,顺便作为给大家一个忠告∶"勿在浮沙筑高台!"。


    //*********************************************************
    //函数:InitWindow( )
    //功能:创建窗口
    //*********************************************************
    static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
    {
    WNDCLASS wc;
    wc.style = NULL;                    //窗口类风格
    wc.lpfnWndProc = (WNDPROC)WinProc; //指向窗口过程函数的指针
    wc.cbClsExtra = 0;                  //窗口类附加数据
    wc.cbWndExtra = 0;                   //窗口类附加数据
    wc.hInstance = hInstance;            //拥有窗口类的实例句柄
    wc.hIcon = NULL;                     //最小窗口图标
    wc.hCursor = NULL;                    //窗口内使用的光标
    wc.hbrBackground = NULL;             //用来着色窗口背景的刷子
    wc.lpszMenuName = NULL;              //指向菜单资源名的指针
    wc.lpszClassName = "menpao_RPG_DEMO";// 指向窗口类名的指针
    RegisterClass(&wc);                  //注册窗口
    hwnd=CreateWindow("menpao_RPG_DEMO","menpao_RPG_DEMO",WS_POPUP|WS_MAXIMIZE,0,0,GetSystemMetrics( SM_CXSCREEN ),GetSystemMetrics( SM_CYSCREEN ), NULL,NULL,hInstance,NULL);
    if( !hwnd ) return FALSE;
    ShowWindow(hwnd,nCmdShow);           //显示窗口
    UpdateWindow(hwnd);                  //刷新窗口
    return TRUE;
    }
    (1)第一个参数:成员style控制窗口样式的某些重要特性,在WINDOWS.H中定义了一些前缀为CS的常量,在程序中可组合使用这些常量.

    (2)第二个参数:lpfnWndProc,给它消息处理函数的函数名称即可,必要时应该进行强制类型转换,将其转换成WNDPROC型。
    (3)第三,四个参数:cbWndExtra域指定用本窗口类建立的所有窗口结构分配的额外字节数。当有两个以上的窗口属于同一窗口类时,如果想将不同的数据和每个窗口分别相对应。则使用该域很有用。这般来讲,你只要把它们设为0就行了,不必过多考虑。
    (4)第五个参数:hInstance成员,给它的值是窗口所对应的应用程序的句柄,表明该窗口与此应用程序是相关联的。
    (5)第六个参数:成员hIcon被设置成应用程序所使用图标的句柄,图标是将应用程序最小化时出现在任务栏里的的图标,用以表示程序仍驻留在内存中。Windows提供了一些默认图标,我们也可定义自己的图标,VC里面专有一个制作图标的工具。
    (6)第七个参数: hCursor域定义该窗口产生的光标形状。LoadCursor可返回固有光标句柄或者应用程序定义的光标句柄。IDC_ARROW表示箭头光标.
    (7)第八个参数:hbrBackground成员用来定义窗口的背景色。这里设为NULL。
    (8)第九个参数:lpszMenuName用来指定菜单名,本程序中没有定义菜单,所以为NULL。
    (9)第十个参数:lpszClassName指定了本窗口的类名。本程序命名为“menpao_RPG_DEMO”。
    当对WNDCLASS结构域一一赋值后,就可注册窗口类了,在创建窗口之前,是必须要注册窗口类的,注册窗口类用的API函数是RegisterClass,注册失败的话,就会出现一个对话框如程序所示,函数RegisterClass返回0值,也只能返回0值,因为注册不成功,程序已经不能再进行下去了。
    注册完了以后,就是创建该窗体,一般我们一时调用API函数中的CreatWindows()函数完成的
    以上面注册的这个窗体为例
    hwnd = CreateWindow(
    "menpao_RPG_DEMO",                //创建的这个窗体类的名称
    "menpao_RPG_DEMO",               //窗口标题
    WS_POPUP|WS_MAXIMIZE,            //窗口风格,全部风格见后表
    0,                               //窗口位置x坐标
    0,                               //窗口位置y坐标
    GetSystemMetrics(SM_CXSCREEN ),  //窗口高度,这里是全屏
    GetSystemMetrics( SM_CYSCREEN ),//窗口高度,这里是全屏
    NULL,                               //父窗口句柄
    NULL,                              //菜单句柄
    hInstance,                        //应用程序句柄
    NULL);                            //最后一个参数是附加数据,一般都是0
    参数1:登记的窗口类名,这个类名刚才咱们在注册窗口时已经定义过了。
    参数2:用来表明窗口的标题。可以和第一个参数一样。
    参数3: 用来表明窗口的风格,如有无最大化,最小化按纽啊什么的。

    在DirectX编程中,我们一般使用的是WS_POPUP | WS_MAXIMIZE,用这个标志创建的窗口没有标题栏和系统菜单且窗口为最大化,可以充分满足DirectX编程的需要。
    参数4,5: 用来表明程序运行后窗口在屏幕中的坐标值。
    参数6,7: 用来表明窗口初始化时(即程序初运行时)窗口的大小,即长度与宽度。
    参数8: 在创建窗口时可以指定其父窗口,这里没有父窗口则参数值为0。
    参数9: 用以指明窗口的菜单,菜单以后会讲,这里暂时为0。
    最后一个参数是附加数据,一般都是0。
    如果窗口创建成功,CreateWindow( )返回新窗口的句柄,否则返回NULL。
    不要以为创建和注册完了以后就大功告成,这样的话你是在屏幕上什么也看不见,我们必须要调用另外一个API函数才能看见窗体就是ShowWindow,他的原型是:
    ShowWindow (hwnd, iCmdShow)
    其第一个参数是窗口句柄,告诉ShowWindow()显示哪一个窗口,而第二个参数则告诉它如何显示这个窗口。

    WinMain()调用完ShowWindow后,还需要调用函数UpdateWindow,最终把窗口显示了出来。调用函数UpdateWindow将产生一个WM_PAINT消息,这个消息将使窗口重画,即使窗口得到更新.

    1.2.3 回调函数

    看了上面这么多内容以后,你一定很疑惑了(我们知道了windows程序是怎么样运行的了,也知道了窗体是怎么样建立的,可是我们怎么通过消息让窗体触发事件的呢),这个问题很关键,对,我们就是通过回调函数来实现用消息触发事件的.下面我们来看看什么是回调函数.

    windows就是一个大的消息循环程序,当遇到外部有其他命令时,就会暂停这个大循环,而进行外部给的命令的事件,而外部命令的这个函数就是回调函数(winproc()),他是通过句柄(hwnd)来确定这个命令触发的窗体。同样我们先写回调函数的原型。在这个函数中,不同的消息将被switch语句分配到不同的处理程序中去。Windows的消息处理函数的原型是这样定义的:

    LRESULT CALLBACK WindowProc(

    HWND hwnd, //接收消息窗口的句柄

    UINT uMsg, //主消息值

    WPARAM wParam, //副消息值1

    LPARAM lParam //副消息值2

    );

    消息处理函数必须按照上面的这个样式来定义,当然函数名称可以随便取。

    举个例说明一下,我们要实现分别点击鼠标左右键在窗体里面分别弹出"left button!"和"right button!"的功能.



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

    //函数:WinProc( )

    //功能:处理主窗口消息

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

    LRESULT CALLBACK q( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )

    {

        switch( message )

        {

        case WM_KEYDOWN://击键消息

           switch( wParam )

           {

           case VK_ESCAPE:

               MessageBox(hWnd,"quit!","Keyboard",MB_OK);

               PostQuitMessage( 0 );//退出

               break;

           }

           return 0;



        case WM_LBUTTONDOWN:

           MessageBox(hWnd,"left button!","Mouse",MB_OK);

           return 0;

        case WM_RBUTTONDOWN:

           MessageBox(hwnd,"right button!","mouse",MB_OK);

           return 0;

        case WM_MBUTTONDBLCLK:

           MessageBox(hwnd,"the other!","mouse",MB_OK);

           return 0;

        case WM_DESTROY:

           PostQuitMessage( 0 );

           return 0;

        }

        return DefWindowProc(hWnd, message, wParam, lParam); //调用缺省消息处理过程

    }

    看明白没有啊?case后面就是触发的消息,当不同的击键产生的时候会触发不同的消息,于是就通过这个回调函数结束前面的循环,产生消息事件,事件完成以后再回到消息循环里面.(哦,天啊,多么怀念当年的vb编程啊,IDE为我们封装了所有的事件和方法,只是调用就是了),同时我们更加应该感到庆幸,因为我们终于明白了windows的运行机制.



    2.3 编后语

    win32编程是一个博大精深的知识,我这里只是肤浅的介绍了一下我对于基础的消息机制的运行原理的理解,再次建议想要进入程序员行业的朋友一定要看看我开始推荐的两本书,(绝对不是书托呀^_^).他里面除了包含最基础的消息机制以外,还有包含所以基础类和派生类的原理,以及com的构架,以及Interface的运作机制,还有更为重要的就是当前流行的.net框架的基础Framework的运行机制和构架设计.这才是这两年编程的命脉,象医生一样,只有把握了命脉,才能把握编程环境的大方向,我们初学者才可以有地放失的学习对自己有用的技术,学习起来效果将会事半功倍.从下一章开始,我们就完全进入游戏编程的介绍了.

    最后用候捷老师的话作为这章的结束语,顺便作为给大家一个忠告∶"勿在浮沙筑高台!"。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/1/15 15:12:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    基础是写程序的根基,赞成"勿在浮沙筑高台!"

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/1/16 8:37:00
     
     thyroc 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(高数修炼中)
      文章:9
      积分:112
      门派:XML.ORG.CN
      注册:2006/8/24

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给thyroc发送一个短消息 把thyroc加入好友 查看thyroc的个人资料 搜索thyroc在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看thyroc的博客3
    发贴心情 
    推荐看<<programming windows>>
    英文版
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/1/31 16:22:00
     
     huhuxuwen 美女呀,离线,快来找我吧!
      
      
      等级:大一新生
      文章:2
      积分:58
      门派:XML.ORG.CN
      注册:2008/5/9

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给huhuxuwen发送一个短消息 把huhuxuwen加入好友 查看huhuxuwen的个人资料 搜索huhuxuwen在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看huhuxuwen的博客4
    发贴心情 
    那怎么在菜单中实现"文件打开"的功能啊!~
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/5/18 12:46:00
     
     ldhwq5735 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(高数修炼中)
      文章:14
      积分:112
      门派:XML.ORG.CN
      注册:2007/12/26

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给ldhwq5735发送一个短消息 把ldhwq5735加入好友 查看ldhwq5735的个人资料 搜索ldhwq5735在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看ldhwq5735的博客5
    发贴心情 
    没有多少新意呀.
    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/7/6 7:50:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2025/2/26 10:02:08

    本主题贴数5,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    109.375ms