65.9K
CodeProject 正在变化。 阅读更多。
Home

CM_ConfigBuilder 1.2g:适用于应用程序设置图形管理的 Visual Studio 6/Visual Studio 2005/Visual Studio 2008 代码生成器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (113投票s)

2004 年 4 月 14 日

CPOL

17分钟阅读

viewsIcon

718275

downloadIcon

9925

CM_ConfigBuilder 可生成并编译必要的文件,以管理应用程序的设置/偏好,并将它们以 XML 格式存储/检索。

Screenshot - screen_shot1_small.jpg

最新更新

CM_Configbuilder 版本 1.2G
1. 修复了 Visual C++ 6.0 项目生成器的问题
2. 修复了 Visual C++ 6.0 测试项目模板的问题

引言

大约两年前,每次客户问我:“你能让这个参数可配置吗?” 我就开始感到厌烦。每次我让一个参数可配置时,都需要编写代码来执行以下操作:将参数保存到文件、从文件检索参数、设置一些图形控件以允许用户更改其值(例如文本框或其他输入控件),以及验证用户设置的值。因此,我决定创建一个工具来为我完成所有这些操作。

第一步是创建一个工具来描述我应用程序中所需参数的结构。第二步是添加描述用户如何编辑数据的能力。第三步是构建一个包含所有必需代码的库。所有这些愿望促使我编写了 CM_ConfigBuilder。CM_ConfigBuilder 生成管理我的数据结构并使其在 XML 文件中持久化的所有代码。CM_ConfigBuilder 生成的 GUI 显示一个包含层次结构中所有类的树视图。

Click to enlarge

Click to enlarge

以下是一个简短的教程,展示了如何创建简单的配置。

步骤 1:创建一些类成员

让我们创建一个由一个根类和三个属性组成的简单配置。要向类添加成员,请右键单击树视图并选择您要添加的项。在此示例中,我们将添加三个成员。

image

通过选择一个成员(在树视图中),我们将在右窗格中看到一组选项卡。第一个选项卡(“global”)包含成员的名称、其标题(用于 GUI)和“持久性模式”。

image

持久性模式可以设置为以下值:

  • “no persistence”(无持久性):生成器将创建成员,但它们不会保存到文件(或从文件中加载)。
  • “XML child node persistence”(XML 子节点持久性):生成器将创建方法,将成员作为容器类的 XML 子节点进行保存。
  • “XML attribute”(XML 属性):该属性将存储为类节点属性。
  • “#text node”(#text 节点):该属性将存储为父标签内的文本节点。只能有一个成员可以持久化为 #text 节点。

步骤 2:设置成员的数据类型

CM_ConfigBuilder 允许定义成员的数据类型:字符串、长整型、布尔型、双精度、日期、时间。默认情况下,成员的数据类型设置为“string”(C++ 生成器使用一个名为 cmStringCString 派生类)。

image

步骤 3:设置成员的验证

成员验证目前支持“Static Enum”(静态枚举)和“Custom Validation”(自定义验证)。

Static Enum(静态枚举)
image

当选择“Static Enum”验证时,CM_ConfigBuilder 会生成:

  • Get 方法(返回当前的枚举值)。
  • Set 方法(设置当前的枚举值)。
  • Get_Value 方法(返回与当前枚举值关联的值)。

具有“Static Enum”验证的字段将由 ComboBox 控件编辑。“Default Values”(默认值)列可用于指定未初始化字段的默认显示值。“Clear Default”(清除默认值)按钮将清除整列:生成器将初始字段值设置为 0。因此,我们可以设置一个成员变量(长整型、字符串或双精度)并将其验证为枚举值。让我们看一个例子。

我们需要声明一个代表采样率的类成员(我们称之为 SampleRate)。我们只想管理几个值:10.55Hz、100.9Hz、1.5KHz。为此,我们只需创建一个数据类型为“double”的成员。如果将其验证为“Static Enum”,我们可以指定枚举值。

名称 Enum Value(枚举值) Associated Value(关联值) 描述
1 低功耗 1 10.55 Low sample rate(低采样率)
2 媒体 5 100.9 Medium sample rate(中等采样率)
3 10 1500 High sample rate(高采样率)

Cm_ConfigBuilder 生成以下代码:

typedef enum enSampleRate 
{ 
    enSampleRate_Low = 1, 
    enSampleRate_Medium = 5, 
    enSampleRate_High = 10 
} 

