norains的专栏

只专注于WINCE开发

用户操作
[即时聊天] [发私信] [加为好友]
norainsID:norains
131055次访问,排名641好友0人,关注者27
代码其实是一种乐趣
norains的文章
原创 186 篇
翻译 0 篇
转载 10 篇
评论 258 篇
norains的公告
联系方式请看置顶文章
最近评论
zhli6:如果我们想令该PIN作为GPIO并输出high,那么代码如下:
REG_HW_PINCTRL_MUXSEL0_SET(BF_PINCTRL_MUXSEL0_BANK0_PIN08(3));
REG_HW_PINCTRL_DOUT0_CLR(1 << 8);
REG_HW_PINCTRL_DOE0_SET(1 << 8);……
晴天:請問一下:
如果要寫成Watchdog timer 納在這這要如何實現呢?
hustpanda:电子书看不了呢?
bobo:“耍大牌”...... 你就该直接拉黑
bulrush:你好,首先先感谢一下。我看了你的音量控制,自己也去实现了一下,但是我个人感觉“AudioUpdateFromRegistry”没有依据注册表的设置来更新控制面板的音量。没有马上更新,我重启系统后才看到更新的结果。也就是说这种方法是可行,但是必须要重启,显然这不合理。上面的兄弟说:引用了这两个类后不起作用
如:
void CSoundDlg::OnSoft()
……
文章分类
收藏
    相册
    动漫
    文章图片
    程序交流
    xumercury的BLOG
    狗友们的博客
    清蒸石斑鱼
    美女如刀锋
    茁茁的BLOG
    魅力老姐的窝
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 在C++类中实现Windows窗口的创建收藏

    新一篇: 享受实况,品味生活 | 旧一篇: 应届生深圳求职攻略

    //========================================================================
    //TITLE:
    //    在C++类中实现Windows窗口的创建
    //AUTHOR:
    //    norains
    //DATE:
    //    Thursday  9-November-2006
    //========================================================================
      在面向过程的方法中实现窗口的创建很简单,但有个非常明显的缺点,就是封装不好。如果是自写自用,倒不是一个很大的问题,但如果是写给用户的,可能用户在包含头文件之后,看到那一大堆函数以及变量声明就已经晕掉。最好的方法当然是使用类,只给使用者留出应该使用的接口。但这会有个问题,就是消息处理函数必须为static的CALLBACK,否则编译会出错;但如果消息处理函数为static,其就归属于类,就根本无法调用对象的成员函数,而这个在经典的《windows 程序设计》中也没有涉及到。
      难道我们就只能束手无策,只能采用面向过程的方法了么?那倒未必,毕竟在MFC框架中已经做到,那么相信我们也可以做到。经过一番摸索,终于找到在类中创建窗口的方法,在此不敢独享,放出代码和大家探讨。
      
      为便于理解,代码的作用很简单,仅仅是完成了类的声明和对话框的创建,唯一多余的是在接收到WM_INITDIALOG消息时弹出一个消息框,以证明private函数能够正常调用。
      代码首先是声明一个CMainDlg类:
      ///////////////////////////
      //MainDlg.h
      ///////////////////////////
      class CMainDlg 
      {
       
       //--------------------------------------------------------------------------------------------   
       public:
        //静态的回调函数
        static BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
       
       //-------------------------------------------------------------------------------------------
       //Function
       public:
        //构造函数
        CMainDlg(HINSTANCE hInst);
        //析构函数
        virtual ~CMainDlg();
        //创建对话框
        BOOL CreateMainDlg();
        //消息调用函数,具体意义请参见函数的实现
        BOOL CallDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);
       
       private:
        //临时测试调用函数,仅作为调试用
        void TempTestFuncion(){MessageBox(NULL,L"test",L"",NULL);};
       
       //---------------------------------------------------------------------------------------------
       //数据成员
       private:
        HINSTANCE m_hInst;
        HWND m_hDlg;
       
      };
      
      
      
      然后是MainDlg类的实现:
      /////////////////////////////////
      //MainDlg.cpp
      ////////////////////////////////
                                                                                         
        #include "stdafx.h"                                                                
        #include "MainDlg.h"                                                               
        #include "resource.h"                                                              
                                                                                       
        //全局指针,用来指向所创建的对象,即this的指向对象                                                              
        CMainDlg *g_pDlg = NULL;                         
                     
        //消息的回调函数的实现                                                  
        BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
        {                                                                                  
         if(g_pDlg != NULL)                                                               
         {
          //如果this指针不为空,则调用CallDlgProc函数                                                                               
          return g_pDlg->CallDlgProc(hWnd,wMsg,wParam,lParam);                           
         }                                                                                
         return FALSE;                                                                    
        }                                                                                  
       
        //构造函数                                                                               
        CMainDlg::CMainDlg(HINSTANCE hInst)                                                
        {                                                                                  
         g_pDlg = this; //存储this对象到全局变量中                                                                   
         m_hInst = hInst;                                                                 
        }                                                                                  
       
        //析构函数                                                                               
        CMainDlg::~CMainDlg()                                                              
        {                                                                                  
                                                                                       
        }                                                                                  
           
        //创建对话框                                                                           
        BOOL CMainDlg::CreateMainDlg()                                                     
        {                                                                                  
         m_hDlg = CreateDialog(m_hInst,MAKEINTRESOURCE(IDD_MAIN_DLG),NULL,MainDlgProc);   
         if(m_hDlg == NULL)                                                               
         {                                                                                
          return FALSE;                                                                  
         }                                                                                
         ShowWindow(m_hDlg,TRUE);//显示窗口                                                         
                                                                                          
         return TRUE;                                                                     
        }                                                                                  
            
        //真正的消息处理函数,在这里可以任意调用对象的成员函数                                                                          
        BOOL CMainDlg::CallDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)        
        {                                                                                  
         switch(wMsg)                                                                     
         {                                                                                
          case WM_INITDIALOG:                                                            
           TempTestFuncion(); //norains:测试的私有函数                                      
           break;                                                                       
         }                                                                                
         return FALSE;                                                                    
        }                          
       
       
       
        这是在主程序中对类的的调用:   
        //////////////////
        //MainApp.cpp
        //////////////////
        #include "stdafx.h"
        #include "MainDlg.h"
      
      int WINAPI WinMain( HINSTANCE hInstance,
           HINSTANCE hPrevInstance,
           LPTSTR    lpCmdLine,
           int       nCmdShow)
      {
       //声明一个对象 
       CMainDlg mainDlg(hInstance);
       //创建并显示窗口
       if(mainDlg.CreateMainDlg() == FALSE)
       {
        return 0x05;
       }
       
       //消息循环
       MSG msg;
       while(GetMessage(&msg,NULL,0,0))
       {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
       }
       return 0;
      }
      
      这段代码的关键点在于MainDlgProc声明为类的static函数,以及使用g_pDlg来存储this对象指针,并在MainDlgProc中调用。只要注意到这两点,在类中创建一个窗口就不是一件非常困难的事情。
      
      对于CallDlgProc()函数,可能有不少人觉得是鸡肋,因为相同的功能完全可以在MainDlgProc()中实现,比如这程序的代码完全可以撇开CallDlgProc()写成这样:
      
      BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
        {                                                                                  
         if(g_pDlg != NULL)                                                               
         {
         switch(wMsg)                                                                     
          {                                                                                
           case WM_INITDIALOG:                                                            
            g_pDlg->TempTestFuncion();                                       
            break;                                                                       
          }                                 
         }                                                                                
         return FALSE;                                                                    
        }               
        所完成的功能和之前的代码相同。不过如果要更改之后的代码正常工作的话,还需要把TempTestFuncion()函数声明为public。也许有的读者已经发现问题之所在:如果对消息相应的处理函数不多,这样倒是可以;但如果很多的话,那么那些消息相应函数都需要声明为public,并且这些消息响应函数都是用户不可能用到的!用户看到如此之多用不到的public函数,即使没头晕,也需要好一阵子才能回神过来。
        所以呢,CallDlgProc()函数只是起到一个缓冲作用,不必要把所有的消息相应函数都暴露给用户。虽然这样做也暴露了CallDlgProc()函数,但毕竟相对于上十个甚至上百个消息响应函数而言,仅仅只是暴露一个没什么作用的CallDlgProc()函数函数,应该能让用户减轻不少负担才是。               
       
        在网上看到有一个方法不是采用全局变量,而是直接设置窗口数据,然后再获取。这方法比较有意思,在此将更改的代码贴出:           
        BOOL CMainDlg::CreateMainDlg()                                                     
        {                                                                                  
         m_hDlg = CreateDialog(m_hInst,MAKEINTRESOURCE(IDD_MAIN_DLG),NULL,MainDlgProc);   
         if(m_hDlg == NULL)                                                               
         {                                                                                
          return FALSE;                                                                  
         }                                                                                
         ShowWindow(m_hDlg,TRUE);//显示窗口                                                      
         SetWindowLong(m_hDlg,GWL_USERDATA,(LONG)this); //将this指针传递给窗口
                                                                                      
         return TRUE;                                                                     
        }   
       
        BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
        {   
         static CMainDlg * pDlg = NULL;
       if(pDlg == NULL)
       {
        pDlg = (CMainDlg *)GetWindowLong(hWnd,GWL_USERDATA);
       } 
                                                                                  
         if(pDlg != NULL)                                                               
         {
         switch(wMsg)                                                                     
          {                                                                                
           case WM_INITDIALOG:                                                            
            pDlg->TempTestFuncion();                                       
            break;                                                                       
          }                                 
         }                                                                                
         return FALSE;                                                                    
        }  
        这段代码关键就只在于两个函数:SetWindowLong()和GetWindowLong().很巧妙地让窗口通过这两个函数来传输this对象,的确是一个很好的方法.

    发表于 @ 2006年11月09日 23:56:00|评论(loading...)|编辑

    新一篇: 享受实况,品味生活 | 旧一篇: 应届生深圳求职攻略

    评论

    #Kusk 发表于2008-01-21 17:26:57  IP: 207.46.92.*
    对于CallDlgProc()函数,可能有不少人觉得是鸡肋,因为相同的功能完全可以在MainDlgProc()中实现,比如这程序的代码完全可以撇开CallDlgProc()写成这样:

    BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
    {
    if(g_pDlg != NULL)
    {
    switch(wMsg)
    {
    case WM_INITDIALOG:
    g_pDlg->TempTestFuncion();
    break;
    }
    }
    return FALSE;
    }
    所完成的功能和之前的代码相同。不过如果要更改之后的代码正常工作的话,还需要把TempTestFuncion()函数声明为public。

    =====================================
    不需要声明为public. 因为MainDlgProc已经是CMainDlg的成员函数(尽管只是静态成员),可以访问到私有域。
    2008-01-22 09:26:58作者回复
    MainDlgProc为静态成员时,就不是成员变量,而是类变量,无论private域还是public域,都无法访问.在类中声明为static是为了限制作用域.
    #Kusk 发表于2008-01-29 21:52:58  IP: 125.34.54.*
    类变量是可以访问的成员变量的,前提是显示地指派了对象。比如你代码中的:
    g_pDlg->TempTestFunction(); // 假若仅仅是TempTestFunction()则不可。

    再比如:

    #include <iostream>

    class A
    {
    public:
    static void foo(A *p) { p->bar(); } // call private member function!
    private:
    void bar() { std::cout << "object " << this << " has been visited." << std::endl;}
    };

    int main()
    {
    A a;
    A::foo(&a);

    return 0;
    }

    该程序是合法的。这里A的static函数就访问了A的(私有)成员函数。因为有这个便利,所以这就是为什么要把MainDlgProc做成类的static(而非全局函数)的原因。
    2008-01-30 14:37:24作者回复
    这样的方式确实可以访问成员函数,但具体到本文的例子,却有点不太适合.假设依你的想法,将MainDlgProc做成类的static,如果要在该函数中访问成员函数,那么在形参中我们必须要有一个指向对象的指针.假设我们这样写:MainDlgProc(CMainDlg *pMainDlg,HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam),那么就可以通过pMainDlg指针来访问成员函数.但这会有个你可能忽视的问题,让MainDlgProc能访问成员函数,前提是我们必须要增加一个指向对象的形参,而恰恰这点导致了不可用的结果.MainDlgProc是作为回调函数来使用,参数只能按微软所给的形参接口来定义,也就是说,MainDlgProc函数的形参只能是如此:MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam).在此情况之下,MainDlgProc声明为类的static函数的唯一好处应该就是TempTestFuncion的Access level可以为private.顺便说一下,这篇文章的代码并不是最简便最通俗的,甚至可以说是最麻烦的(我现在看了也头晕晕),比这篇更符合封装要求的(至少更清晰明了)请见该文:http://blog.csdn.net/norains/archive/2007/10/23/1840482.aspx
    #Kusk 发表于2008-01-30 21:40:48  IP: 123.112.69.*
    你的代码已经通过GetWindowLong来得到指向对象的指针了,不需要以形参的方式传递进去。为什么你会想到“在形参中必须要有一个指向对象的指针”这个问题呢?我们完全不需要更改接口。

    我的回复只是针对你关于“需要把TempTestFuncion()函数声明为public”一句的纠正。如我前面所说,事实上是不需要的。
    2008-01-30 22:19:51作者回复
    当时写代码时,并没有意识到SetWindowLong所带来的便利性,而在文中提到的GetWindowLong来得到指向对象的指针其实是后来作为附加内容加的,和前面的代码及内容关联不大.之前的回复是因为我误认为你想按你所给的例子改写MainDlgProc的形参,通过指针来访问成员变量,所以才有之前的回复. :)
    2008-01-30 22:21:42作者回复
    说得没错,依照你的方式,“需要把TempTestFuncion()函数声明为public”确实是不需要的.非常感谢你指出该纰漏. :-)
    #Kusk 发表于2008-01-31 22:26:57  IP: 125.34.51.*
    :)
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © norains