看过许多windows消息循环的内容了。但还是感觉没有系统的掌握windows窗口显示的原理。    句柄啊,GDI啊,windows消息循环啊,wndproc回调函数啊。    窗体与控件的区别啊,  容器与控件的关系啊,  等等。    尤其是当一个windows窗体程序,从运行到显示的过程中,几个关键点是什么,操作系统先创建了什么??再创建了什么,再根据什么执行的GDI中的代码从而在界面上绘制出了窗体,窗体容器与控件之间的关系 在代码中如何体现的。    比如,我在c#中,一个控件在一个窗体上显示,代码一般是 new 一个控件。然后添加到form.controls集合中。在窗体的构造函数中执行此代码。    但窗体类,控件类,执行的过程 与windows创建句柄,前后的关系是什么?
 
    写的比较乱,因为思维就比较乱。 望能尽可能系统的讲一下。前后的逻辑关系与对应关系。         

解决方案 »

  1.   

    大概说下我的理解吧:
    句柄:句柄是窗口的标识,用来唯一的识别一个窗口
    GDI:Win32下图形接口
    windows消息循环:
    先来看一下一个GUI程序的执行流程:
    code=C/C++] while (GetMessage(&msg, NULL, 0, 0))
    {
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    }[[/code]
    应用程序通过一个循环,不停的从消息队列里提取消息,并进行处理,可以看出,一个WinForm程序基本上是一个“死循环”,因为只要有消息,GetMessage就返回true。
    这就是消息循环。
    WndProc窗口过程:在上面的代码中,DispatchMessage函数用于将消息提交到窗口过程WndProc中,在这里你可以进行消息处理。
    再来看看通常WndProc里的代码:
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc; switch (message)
    {
    case WM_COMMAND:
    wmId    = LOWORD(wParam);
    wmEvent = HIWORD(wParam);
    // 分析菜单选择:
    switch (wmId)
    {
    case IDM_ABOUT:
    DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    break;
    case IDM_EXIT:
    DestroyWindow(hWnd);
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
    case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: 在此添加任意绘图代码...
    EndPaint(hWnd, &ps);
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
    }
    每个消息包括4部分:窗口句柄(标识将要发送给哪个窗口),消息号(标识不同的消息,例如WM_KEYDOWN标识键盘按下),wParam,lParam这是两个额外的参数,在16位机器中,l表示WORD,占2个字节,l表示LONG,占4个字节,但现在32位的机器都是4个字节。
    系统已经帮你处理了一些很重要的消息,例如窗体重绘,窗体销毁等。而像一些事件,例如单击,也是从这里开始的,当系统检索到左键按下,左键抬起消息时,就将其处理成单击,并调用OnClick方法,并最终调用了Click事件。
      

  2.   

    更正一下,只要GetMessage提取的消息不是WM_CLOSE,就返回true
    而这个消息会返回false,从而退出消息循环。
      

  3.   

    谢谢。  看了楼上的解释。我更明白了自己的疑问在哪了。   就是单独说消息循环啊,回调函数啊,窗口啊,我都基本了解了。
       常说的  1 设计窗口类
               2 注册窗口类
               3  创建窗口
               4 显示及更新窗口。
       这么个过程。对于窗体这个窗口也比较理解了。
       
       比如,我们常见的  new form1();这是对应到了创建窗口了吧?? 而注册窗口类的环节,net给隐藏了吧??   那对应的控件  new button1(); 这是创建子窗口-- 控件吗??    但,显示时。不把控件添加到父窗口的控件集合属性,按钮是不会显示出来的。但是,按钮的visiable属性却是true。
       所以现在疑惑比较集中在,字窗口 也就是控件 与容器 父窗口的关系上。
      

  4.   

    Petzold 之 Programming Windows Fifth Edition 那么厚的一本书.不是 3 言 2 语就说清楚的.简化的在线教程让我来给你推荐一下:
    1.
    theForger's Win32 API Tutorial
    http://www.winprog.org/tutorial/
    2.
    Win32 Tips, Tricks and Tutorials
    http://www.catch22.net/tuts
    3.
    Stromcode Win32/C++
    http://www.stromcode.com/category/code/
    4.
    A programming tutorials on C++ language, C language, MFC Windows 
    http://www.tenouk.com/其他的 FunctionX, DevX, codeproject, codeguru 就不列了.
      

  5.   

    在Windows系统中,窗口和控件都是Window,系统提供了一些公共控件,应用程序可以使用公共控件或者用RegisterClassEx注册自己的Window类型。窗口和控件都使用CreateWindowEx创建,创建后会收到各种消息,在WindowProc中处理消息,对于程序不感兴趣的消息,可以调用DefWindowProc来处理。窗口关闭时,调用DestroyWindow销毁窗口。在.NET中,这些过程都被隐藏了,new操作是创建一个类对象,并没有创建窗口,当调用Show等方法时,如果窗口没有创建,则创建窗口,程序通过响应事件的形式来处理窗口消息。
      

  6.   

    楼主啊……前面的问题就不说了。至于为什么不添加控件就不显示的问题,是因为,没有画上去。控件,包括窗体,都有回调函数 OnPaint 方法,你一定没有接触过,这个是 WM_PAINT 消息的回调方法的外包装,你说得没错,消息循环是内部给处理好的了,先不说C#.net,便是MFC,你去创建一个UI线程,消息循环也是替你照顾好的。UI的话,有一个结构,叫做“视觉树”,这是一个迭代过程,只有加入“树”中的元素才会递归地去显示到UI上。你新生成一个控件,但是你不将之加入到该“树”中,你当然看不到。因为,它被UI给忽略了,但它还是在内存中存在着。我觉得你借着这个兴趣,应该去看看底层。.net也是一个体系,它也有底层。
      

  7.   


    谢谢。视觉树这个概念,也许能解释我的疑惑了。控件必须在容器上绘制。而不添加到父窗口的控件集合属性中,就没有添加到视觉树中。不过,除了在窗体代码中 显示新的窗体,  需要 show方法外。 控件的显示 父窗体的显示,都没有调用show方法。
      

  8.   


    show是父级窗体的显示方法,它将触发回调,并以此窗体为树根进行树的整个遍历ONPAINT。还有,每个控件都是一个WINDOW,所以都会有同样的回调接口。
      

  9.   

    可查阅WIN32 SDK编程相关资料。
      

  10.   

    控件与窗体的区别并不是特别大
    你想理解这些建立你学习c++与windows核心开发记和创建一个窗体是使用createwinprc函数消息泵由windows自己维护(windows会自动将消息发给当前激活状态的窗体[控件])
      

  11.   

    看来没有学win32而直接学C#不是很好啊!
    如果还是学生的,先学一下C++,或Delphi,
    Delphi还可以直接看原代码,很好的,可惜Delphi已经.....
      

  12.   

    C#的类把复杂的过程都封装起来了!
    如果要更好的理解可以看看
    WINSDK编程或者深入了解MFC!
      

  13.   

    现在的高级语言编程,都将这些底层的东西封装好了,不需要程序开发者去关注。例如,Delphi 和 .NET ,窗体和控件的这些消息都是系统帮我们处理好了。楼主,想知道这些底层的东西,可以用 vc 自己做一个窗口,不要用 MFC 或者 ATL 框架,用纯粹的 Windows Application 就知道了。找一本 Windows 程序开发的书看一下就可以知道了。
      

  14.   

    看书吧,《Windows程序设计》,网上有电子书下
      

  15.   

    不要人云亦云, 《Windows程序设计》对于WINDOWS的消息机制介绍并不多。远远比不上侯捷的《深入解析MFC》多。
    我个人对这个也不是很懂, 大概说, 就是有一个消息队列, 默认就能运行的了。写WIN32的话, 就是对消息队列相关的消息再进行需要的变化。
    看MFC是体现不出这个的, 只能看WIN32。
    句柄?就是学号呗。学校是不管你的姓名的, 只管你的学号。就这个意思
    wndproc?就是填写相关的消息用的函数呗。
      

  16.   

    我来终结这个帖子吧
    就mfc窗口程序来说,
    1. 给C***App填上虚拟函数 virtual BOOL PumpMessage();
       填上代码:
    BOOL CTestmfcApp::PumpMessage()
    {
    ASSERT_VALID(this);

    if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
    {
    return FALSE;
    }
    if (m_msgCur.message==WM_ENDSESSION) {
    AfxMessageBox("WM_ENDSESSION");
    }

    if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
    {
    ::TranslateMessage(&m_msgCur);
    theGroup++; // 这个为全局变量,只在这里被增加!                // 这个是输出函数,将消息利用OutputDebugString打印到 Dbgview.exe里面
                      // 格式自己定义,theMSGSTR 为一个类,里面封装了 消息字符串到消息值的映射
                      // 将消息的个数 theGroup 也打印出来
    SOutputDebugString("CRibbonApp",&theMSGSTR,m_msgCur.message,theGroup);
    ::DispatchMessage(&m_msgCur);
    }
    return TRUE;
    //return CWinApp::PumpMessage();
    }
    2. 给 CMainFrame添上虚函数WindowProc ,在虚函数里面调用上面那个SOutputDebugString
    3. 给 C***View添上虚函数WindowProc ,在虚函数里面调用上面那个SOutputDebugString
    4. 设置模式为debug模式,编写SOutputDebugString 函数
    5. 你会发现,mfc程序启动之后,有很多消息,呵呵,一清二楚,不用再猜了,如此如此,定可搞定windows应用编程,不是吹的
        我的图片如下:
        
        有兴趣加我:1123392038
      

  17.   

    显示的消息详细到何种程度,自己把握,这里面需要一个数据表的,不便上传,又需要的,加我.
    原理很简单,很实用,我处理一些windows绘图技术,就是通过这种手段研究windows消息的规律
    不久,我就可以发布一些windows规律了
      

  18.   

    +本人也在研究中,研究结果和大家分享!
    建议:每个人用这个方法研究一些windows api函数,把研究得出来的消息等结果最后汇总起来,公布!
    不久我就给出具体的意见
      

  19.   

     你写了些 什么我没有看清楚啊!xia 次写明白点噢噢
      

  20.   

    这样子的话岂不是又要学回去了,先学c#,然后c++,最后是c。很弱弱的问一句,win32编程还有人用吗?如果有,都是哪些方面?大家有兴趣的话可以再开个帖子讨论web方面的。
      

  21.   

    窗口的消息处理都过时了,没必要去细究,有空研究WPF去吧,或者DOM。
      

  22.   

    我写的,就是在应用程序里面的消息循环函数处,利用OutputDebugString向一个小程序Dbgview.exe 发送调试字符串
    Dbgview.exe 是 sysinternals 工具箱里面的一个.原理:就是将程序里面的每个消息都变成对应的字符串,发送到一个小程序Dbgview.exe
    1.CWinApp里面有个消息循环,其中这个类有一个虚函数PumpMessage,利用source insight 查阅mfc源码可以看到
    利用vc 6.0 class wizard 不能添加,只能手动覆盖掉PumpMessage.将 mfc里面的源码拷贝出来,去掉一些不重要的调试代码就可以了2.每次DispatchMessage之前,将特定格式的字符串利用OutputDebugString输出到Dbgview.exe.
      我使用的信息: 1). GetMessage被调用的次数(创建一个全局变量,每次DispatchMessage之前递增)
                   2). 消息循环的类名称,如下面的"CMainFrame",当前消息的指针(GetCurrentMessage来获取)
      LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
    {
            // TODO: Add your specialized code here and/or call the base class
    //SOutputDebugString("CMainFrame",&theMSGSTR,message,theGroup);
    SOutputDebugString("CMainFrame",&theMSGSTR,GetCurrentMessage(),theGroup,time);
    return CFrameWnd::WindowProc(message, wParam, lParam);
    }
    3.CMainFrame里面的虚函数WindowProc 用来处理所有CMainFrame能接受到的界面消息,在这个函数里面也将消息格式化成字符串后发送给Dbgview.exe 
    3.C***View里面的虚函数WindowProc 用来处理所有C***View能接受到的界面消息,在这个函数里面也将消息格式化成字符串后发送给Dbgview.exe 先运行Dbgview.exe,再启动被调试的程序,你就会发现所有的windows消息都流到Dbgview.exe里去了.见上图
      

  23.   

    很多msdn上面都没有的,在源码里面可以查得到
    很多源码里面没有的,通过验证可以查得到,比如未定义的WM_SYSCOMMAND消息,当你拖动窗口右边的边框时,会产生WM_SYSCOMMAND,wParam为0xF002好好利用source insight,利用里面的查询工具
    里面的symbol 不一定能搜索出所有的东西,Search Projects 命令也不能搜索出所有的,Search Files能搜索出很多东西,只是太泛了好好利用Dbgview.exe
    以前,图形界面我怎么也调试不到,总是用AfxMessageBox来探测运行到哪儿来了,可这个家伙总会破坏程序的消息队列,你会被结果搞得一团糟
    将所有的消息打印到Dbgview.exe,是观察windows 消息转递机制的好办法.
    我利用这个技术,已经将鼠标缩放窗口的所有消息的规律分析出来了,自己设计了一些缩放窗口时只绘制缩放的那一个很窄的条条的算法,效率还不错,满意总之,你把windows 消息搞清楚了,windows图形编程就不再是难事了,真的
      

  24.   

    hehe v总之,你把windows 消息搞清楚了,windows图形编程就不再是难事了,真的
      

  25.   

    你下载个 《Programing Windows》看吧
    我觉得挺经典的
      

  26.   

    自己实现一个gui,就差不多了弄明白了
      

  27.   

    Windows api 可以绘制 所有winform程序  C# Winform 不过是又把api封装了一次。
      

  28.   

    看visopsys.org,这个系统可能会给你点类似的东西。