enSampleRate;
           
void SetSampleRate(enSampleRate newValue);
enSampleRate GetSampleRate() const;
double GetSampleRate_Value() const; 
// this methods returns 10.55 when sampleRate is enSampleRate_Low

这样,就可以轻松进行比较(if (GetSampleRate() == enSampleRate_Low)...)以及进行计算(double x = GetSampleRate_Value()* 10)。

自定义验证

CM_ConfigBuilder 可以生成一个接口。此接口包含每个使用自定义验证的成员的验证函数。项目中的每个类成员都可以针对每个类具有一个验证函数。验证过程已与一组可能的结果关联:

  • Error(错误):显示错误图标( validation_error )和错误消息。
  • Warning(警告):显示警告图标( validation_warning )和警告消息。
  • Question(问题):显示问题图标( validation_question )和问题消息。
  • Info(信息):显示信息图标( validation_info )和信息消息。
  • Ok(确定):不显示任何图标或消息。
GUI mode(GUI 模式):当用于输入类成员值的文本框失去焦点时,会调用验证函数。当显示类对话框(类别列表)时,也会调用相同的函数。对于 ATL 代码生成,验证函数声明如下:
image

如果为类成员启用自定义验证,您将获得以下函数:

// 
// VB Sample
//
Implements ItestRootValidator

Private Sub ItestRootValidator_MEMBERNAME_OnLostFocus(_
    parent As CLASS, value As DATATYPE)

    ' if you implement this interface you could change value
    ' call SetMemberValidationStatus (enum memberId, validationStatus)
    ' to indicate the icon to display
    parent.SetMemberValidationStatus enAttributeId_MEMBERNAME, _
        enValidationResult_Error

    ' call SetMemberValidationMsg (enum memberId, _
    ' displayDefaultMsg as Boolean, Msg As String) to indicate the 
    ' message to display
    ' if you set displayDefaultMsg to True the message set in 
    ' figure above will be shown, if you set displayDefaultMsg to 
    ' False you can provide the message to be displayed
    parent.SetMemberValidationStatus enAttributeId_MEMBERNAME, _
        False, "The value you entered is wrong"
End Sub

下图显示了自定义成员验证的一种可能用法:

Screenshot - member_validation_custom_sample.jpg

步骤 4:设置成员的“GUI 模式”

另一项工作是设置“GUI 模式”。我们可以决定成员是可见还是隐藏。

image

对于每个类成员,CM_ConfiguBuilder 将生成一对 Get/Set 方法。如果成员设置为可见,并且生成器配置为生成编辑配置所需的 GUI,则该成员将被显示,并且如果未选中“Read only”(只读)复选框,则可编辑。

步骤 5:配置根类

要配置单个类,我们必须单击树视图中的相应节点。第一个选项卡(“global”)包含关于类的常规信息:其名称、其标题(显示在生成的 GUI 的树视图中)以及其容器标题。当类的基数是 ArrayMap 时(参见 CM_ConfigBuilder_samples.zip 中的 sample 1),将使用容器标题。

Screenshot - class_global.jpg

步骤 6:定义 GUI 模式

“GUI”选项卡允许我们定义我们希望如何查看属性。目前,仅支持“Category list”(类别列表)和“Grid”(网格)。CategoryList 允许按组对类属性进行分组,如下所示。配置面板有两个选项卡:第一个是生成面板的预览,第二个选项卡允许编辑面板结构。

Screenshot - category_list_preview.jpg

Screenshot - category_list_struct.jpg

Grid 样式允许类数组显示在单个表中,其中每一行代表一个类实例。目前,CM_ConfigBuilder 提供以下自定义:

  1. Button bar generation(按钮栏生成)(可以生成带有添加/删除行按钮的工具栏)。
  2. Optional column with row number(可选的行号列)(零或一列对齐)。
  3. GUI style(GUI 样式)(目前,仅提供 classic 和 test1 样式)。
  4. Info area display(信息区域显示)。
Screenshot - grid_preview.jpg

从 1.2c 版本开始,“category list”(由组件 cmOptionList 实现)和“grid”(由组件 cmTable 实现)有了新的样式(即将支持自定义)。

