经典与现代的结合:在MFC中集成RAD.NET框架
下面图老师小编跟大家分享经典与现代的结合:在MFC中集成RAD.NET框架,一起来学习下过程究竟如何进行吧!喜欢就赶紧收藏起来哦~
namespace test
{
__gc public class testDocObject
: public Object
{
public:
testDocObject(void)
{
}
};
} 经过以上步骤,Visual Studio.NET生成的代码被装进了MFC程序,当然完全可以手动创建.h文件和.cpp文件,输入相应的代码,然后把它们添加到当前工程。由于以上步骤在托管扩展编程中经常碰到,因此,将上述过程自动化是必要的,有鉴于此,我们在附赠的光盘中提供了完整的添加.NET对象的Wizard。 在MFC非托管类中定义托管成员变量 在MFC类中使用托管对象,提供对象的声明和初始化方法与传统的方法略有不同。以在文档类CtestDoc中添加一个托管成员变量为例,声明托管对象的代码如下:以下是引用片段:
public:
gcroottest::testDocObject* m_ptestDocObj; gcroot类型安全包装模板可以将托管参考类型指针作为成员变量嵌入到非托管类中,该变量就可以像其他类型的变量一样使用了。在CtestDoc的成员函数InitialDocument中创建这个对象,代码如下:以下是引用片段:
BOOL CtestDoc::InitialDocument()
{
#pragma push_macro("new")
#undef new
m_ptestDocObj = new test::testDocObject();
#pragma pop_macro("new")
} 由于testDocObject是一个托管参考类型,它总被分配在CLR堆上,所以自然不能使用在afx.h中定义的new操作符来直接初始化该对象以避免该托管对象在非托管的本地C++堆上创建导致的错误。在托管对象中声明MFC对象,与常规方法一致。 把握了上述的基本托管类和对象在传统MFC项目中的对偶使用方法,就可以保证您充分使用.NET框架所提供的丰富的类库支持(引用相关的动态链接库并声明名称空间是必要的)。假如希望更多地了解托管和非托管C++代码混用的技术,可以参考Tom Archer与Nishant Sivakumar合著,由Addison Wesley出版社出版的《Extending MFC Applications with the .NET Framework》一书,相信会很有帮助。 宿主.NET控件 宿主.NET控件的理论基础 在.NET Framework的世界里,功能丰富的.NET控件无疑是光彩夺目的明珠,MFC程序自然想联姻这些华丽的事物。由于MFC框架不提供对.NET控件的直接支持,从而导致MFC后天的失落(缺乏类似C#、VB.NET特有的可视化设计机制以及自由的控件组织功能),这一点多少成为MFC远离.NET世界的一种合理的客观原因。但是,我们注重到:.NET控件本质上就是ActiveX控件,二者之间的重要区别是注册方式不同——ActiveX控件是全局的,在系统注册表中注册;而.NET控件既可以在全局AssemblyCache中注册,也可以放在局部的目录中,相应的,在程序中获取它们相关信息的方式是不同的。但是,一旦.NET控件的基本信息被我们“捕捉”,我们就可以使用与创建ActiveX控件一致的方法将.NET控件创建到MFC项目中。 (图4:MFC框架中ActiveX控件的创建) 我们知道,MFC是通过COleControlSite类创建ActiveX控件的,由于针对用于ActiveX控件的COleControlSite类不适用于.NET控件,因此必须重新派生一个新类CWFControlSite来提供必要的支持,通过一个CWFControlWrapper类将一个.NET控件包装在一个CWnd窗体中,并将包装后的窗体“安置”在CWFControlSite内。CWFControlWrapper类代码如下:以下是引用片段:
class CWFControlWrapper : public CWnd
{
public:
CWFControlWrapper();
virtual ~CWFControlWrapper(void);
IUnknown *pUnkControl;
IUnknown *GetManagedControl()
{
return pUnkControl;
}
void SetControlSite(COleControlSite *pSite)
{
m_pCtrlSite = pSite;
}
}; 下一步,要设计一个通用的CUserCtrlView类(从CView类派生),使得在CWFControlSite中指定的.NET控件可以像在COleControlSite中指定的ActiveX控件一样显示给用户。正象每个ActiveX控件必需用一个CWnd对象进行创建一样,一个支持.NET控件的CView类需要一个对应的CWnd对象,CWFControlWrapper就是针对这个目的设计的,通过CWFControlWrapper对象,MFC程序可以得到.NET对象对应的IUnknow、IDispatch。稍后我们介绍CUserCtrlView类的具体设计和使用方法。 (图5:MFC框架中.NET控件的创建) NET控件的消息处理 一般而言,控件的对话框消息处理是一个极为要害的问题,在网上能找到的MFC中宿主控件的解决方法中,均没有实现.NET控件的对话框消息处理,一个明显的特征是不能处理“Tab”键消息。为此,我们重载了CUserCtrlView的PreTranslateMessage函数:以下是引用片段:
BOOL CUserCtrlView::PreTranslateMessage(MSG *pMsg)
{
BOOL bRet = FALSE;
if(m_Control.pUnkControl != NULL)
{
CComQIPtrIOleInPlaceActiveObject
spInPlace(m_Control.pUnkControl);
if(spInPlace)
bRet =(S_OK == spInPlace-
TranslateAccelerator(pMsg)) ?
TRUE : FALSE;
}
if(CView::PreTranslateMessage(pMsg))
return TRUE;
CFrameWnd *pFrameWnd = GetTopLevelFrame();
if(pFrameWnd != NULL
&& pFrameWnd-m_bHelpMode)
return FALSE;
// start with first parent frame
pFrameWnd = GetParentFrame();
while(pFrameWnd != NULL)
{
if(pFrameWnd-PreTranslateMessage(pMsg))
return TRUE;
pFrameWnd = pFrameWnd-GetParentFrame();
}
return bRet;
} 这样可以使得CUserCtrlView可以正确的处理.NET Control的对话框消息。 回归RAD世界 接下来我们看看如何在工程中插入一个.NET用户自定义控件。我们增加一个新的托管类testControl,代码如下以下是引用片段:
#pragma once
...
namespace test
{
public __gc class testControl :
public System::Windows::Forms::UserControl
{
public:
testControl(void)
{
InitializeComponent();
}
protected:
void Dispose(Boolean disposing)
{
if(disposing && components)
components-Dispose();
__super::Dispose(disposing);
}
private:
System::Windows::Forms::Label *label1;
System::ComponentModel::Container
*components;
void InitializeComponent(void)
{
this-label1 = new
System::Windows::Forms::Label();
this-SuspendLayout();
this-label1-Location =
System::Drawing::Point(16, 24);
this-label1-Name = S"label1";
this-label1-Size =
System::Drawing::Size(208, 16);
this-label1-TabIndex = 0;
this-label1-Text =
S"Welcome to TZ MFC.NET!";
this-Controls-Add(this-label1);
this-Name = S"testControl";
this-Size =
System::Drawing::Size(240, 160);
this-ResumeLayout(false);
}
};
} 注重,testControl类继续自UserControl类,用户控件是开发者创建的任何控件,您可以将多个.NET控件组织在一起,添加功能代码,然后把它作为一个更综合一些的控件来使用,使用每一个用户控件和使用其他的.NET标准控件的步骤都是没有区别的。在上面的代码中,我们自定义的用户控件仅包含了一个.NET Label控件。 到目前为止,我们已经可以在原生MFC项目中成功插入.NET控件。然而,因为上面的.NET控件的插入是纯手工方式的,不直观且很难驾驭,一个聪明的办法是实现一个集成在Visual Studio .NET IDE中的Wizard,以使得MFC工程中可以直接使用可视设计器,在随机光盘中,我们提供了相关的Wizard,安装后您就可以直接在MFC项目中插入并可视化设计.NET用户控件了。 通过集成的Wizard,传统的MFC可以与现代的.NET RAD机制完美的结合在一起,使得你既可以得到传统C++的优雅,又可以享有现代RAD机制的风韵,对资源的整合力度也极大地扩展了。