正文

[z]DLL封装框架视图经验总结-2011-01-15 15:04:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lym51/52174.html

分享到:

作者:朱金灿

来源:http://blog.csdn.net/clever101

 

 

    有关VC编程中DLL封装对话框的资料网上多如牛毛,现在我想探究一下如何在DLL中封装框架窗口、文档和视图,略有所得,与诸君共享。我找到了两种DLL封装框架视图的方式。实际上用DLL封装框架视图涉及到两点:一是如何封装;二是确保窗口销毁之后的不出现内存泄露。(下面所有代码的开发环境为:VS C++ 2005+sp1, Win XP + sp2

 

方式一 动态创建窗口

 

     请不要误会,我不是指用C语言开发SDK的方式动态创建窗口的方式,当然这样是完全可以的,问题是这种太过于方式太过于复杂。微软已经封装好了MFC,我们没必要不领微软的情。我采用的是一种APIMFC结合的方式。我们把调用DLL模块的程序叫宿主程序,把封装窗体的DLL叫客户程序。

 

首先我们建一个使用共享MFC的规则DLL工程Custom1。我的基本想法是这样的:定义三个类:

类名

描述

备注

CCustomManage1

对外接口类,该类负责动态窗口的创建和销毁。

 

CCustomFrameWnd1

 

派生自CFrameWnd,为动态创建的框架窗口类。

 

CCustomView1

 

派生自CView,为动态创建的视图类。

 

 

 

   

大致的设计是这样的:在CCustomManage1类定义一个CCustomFrameWnd1类的指针,在CCustomFrameWnd1类定义一个CCustomView1类的指针。

 

主要创建代码如下:

  1. /******************************************************************* 
  2. * 函数名称:CreateFrameWnd 
  3. * 功   能:动态创建框架视图 
  4. * 参   数: 
  5. * 返回值:TRUE标识创建成功,FALSE表示创建失败 
  6. *******************************************************************/  
  7. extern CCustom1App theApp;  
  8. BOOL CCustomManage1::CreateFrameWnd()  
  9. {  
  10.     // 确保资源句柄有效  
  11.     AfxSetResourceHandle(theApp.m_hInstance);  
  12.   
  13.     m_pFrmWnd = new CCustomFrameWnd1();  
  14.   
  15.     CString wndClass = _T(""); // 用于保存窗口类名称  
  16.   
  17.     try  
  18.     {  
  19.         // 注册窗口类  
  20.         wndClass = ::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE), 0);  
  21.   
  22.     }  
  23.     catch (CResourceException* pEx)  
  24.     {  
  25.         TCHAR   szCause[255];  
  26.         CString strFormatted;  
  27.   
  28.         pEx->GetErrorMessage(szCause, 255);  
  29.   
  30.         strFormatted = _T("窗口创建失败原因: ");  
  31.         strFormatted += szCause;  
  32.         AfxMessageBox(strFormatted);  
  33.         pEx->Delete();  
  34.   
  35.         return FALSE;  
  36.     }  
  37.   
  38.     // 设定窗口的大小  
  39.     RECT rc;  
  40.     rc.top = 0;  
  41.     rc.left = 0;  
  42.     rc.bottom = 600;  
  43.     rc.right = 800;  
  44.     CString csWindowName = _T("使用动态创建的方式封装框架试图");  
  45.     // 正式创建窗口  
  46.     if( !m_pFrmWnd->Create(wndClass,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL))  
  47.     {  
  48.         TRACE0("创建窗口失败!\n");  
  49.         return FALSE;  
  50.     }  
  51.   
  52.     m_pFrmWnd->ShowWindow(SW_NORMAL);  
  53.   
  54.     // 创建视图  
  55.     m_pFrmWnd->CreateCustomView();  
  56.   
  57.     AfxSetResourceHandle(AfxGetApp()->m_hInstance);  
  58.     return TRUE;  
  59. }  
  60.   
  61. /******************************************************************* 
  62. * 函数名称:CreateCustomView 
  63. * 功   能:创建视图 
  64. * 参   数: 
  65. * 返回值: 
  66. *******************************************************************/  
  67. void CCustomFrameWnd1::CreateCustomView()  
  68. {  
  69.     CCreateContext context;  
  70.     context.m_pCurrentDoc = NULL;  
  71.     context.m_pCurrentDoc =  NULL;  
  72.     context.m_pCurrentFrame = this;  
  73.     context.m_pLastView = NULL;  
  74.     context.m_pNewDocTemplate = NULL;  
  75.     context.m_pNewViewClass = RUNTIME_CLASS(CCustomView1);  
  76.     m_pView = static_cast<CCustomView1*>(this->CreateView(&context));        
  77. }  

为了防止内存泄露,我们需要考虑防止如何销毁窗口。为了更好地说明这个问题,我先建一个调用该DLL的单文档工程Ower来说明这个问题。现在Ower工程的框架类CMainFrame类定义一个CCustomManage1类的私有变量:

   

  1. private:  
  2.     CCustomManage1 m_CustomManage1;  
 

然后新建一个菜单项,在菜单项的命令响应函数里弹出新建窗口,具体代码如下:

  1. void CMainFrame::OnTest1()  
  2. {  
  3.     // TODO: 在此添加命令处理程序代码  
  4.     m_CustomManage1.CreateFrameWnd();  
  5. }  

 这时我们需要考虑用户是怎么关闭新建窗口,用户就是要么是单击调用程序的关闭按钮把两个窗口都关闭;要么单击DLL弹出的新建窗口的关闭按钮。那么在实现CCustomManage1类的DestroyFrameWnd函数里需要考虑这一点,防止用户先关闭新建窗口,再关闭调用程序时出错,就是要确保关闭时窗口句柄是有效的。

     

  1. /******************************************************************* 
  2. * 函数名称:DestroyFrameWnd 
  3. * 功   能:销毁动态创建的窗口 
  4. * 参   数: 
  5. * 返回值: 
  6. *******************************************************************/  
  7. void CCustomManage1::DestroyFrameWnd()  
  8. {  
  9.     HWND hWnd = NULL;  
  10.     if (NULL!=m_pFrmWnd)  
  11.     {  
  12.         // 确保窗口的句柄有效,才进行销毁窗口操作  
  13.         hWnd = m_pFrmWnd->GetSafeHwnd();  
  14.         if(::IsWindow(hWnd))  
  15.         {  
  16.             m_pFrmWnd->DestroyWindow();  
  17.         }  
  18.     }   
  19. }  
  20. // 在析构函数里调用该函数  
  21. CCustomManage1::~CCustomManage1(void)  
  22. {  
  23.     DestroyFrameWnd();  
  24. }         

     

效果图如下:

动态创建窗口图1

    

     当然你还可以测试在DLL的新建窗口的是否可以加载工具栏,响应Windows的标准消息。我测试过是可以的。

阅读(4367) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册