cmOptionList 的示例(style1

Screenshot - cmOptionList_Style1.jpg

cmTable 的示例(style1

Screenshot - cmTable_Style1.jpg

步骤 7:定义基数

“Cardinality”(基数)选项卡允许我们说:“这个类不是单个实例。” 我们可以决定是创建类数组还是类映射。这些设置在 sample 1 中显示(参见 CM_ConfigBuilder_samples.zip 中的 sample 1)。附注:此版本不支持数组或映射的最小/最大大小。

Screenshot - class_cardinality.jpg

步骤 8:定义树图标

“Tree Icons”(树图标)选项卡允许我们指定树视图中将显示哪些图标。对于非“单实例”类(参见 Cardinality),可以指定将在容器节点上显示的图标。

image

步骤 9:类验证

Screenshot - class_validation.jpg

如果您需要为类实现特定的验证过程,您需要设置上面的面板。对于每个类,您可以选择要进行的验证类型:

  • No Validation(无验证):此类的验证接口将不会生成。
  • Use Default Class Callbacks(使用默认类回调):CM_ConfigBuilder 生成一个带有为默认类配置的回调的验证接口(菜单:Code Generation -> Default Class)。
  • Use Custom Callbacks(使用自定义回调):您可以启用所需的回调。
    • Initial validation method(初始验证方法):此方法(如果启用)将在调用 MainDialog 上的 SetData 方法时调用。这允许您执行首次验证。
    • Final validation method(最终验证方法):此方法(如果启用)将在用户按下 OK 按钮时调用。这允许您执行对用户输入的所有值的最终检查。
    • GetFocus validation method(获取焦点验证方法):每次显示类时都会调用此方法。
    • LostFocus validation method(失去焦点验证方法):每次隐藏类(并显示新类)之前都会调用此方法。

您还可以决定是显示默认消息(在 Default Class 设置中定义)还是提供特定于类的消息。对于基数为 Map 或 Array 的类,您可以有一个 Container Class Validation Interface(容器类验证接口)。您可以像配置 Class Validation Interface 一样配置它,并获得更多方法:

  • OnBeforeItemAdd:在用户尝试将新项添加到类 Container(Array 或 Map)时调用。
  • OnBeforeItemDelete:在用户尝试从类 Container(Array 或 Map)中删除项时调用。

每个类都有两个附加方法:

  • SetClassValidationStatus:允许您指示在与类关联的树视图节点工具提示中显示的验证图标。如果选择 enValidationResult_Error,树视图项文本将以红色显示。
  • SetClassValidationMsg:允许您指示在与类关联的树视图节点工具提示中显示的验证消息。
Screenshot - class_validation_sample.jpg

步骤 10:自定义主对话框

CM_ConfigBuilder 允许您自定义名为“Main Dialog”(主对话框)的对话框。

Screenshot - main_dialog_general.jpg

Screenshot - main_dialog_tree.jpg

步骤 11:为 MFC DLL 设置选项

定义自定义数据结构后,可以通过选择菜单“Code Generation >> Options...”来访问选项。通过选中“Enable C++ code generation”(启用 C++ 代码生成),我们可以设置 C++ 库的生成。

  • Class prefix(类前缀):此前缀用于创建类的名称。对于“Root”类,将创建两个对应的文件 CfgSample_Root.h/cpp。使用“class prefix”字段允许我们在同一项目中 O 使用具有不同前缀的不同配置。类前缀将用作库的名称。
    CfgSample_D.lib 调试版本的库
    CfgSample_D.dll 调试版本的库
    CfgSample_DU.lib Unicode 调试版本的库
    CfgSample_DU.dll Unicode 调试版本的库
    CfgSample_R.lib 发布版本的库
    CfgSample_R.dll 发布版本的库
    CfgSample_RU.lib Unicode 发布版本的库
    CfgSample_RU.dll Unicode 发布版本的库
  • Generation path(生成路径):此字段指定生成器将创建所有目录和文件的位置。
  • DLL file name prefix(DLL 文件名首缀):此字段指定生成库(DLL)的名称首缀。最终名称将遵循以下格式:<name>_<configuration>.dll(configuration 为 _D 代表 Debug,_DU 代表 DebugUnicode,_R 代表 Release,_RU 代表 ReleaseUnicode)。
  • Visual Studio Version(Visual Studio 版本):允许您指定将使用哪个版本的 Visual Studio 来生成库项目。
  • After build, copy...(构建后复制...):此字段指定构建步骤完成后 DLL 将被复制到何处(例如,我们可以设置应用程序的主目录)。
  • Generate Test project(生成测试项目):如果选中此复选框,生成器将创建一个简单的(非常简单的)项目来测试生成的库。
  • Generate GUI(生成 GUI):如果选中此复选框,生成器将生成一个 GUI 来编辑类。我们还可以通过设置资源偏移量来避免资源重叠。
  • Delete previously generated files(删除先前生成的文件):此功能尚不支持
image

关于 Visual Studio 2005 的说明:如果您需要将这些库与 Visual Studio 2005 一起使用,只需用 Visual Studio 2005 打开生成的项目(*.dsw)并进行编译即可。

步骤 12:为 ATL DLL 设置选项

ATL 生成允许 Visual Basic 用户访问类层次结构。通过选中“enable ATL code generation”(启用 ATL 代码生成),我们可以设置 ActiveX ATL 库的生成。

  • Class prefix(类前缀):参见 C++ 库生成。
  • Generation path(生成路径):指定生成器将创建所有目录和文件的位置。
  • After build, copy...(构建后复制...):此字段指定构建步骤完成后 DLL 将被复制到何处(例如,我们可以设置应用程序的主目录)。
  • Generate Test project(生成测试项目):如果选中此复选框,生成器将创建一个简单的(非常简单的)项目来测试生成的库。
  • Generate GUI(生成 GUI):如果选中此复选框,生成器将生成一个 GUI 来编辑类。我们还可以通过设置资源偏移量来避免资源重叠。
  • Delete previously generated files(删除先前生成的文件):此功能尚不支持
  • Reset GUIDs(重置 GUID):此按钮将重置与类关联的所有 GUID。如果您不按此按钮,所有类将保持相同的 GUID,这将避免需要重新编译使用该库的应用程序。
  • 注意:生成的 ATL 项目支持以下配置:Debug、Release Min Size、Release Min Dependency、Unicode Debug、Unicode Release Min Size、Unicode Release Min Dependency。
image

步骤 13:最后……代码生成!!!

选择菜单“Code generation >> Go”,我们将看到生成器对话框。按下“Generate”(生成)按钮,最终得到我们想要的结果!对于 C++ 和 ATL 生成器,我们可以定义一些后置步骤:

  • Compile Library(编译库):如果选中,Visual C++ 将自动启动并编译库;调试或发布取决于“debug”(调试)或“release”(发布)复选框(ATL 库为 release Min Dependencies)。
  • Open project with MSDEV(用 MSDEV 打开项目):此选项将启动 Visual C++ 并打开库项目。您可以通过按 F7 来编译!如果编译过程中出现错误,此选项很有用。我更希望 0 错误和 0 警告;)
  • Do nothing(什么都不做):不执行任何操作。如果 Visual C++ 已经打开,此选项很有用。
image

步骤 14:发生了什么?

生成和编译完成后,我们应该看到以下目录结构:

image

该结构显示了一个“global include folder”(全局包含文件夹),其中包含将库集成到我们的应用程序所需的所有包含文件。显然,ATL 组件不需要包含文件。该结构显示了一个“global lib folder”(全局库文件夹),其中包含由构建过程生成的所有 *.lib*.dll 文件。

步骤 15:将库集成到您的 MFC 应用程序中

要将生成的库集成到我们的应用程序中,我们需要遵循以下步骤:

  • 在菜单“project >> settings >> C/C++ >> preprocessor”中,添加指向“global include folder”的路径。
  • 在菜单“project >> settings >> link >> input >> object/library modules”中,添加 cfgSample_D.lib(对于调试版本)。
  • 在菜单“project >> settings >> link >> input >> additional library path”中,添加指向全局库文件夹的路径。
  • 在项目的“file view”(文件视图)中,添加生成类的头文件,以便它们具有 Intellisense 支持。只需添加所有 CfgSample_*.hxmlserializable.h

以下代码展示了如何使用这些类:

// 
// C++ sample
//
Cfg_Root root;
Cfg_CfgManagerDlg dlg;
UINT ret;

ret = root.LoadFromXmlFile("mySettings.xml");
if (!ret) 
{
    // file not found: set defaults
    //
    root.SetMember1("default value");
    root.SetMember2(10000);
    root.SetMember3(true);
}
dlg.SetData(root);
ret = dlg.DoModal(); // display modal dialog
if (ret == IDOK) {
   root = dlg.GetData();
   root.SaveToXmlFile("mySettings.xml");
}

// embedded dialog sample
//
BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();
    
    Cfg_Root root;
    Cfg_CfgManagerDlg dlg;
    UINT ret;

    ret = root.LoadFromXmlFile("mySettings.xml");

    dlg_.CreateAndEmbed(this, CRect(0, 0, 100, 100));   
    // dlg_ should be declared as class member
    dlg_.SetData(root);
}

