[z]DLL封装框架视图经验总结-


有关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. externCCustom1ApptheApp;
  8. BOOLCCustomManage1::CreateFrameWnd()
  9. {
  10. //确保资源句柄有效
  11. AfxSetResourceHandle(theApp.m_hInstance);
  12. m_pFrmWnd=newCCustomFrameWnd1();
  13. CStringwndClass=_T("");//用于保存窗口类名称
  14. try
  15. {
  16. //注册窗口类
  17. wndClass=::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE),0);
  18. }
  19. catch(CResourceException*pEx)
  20. {
  21. TCHARszCause[255];
  22. CStringstrFormatted;
  23. pEx->GetErrorMessage(szCause,255);
  24. strFormatted=_T("窗口创建失败原因:");
  25. strFormatted+=szCause;
  26. AfxMessageBox(strFormatted);
  27. pEx->Delete();
  28. returnFALSE;
  29. }
  30. //设定窗口的大小
  31. RECTrc;
  32. rc.top=0;
  33. rc.left=0;
  34. rc.bottom=600;
  35. rc.right=800;
  36. CStringcsWindowName=_T("使用动态创建的方式封装框架试图");
  37. //正式创建窗口
  38. if(!m_pFrmWnd->Create(wndClass,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL))
  39. {
  40. TRACE0("创建窗口失败!\n");
  41. returnFALSE;
  42. }
  43. m_pFrmWnd->ShowWindow(SW_NORMAL);
  44. //创建视图
  45. m_pFrmWnd->CreateCustomView();
  46. AfxSetResourceHandle(AfxGetApp()->m_hInstance);
  47. returnTRUE;
  48. }
  49. /*******************************************************************
  50. *函数名称:CreateCustomView
  51. *功能:创建视图
  52. *参数:
  53. *返回值:
  54. *******************************************************************/
  55. voidCCustomFrameWnd1::CreateCustomView()
  56. {
  57. CCreateContextcontext;
  58. context.m_pCurrentDoc=NULL;
  59. context.m_pCurrentDoc=NULL;
  60. context.m_pCurrentFrame=this;
  61. context.m_pLastView=NULL;
  62. context.m_pNewDocTemplate=NULL;
  63. context.m_pNewViewClass=RUNTIME_CLASS(CCustomView1);
  64. m_pView=static_cast<CCustomView1*>(this->CreateView(&context));
  65. }

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

  1. private:
  2. CCustomManage1m_CustomManage1;

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

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

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

  1. /*******************************************************************
  2. *函数名称:DestroyFrameWnd
  3. *功能:销毁动态创建的窗口
  4. *参数:
  5. *返回值:
  6. *******************************************************************/
  7. voidCCustomManage1::DestroyFrameWnd()
  8. {
  9. HWNDhWnd=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. }

效果图如下:

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

教程下载(文档下载地址:http://www.ctdisk.com/file/1758317

你可能感兴趣的:(dll)