正文

[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,我们没必要不领微软的情。我采用的是一种API和MFC结合的方式。我们把调用DLL模块的程序叫宿主程序,把封装窗体的DLL叫客户程序。   首先我们建一个使用共享MFC的规则DLL工程Custom1。我的基本想法是这样的:定义三个类: 类名 描述 备注 CCustomManage1 对外接口类,该类负责动态窗口的创建和销毁。   CCustomFrameWnd1   派生自CFrameWnd,为动态创建的框架窗口类。   CCustomView1   派生自CView,为动态创建的视图类。           大致的设计是这样的:在CCustomManage1类定义一个CCustomFrameWnd1类的指针,在CCustomFrameWnd1类定义一个CCustomView1类的指针。   主要创建代码如下: view plaincopy to clipboardprint? /*******************************************************************  * 函数名称:CreateFrameWnd  * 功   能:动态创建框架视图  * 参   数:  * 返回值:TRUE标识创建成功,FALSE表示创建失败  *******************************************************************/   extern CCustom1App theApp;   BOOL CCustomManage1::CreateFrameWnd()   {       // 确保资源句柄有效       AfxSetResourceHandle(theApp.m_hInstance);          m_pFrmWnd = new CCustomFrameWnd1();          CString wndClass = _T(""); // 用于保存窗口类名称          try       {           // 注册窗口类           wndClass = ::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE), 0);          }       catch (CResourceException* pEx)       {           TCHAR   szCause[255];           CString strFormatted;              pEx->GetErrorMessage(szCause, 255);              strFormatted = _T("窗口创建失败原因: ");           strFormatted += szCause;           AfxMessageBox(strFormatted);           pEx->Delete();              return FALSE;       }          // 设定窗口的大小       RECT rc;       rc.top = 0;       rc.left = 0;       rc.bottom = 600;       rc.right = 800;       CString csWindowName = _T("使用动态创建的方式封装框架试图");       // 正式创建窗口       if( !m_pFrmWnd->Create(wndClass,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL))       {           TRACE0("创建窗口失败!\n");           return FALSE;       }          m_pFrmWnd->ShowWindow(SW_NORMAL);          // 创建视图       m_pFrmWnd->CreateCustomView();          AfxSetResourceHandle(AfxGetApp()->m_hInstance);       return TRUE;   }      /*******************************************************************  * 函数名称:CreateCustomView  * 功   能:创建视图  * 参   数:  * 返回值:  *******************************************************************/   void CCustomFrameWnd1::CreateCustomView()   {       CCreateContext context;       context.m_pCurrentDoc = NULL;       context.m_pCurrentDoc =  NULL;       context.m_pCurrentFrame = this;       context.m_pLastView = NULL;       context.m_pNewDocTemplate = NULL;       context.m_pNewViewClass = RUNTIME_CLASS(CCustomView1);       m_pView = static_cast<CCustomView1*>(this->CreateView(&context));         }   /******************************************************************* * 函数名称:CreateFrameWnd * 功 能:动态创建框架视图 * 参 数: * 返回值:TRUE标识创建成功,FALSE表示创建失败 *******************************************************************/ extern CCustom1App theApp; BOOL CCustomManage1::CreateFrameWnd() { // 确保资源句柄有效 AfxSetResourceHandle(theApp.m_hInstance); m_pFrmWnd = new CCustomFrameWnd1(); CString wndClass = _T(""); // 用于保存窗口类名称 try { // 注册窗口类 wndClass = ::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE), 0); } catch (CResourceException* pEx) { TCHAR szCause[255]; CString strFormatted; pEx->GetErrorMessage(szCause, 255); strFormatted = _T("窗口创建失败原因: "); strFormatted += szCause; AfxMessageBox(strFormatted); pEx->Delete(); return FALSE; } // 设定窗口的大小 RECT rc; rc.top = 0; rc.left = 0; rc.bottom = 600; rc.right = 800; CString csWindowName = _T("使用动态创建的方式封装框架试图"); // 正式创建窗口 if( !m_pFrmWnd->Create(wndClass,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL)) { TRACE0("创建窗口失败!\n"); return FALSE; } m_pFrmWnd->ShowWindow(SW_NORMAL); // 创建视图 m_pFrmWnd->CreateCustomView(); AfxSetResourceHandle(AfxGetApp()->m_hInstance); return TRUE; } /******************************************************************* * 函数名称:CreateCustomView * 功 能:创建视图 * 参 数: * 返回值: *******************************************************************/ void CCustomFrameWnd1::CreateCustomView() { CCreateContext context; context.m_pCurrentDoc = NULL; context.m_pCurrentDoc = NULL; context.m_pCurrentFrame = this; context.m_pLastView = NULL; context.m_pNewDocTemplate = NULL; context.m_pNewViewClass = RUNTIME_CLASS(CCustomView1); m_pView = static_cast<CCustomView1*>(this->CreateView(&context)); } 为了防止内存泄露,我们需要考虑防止如何销毁窗口。为了更好地说明这个问题,我先建一个调用该DLL的单文档工程Ower来说明这个问题。现在Ower工程的框架类CMainFrame类定义一个CCustomManage1类的私有变量:     view plaincopy to clipboardprint? private:       CCustomManage1 m_CustomManage1;   private: CCustomManage1 m_CustomManage1; 然后新建一个菜单项,在菜单项的命令响应函数里弹出新建窗口,具体代码如下: view plaincopy to clipboardprint? void CMainFrame::OnTest1()   {       // TODO: 在此添加命令处理程序代码       m_CustomManage1.CreateFrameWnd();   }   void CMainFrame::OnTest1() { // TODO: 在此添加命令处理程序代码 m_CustomManage1.CreateFrameWnd(); }  这时我们需要考虑用户是怎么关闭新建窗口,用户就是要么是单击调用程序的关闭按钮把两个窗口都关闭;要么单击DLL弹出的新建窗口的关闭按钮。那么在实现CCustomManage1类的DestroyFrameWnd函数里需要考虑这一点,防止用户先关闭新建窗口,再关闭调用程序时出错,就是要确保关闭时窗口句柄是有效的。       view plaincopy to clipboardprint? /*******************************************************************  * 函数名称:DestroyFrameWnd  * 功   能:销毁动态创建的窗口  * 参   数:  * 返回值:  *******************************************************************/   void CCustomManage1::DestroyFrameWnd()   {       HWND hWnd = NULL;       if (NULL!=m_pFrmWnd)       {           // 确保窗口的句柄有效,才进行销毁窗口操作           hWnd = m_pFrmWnd->GetSafeHwnd();           if(::IsWindow(hWnd))           {               m_pFrmWnd->DestroyWindow();           }       }    }   // 在析构函数里调用该函数   CCustomManage1::~CCustomManage1(void)   {       DestroyFrameWnd();   }          /******************************************************************* * 函数名称:DestroyFrameWnd * 功 能:销毁动态创建的窗口 * 参 数: * 返回值: *******************************************************************/ void CCustomManage1::DestroyFrameWnd() { HWND hWnd = NULL; if (NULL!=m_pFrmWnd) { // 确保窗口的句柄有效,才进行销毁窗口操作 hWnd = m_pFrmWnd->GetSafeHwnd(); if(::IsWindow(hWnd)) { m_pFrmWnd->DestroyWindow(); } } } // 在析构函数里调用该函数 CCustomManage1::~CCustomManage1(void) { DestroyFrameWnd(); }       效果图如下:           当然你还可以测试在DLL的新建窗口的是否可以加载工具栏,响应Windows的标准消息。我测试过是可以的。

阅读(6061) | 评论(1)


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

评论

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