从 1.2b 版本开始,每个单独的类对话框都可以嵌入到您的应用程序中。每个对话框(为类及其容器生成的)都有一个方法:CreateAndEmbed。要将对话框嵌入到您的对话框中,您只需:

  1. 为要嵌入的对话框声明一个成员变量。
  2. 为要在您的窗体中编辑的类或容器声明一个成员变量。
  3. 在您的 OnInitDialog 处理程序中,调用 CreateAndEmbed 方法,并将要编辑的变量通过 SetData 方法传递给嵌入式对话框。
  4. 完成后(例如,在您的 OnOK() 事件处理程序中),调用嵌入式对话框的 StoreData
// 
// C++ sample (how to embed a single class)
//

// header file
//
    
    Cfg_SampleClassDlg dlg_;
    Cfg_SampleClass data_;

// implementation file
//
BOOL CMyClass::OnInitDialog()
{
    CDialog::OnInitDialog();

    dlg_.CreateAndEmbed(this, CRect(0, 0, 200, 200));
    dlg_.SetData(&data_);
}

void CMyClass::OnOK()
{
    dlg_.StoreData();    // this updates data_

    data_.SaveToXmlFile(...) // if you need to store data_
}

您可能会得到类似这样的结果(抱歉……是意大利语的)。

Screenshot - shot9_embedded_dialog.jpg

