3/19/2005

示例:在MFC程序中集成.Net中的控件

从.Net Framework 1.1开始,.Net控件可以以ActiveX的方式被集成到非托管宿主中——但是官方的支持只对于使用托管C++的MFC程序。Chris Sells2003年3月份的MSDN杂志中描述了这样一个示例(http://msdn.microsoft.com/msdnmag/issues/03/03/WindowsForms/default.aspx)。这个示例使用的代码稍微繁琐,而且没有描述如何处理控件的事件。MFC 8.0增加了一系列这方面的支持来把这个集成过程简单化(参考http://msdn2.microsoft.com/library/ahdd1h97.aspx)。这使得在MFC程序中使用.Net中的一些比较好用的类,例如System::Windows::Forms::PropertyGrid比以前容易多了。

示例图片

举例来说,要在MFC的基于对话框的程序中使用System::Windows::Forms::PropertyGrid控件,首先创建一个基于对话框的程序,添加必要的引用:

#include <afxwinforms.h>// MFC Windows Forms support
#using <system.dll>
#using <Microsoft.VisualC.Dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <mscorlib.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::ComponentModel;
using namespace Microsoft::VisualC::MFC;
using namespace stdcli::language;

之后添加代码(下面这个类是从MSDN中的充分利用.NET 框架的PropertyGrid 控件这篇文章里面借过来的,关于此控件的更加高级的使用方法也可以参考这篇文章)。

public ref class AppSettings
{
    public:
    [Description("文档设置"), Category("文档设置"), DefaultValue(false)]
        property Boolean saveOnClose ;
    [Description("文档设置"),Category("全局设置"), ReadOnly(true),DefaultValue("欢迎使用应用程序!")]
        property String^ greetingText ;
    [Category("全局设置"), DefaultValue(4)]
        property Int32 itemsInMRU ;
    [Description("以毫秒表示的文本重复率。"), Category("全局设置"),DefaultValue(10)]
        property Int32 maxRepeatRate ;
    [Browsable(false), DefaultValue(false)]
        property Boolean settingsChanged ;
    [Category("版本"), DefaultValue("1.0"), ReadOnly(true)]
        property String^ appVersion ;
    AppSettings()
    {
        this->saveOnClose = true;
        this->greetingText = gcnew String("欢迎使用应用程序!");
        this->maxRepeatRate = 10;
        this->itemsInMRU = 4;
        this->settingsChanged = false;
        this->appVersion = gcnew String("1.0");
    }
};
 

class CPropertyGridTestDlg : public CDialog

{

    //为了偷懒起见,向导生成的默认代码省略

    CWinFormsControl<System::Windows::Forms::PropertyGrid> m_wndPropertyGrid;

    BEGIN_DELEGATE_MAP( CPropertyGridTestDlg )
        EVENT_DELEGATE_ENTRY( PropertyValueChanged , Object, PropertyValueChangedEventArgs )
        EVENT_DELEGATE_ENTRY( HandleDestroyed , Object, EventArgs )
    END_DELEGATE_MAP()
public:
    void PropertyValueChanged ( Object^ sender, PropertyValueChangedEventArgs ^ e )
    {
        TRACE("PropertyValueChanged %S\n", marshal_as<CString>(e->ToString()));
    }
    void HandleDestroyed( Object^ sender, EventArgs ^ e )
    {
        TRACE("PropertyValueChanged %S\n", marshal_as<CString>(e->ToString()));
    }
};

BOOL CPropertyGridTestDlg::OnInitDialog()
{

    //为了偷懒起见,向导生成的默认代码再次省略

    // TODO: 在此添加额外的初始化代码
    CRect rect;
    GetDlgItem(IDC_PLACEHOLDER)->GetWindowRect(rect);//IDC_PLACEHOLDER是一个用来占地方的Static控件
    GetDlgItem(IDC_PLACEHOLDER)->DestroyWindow();
    ScreenToClient(rect);


    m_wndPropertyGrid.CreateManagedControl( WS_VISIBLE|WS_CHILD, rect, this, IDC_PLACEHOLDER );
    System::Windows::Forms::PropertyGrid^ pGrid=m_wndPropertyGrid.GetControl();

    AppSettings^ appSettings=gcnew AppSettings;
    pGrid->SelectedObject=appSettings;

    pGrid->PropertyValueChanged += MAKE_DELEGATE( PropertyValueChangedEventHandler ,PropertyValueChanged );

    pGrid->HandleDestroyed += MAKE_DELEGATE( System::EventHandler , HandleDestroyed );

}

在VC2005二月份的CTP中使用这个功能还有一些小问题:启动的时候输出窗口有几个警告:还有一个Assert窗口,可以简单地忽略。退出的时候有一个原因不明的内存泄漏。

题外话:尽管我确定marshal_as这个函数2004年4月就在可用(在2004年4月的全球MVP峰会上,我亲眼看见对这个函数的引用在Visual C++ 2005中通过了编译),但是到目前为止我还没发现这家伙到底在哪个头文件或者名称空间里面。为了平时偷懒起见,我不得不自己写了一个模板函数。

template<typename T>
interior_ptr<T> marshal_as (String^ s)
{
    interior_ptr<const System::Char> txt=PtrToStringChars (s);
    return interior_ptr<T>(txt);
}

这个模板函数在微软的MSDN里面也是语焉不详,或许这个函数现在还没有启用吧。

3/17/2005

《转换指南: 将程序从托管扩展C++迁移到C++/CLI》译后记

终于把Stan Lippman先生的这篇文章译完了。从去年4月在全球MVP峰会上拿到这篇文章的手稿到现在,差不多一年过去了。虽然当时的Visual Studio 2005还不支持一些语法,但是我和董颖涛对新的C++/CLI语言都很感兴趣,在当时就讨论过翻译的问题。之后我就开始翻译这篇文章,但是进度一直很慢——主要是杂务太多、语言上的困难(尽量避免误解和词不达意的情况,以及斟酌用词的选择)。在1月份完成了全文之后,看到了Sunhui的一篇文章(http://community.csdn.net/expert/Topicview1.asp?id=3834281),觉得附录里面讲到的一些内容或许一些人也有兴趣,所以继续翻译附录的工作,幸好现在是春假,比较有时间,终于在今天完成了。译文目前在http://blog.csdn.net/jiangsheng/archive/2004/10/18/140450.aspx可以访问,希望读者指正。

在翻译过程中得到了曾毅的帮助,得以联系到Stan Lippman先生,在此一并感谢。

文章简介:

C++/CLI代表ISO-C++标准语言的一个动态编程范型扩展(dynamic programming paradigm extension). 在原版语言设计(V1)中有许多显著的弱点,我们觉得在修订版语言设计(V2)中已经修正了。 本文列举了V1版本语言的特色和它们在V2版本中的对应 (如果有这样的对应存在的话);并指出为对应不存在的V1特色构建的语言特性。对于有兴趣的读者,附录中提供新语言设计的扩展原理。 另外,一个源代码级别的转换工具(mscfront)正在开发中,而且可能在C++/CLI的发布版中提供给希望 自动化移植V1代码到新语言设计的人。

本文分为五个章节加一个附录。第一节讨论主要的语言关键字,特别是双下划线的移除以及上下文性分段关键字。 第二节着眼于托管数据类型的变化——特别是托管引用类型和数组类型。还可以在这里找到有关确定性终结化语义(deterministic finalization)的详细讨论。关于类成员的变化,例如属性、索引属性和操作符,是第三节的焦点。第四节着眼于托管枚举、内部和约束指针的语法变化。它也讨论了许多可观的语义变化,例如隐式装箱的引入、托管CLI枚举的变化,和对类默认构造函数的支持的移除。第五节有几分像大杂烩——声名狼藉的杂项。可以在里面找到对类型转换符号、字符串常数的行为和参数数组的讨论。

 

3/05/2005

Win32 to .NET API Map

.Net类库提供了Windows API的封装。下面的文章描述了实现类似Win32函数功能的.Net架构1.0和1.1API。

Microsoft Win32 to Microsoft .NET Framework API Map

  • 只有一小部分的Win32函数在.Net中有对应,但是会越来越多。
  • 部分新的API不会提供Win32函数版本。其中已知的有Avalon的高层函数。
  • 建议从Win32转移到.Net的开发者看看
  • 如果你没有找到某个API在.Net的对应,尝试去http://www.pinvoke.net/ 看一看。这是一个开放的WIKI,描述了一些Win32函数在托管代码中的对应函数或者代码(基本上都是用VB.Net或者C#写的,但是很容易翻译成其他.Net语言)