步骤 16:将库集成到我的 Visual Basic 6.0 应用程序中

要将 ActiveX 组件集成到 Visual Basic 中,您只需选择菜单“Project >> References ...”并选择库“CM_ConfigBuilder Sample2 Type Library 1.0”。

image

以下代码展示了如何从 VB 使用这些类:

' vb sample
'
Dim dlg As New CFGSAMPLE_Lib.MainDialog
Dim cfg As New CFGSAMPLE_Lib.Root
Dim ret As Boolean

ret = cfg.Load("mySettings.xml")
If Not ret Then
    cfg.Member1 = "default value"
    cfg.Member2 = 10000
    cfg.Member3 = True
End If

ret = dlg.Display(cfg)
If ret Then
    cfg.Save "mySettings.xml"
End If

致谢

CM_ConfigBuilder 所使用的许多资源来自 CodeProject。我想感谢:

  • 所有参与 MFCGrid 组件的人。
  • .dan.g. 的 CEnTabControl
  • Sven Wiegand 的 MSXML C++ 包装类。
  • Alvaro Mendez 的 CAMSEdit 验证类。
  • Marc Richarme 的 flat splitter window(平坦分割窗口)。
  • Sven Wiegand 的 CTreePropSheet
  • Kochise Kochise 的 CPathSplit
  • Paul J. Weiss 的 CStringUtils
  • Dana Holt 的 CXSBrowseFolder
  • FahadAsh 的 CCoolButton
  • Frank Luchs 的 CVMBitmap

历史

  • 2008.01.24(版本 1.2F)
    • 添加了 Visual Studio 2008 项目生成。
  • 2007.11.28(版本 1.2E)
    • bugfix:ATL 项目缺少 splitter cursor 文件。
    • bugfix:ATL 项目的“open project folder”(打开项目文件夹)不起作用。
    • bugfix:ATL 项目编译错误(由于新样式)。
    • ATL 项目更新:使用新的 cmTableWnd。
    • bugfix:cmGlassButton 在 vs2005 下不起作用。
    • bugfix:在 vs2005 下加载图标时出现错误。
    • NEW:cm_Configbuilder 项目已移植到 vs2005。
    • NEW:CM_ConfigBuilder 现在能够生成 vs2005 项目,而无需安装 Visual Studio 6.0。
  • 2007.10.30(版本 1.2d)
    • cmTreeCtrl:图标绘制速度更快。
    • Grid dialogs(网格对话框):修复了对话框大小调整时的重绘问题。
    • Category list and grid dialogs(类别列表和网格对话框):添加了可调整大小的 InfoArea
    • Category list and grid dialogs(类别列表和网格对话框):添加了方法 ShowInfoArea
    • 增强了网格渲染预览。
    • 新的类别列表渲染预览。
    • 修复了 Test project(测试项目)中单个嵌入式对话框的错误。
    • container dialog(容器对话框):隐藏了“Append”(追加)按钮。
    • 新增按钮“open project folder”(打开项目文件夹)在生成面板中。由于 CM_ConfigBuilder 尚未与 Visual Studio 2005 集成,代码生成后,您可以打开项目文件夹并使用 VS 2005 打开它。
  • 2007.10.10(版本 1.2.d BETA)
    • 为 GUI 组件 cmOptionList 添加了新的图形样式。
    • 为 GUI 组件 cmTable 添加了新的图形样式。
    • 次要修复。
  • 2007.09.30(版本 1.2c)
    • 为类和容器嵌入对话框(仅 MFC 库)。
    • Time DataType(时间数据类型)和 GUI Control(GUI 控件)(仅 MFC 库)。
    • MFC 库测试项目,包含单个类对话框测试器。
    • 为 Static Enums 验证字段添加了默认值。
    • 其他次要修复。
  • 2007.06.03(版本 1.2b)
    • 为类和容器嵌入对话框(仅 MFC 库)。
    • Time DataType(时间数据类型)和 GUI Control(GUI 控件)(仅 MFC 库)。
    • MFC 库测试项目,包含单个类对话框测试器。
    • 为 Static Enum 验证字段添加了默认值。
    • 次要修复。
  • 2007.01.08(版本 1.2a BETA1)
    • MFC 库的嵌入式对话框。
    • ATL 库的嵌入式 ActiveX 组件。
    • 类验证回调。
    • 成员验证回调。
    • 模板类。
    • 模板成员。
    • 次要修复。
  • 2005.10.07(版本 1.1f)
    • 长数据成员的 SmartHex 字段。
    • 选项对话框中编译 DLL 的 FileName 前缀。
    • 消除了编译时警告。
    • 其他次要修复。
  • 2005.07.24
    • 主对话框树视图中隐藏/可见根节点的标志。
    • 主对话框树视图的自定义外观。
  • 2005.06.25
    • 已为主树视图添加了拖放支持。这使得修改配置结构更加容易。
    • 图标嵌入。早期版本存储了指向生成对话框的类树视图节点关联的图标文件的绝对链接。从这个版本开始,图标存储在项目(XML 文件)中。
    • 改进了“Static Enum”管理(请参阅文章中的“Static Enum”部分)。
    • 生成配置对话框的每个树视图节点的初始状态(折叠/展开)。
    • 多行文本的描述编辑现在支持“Enter”键。
    • 类别列表对话框已变为可调整大小,以获得更好的编辑体验。
    • 其他次要修复。
  • 2005.05.03(版本 1.1c)
    • 为类成员添加了“as CDATA”(作为 CDATA)持久性。
    • 其他次要修复。
  • 2005.04.08(版本 1.1b)
    • 为类成员添加了“as #text node”(作为 #text 节点)持久性。
    • 为具有基数的类添加了避免容器 XML 节点的可能性。
  • 2005.03.29(版本 1.1a)
    • 修复了批处理文件生成中的一些错误。
  • 2005.03.20(版本 1.1)
    • 添加了对 Unicode 的全面支持。
    • 添加了成员作为属性的序列化。
    • 移除了对 xmlParser 包装器的依赖(这允许使用 Visual Studio .NET 打开 VC++ 6.0 项目),其他次要修复。
    • 注意:cm_configbuilder 的 Unicode 版本使用新的字符串类(cmString,派生自 CString)。
  • 2004.05.25
    • 从 ATL 生成的库中删除了内存泄漏。
    • 添加了 VC++ 7.0 库生成。
    • 在 Category List GUI 模式下添加了保持设计顺序的可能性。
    • 为 ATL 库测试添加了测试项目生成。
    • 其他次要修复。
  • 2004.04.13
    • CM_ConfigBuilder 的首次发布。

联系方式

您可以通过在下面的讨论区留言与我联系。如有任何问题,请随时将您的项目和问题简要描述发送给我。我会尽快回复!

© . All rights reserved.