第四章、给MDL应用添加命令
您可能已经注意到了MicroStation中存在着许多键入命令。在Home卡片的Primary组中能找到Key-in图标,可打开键入命令对话框,在这里可浏览并执行当前可用的所有键入命令,如下图所示。虽然该对话框中只列出了四栏,但实际上每个键入命令可由多于4个单词组成。
这些键入命令有许多用途:比如在交互操作中可随时键入一个命令来实现操作的一个步骤;比如可以写一个由键入命令组成的脚本文件在MicroStation中直接执行;比如执行批处理功能时需要指定一个命令文件;再比如每个菜单项或工具栏中的每个图标工具,它们后台都关联着键入命令。可以这样说,键入命令是MicroStation图形用户界面与后台执行代码的重要纽带。以上列举的键入命令的四种用途分别如下图所示:
下面我们就一步步地在现有HelloWorld项目的基础上对其增加命令功能。
1、在Visual Studio新建一个文本文件HelloWorldCmd.r,将如下内容复制到该文件中并保存。
#include <MstnMdlApi scdefs.r.h> #include <MstnMdlApicmdclass.r.h> /*----------------------------------------------------------------------+ | Local Defines +----------------------------------------------------------------------*/ enum CmdTableIds { CT_NONE = 0, CT_MAIN, CT_SUB, CT_CREATE }; /*----------------------------------------------------------------------+ | HelloWorld commands +----------------------------------------------------------------------*/ CommandTable CT_MAIN = { { 1, CT_SUB, PLACEMENT, REQ, "HELLOWORLD" }, }; CommandTable CT_SUB = { { 1, CT_CREATE, INHERIT, NONE, "CREATE" }, }; CommandTable CT_CREATE = { { 1, CT_NONE, INHERIT, DEF, "Line" }, { 2, CT_NONE, INHERIT, NONE, "ComplexShape" }, { 3, CT_NONE, INHERIT, NONE, "ProjectedSolid" }, { 4, CT_NONE, INHERIT, NONE, "BsplineSurface",}, };
以上命令表文件定义了如下6个键入命令,它们分别有对应的命令号。
键 入 |
命名号 |
命令号的值 |
HelloWorld |
CMD_HELLOWORLD |
0x0100000000000000UI64 |
HelloWorld Create |
CMD_HELLOWORLD_CREATE |
0x0101000000000000UI64 |
HelloWorld Create Line |
CMD_HELLOWORLD_CREATE_LINE |
0x0101010000000000UI64 |
HelloWorld Create ComplexShape |
CMD_HELLOWORLD_CREATE_COMPLEXSHAPE |
0x0101020000000000UI64 |
HelloWorld Create ProjectedSolid |
CMD_HELLOWORLD_CREATE_PROJECTEDSOLID |
0x0101030000000000UI64 |
HelloWorld Create BsplineSurface |
CMD_HELLOWORLD_CREATE_BSPLINESURFACE |
0x0101040000000000UI64 |
对以上命令表文件做如下几点说明:
- 需要包含两个必要的头文件rscdefs.r.h和cmdclass.r.h;
- 通过enum定义了一些标识符CT_NONE、CT_MAIN、CT_SUB和CT_CREATE。当然也可直接通过#define来逐个定义。用enum的好处是能自动递增编号,不会发生重复定义的情况;
- 每个命令表由CommandTable关键字定义,后跟一个命令表标识。命令表是一个动态数组,数组中的每行定义该级命令可用的关键字以及相关信息;
- 命令表中的每行至少由五列组成(后续会使用到更多的列):第一列是索引值,第二列是子表标识,第三列是命令类别,第四列是命令选项,第五列是键入命令关键字。
- 索引值构成了最终的命令号的值,命令类别在cmdclass.r.h中有定义,命令选项计有NONE、REQ(Required的缩写)、DEF(Default的缩写)、TRY(Try Parse)、HID(Hidden的缩写)以及IMM(Immediate的缩写)。
2、在Visual Studio打开HelloWorld.mke文件并进行如下两处改动:
a. 将第11行的appRscs = $(o)$(appName).rsc改为
appRscs = $(o)$(appName).rsc $(o)$(appName)cmd.rsc
b.将第46和48行前的注释符#删除。
$(baseDir)$(appName)cmd.h : $(baseDir)$(appName)cmd.r
$(o)$(appName)cmd.rsc : $(baseDir)$(appName)cmd.r
【注】:以上代码中含有两个很重要的空行,不能随手删掉它们。空行表示按默认规则来生成目标文件。在编译过程中bmake将会到mdl.mki文件中找到.r.h和.r.rsc规则去编译并生成HelloWorldCmd.h和HelloWorldCmd.rsc。HelloWorldCmd.h文件会在HelloWorld.cpp中引用,HelloWorldCmd.rsc被加入到appRscs宏定义中,从而最终被打包到HelloWorld.ma中。
3、下面要对HelloWorld.cpp进行多处改动:
a. 包含HelloWorldCmd.h:
#include <MstnMdlApiMdlApi.h> #include <DgnPlatformDgnPlatformApi.h> #include "HelloWorldCmd.h"
b. 在MdlMain函数中删除原来的一些函数调用,增加命令号和命令处理函数动态数组定义、打开资源文件、装载命令表以及注册命令号等动作如下:
MdlCommandNumber cmdNums[] = { { (CmdHandler)createALine, CMD_HELLOWORLD_CREATE_LINE }, { (CmdHandler)createAComplexShape, CMD_HELLOWORLD_CREATE_COMPLEXSHAPE }, { (CmdHandler)createAProjectedSolid, CMD_HELLOWORLD_CREATE_PROJECTEDSOLID }, { (CmdHandler)createABsplineSurface, CMD_HELLOWORLD_CREATE_BSPLINESURFACE }, 0 }; extern "C" DLLEXPORT void MdlMain(int argc, WCharCP argv[]) { ModelInfoCP pInfo = ACTIVEMODEL->GetModelInfoCP(); g_1mu = pInfo->GetUorPerStorage(); RscFileHandle rscFileH; mdlResource_openFile(&rscFileH, NULL, RSC_READONLY); mdlParse_loadCommandTable(NULL); mdlSystem_registerCommandNumbers(cmdNums); }
以上代码中的mdlResource_openFile会打开资源文件HelloWorld.ma,然后mdlParse_loadCommandTable从中装载命令表资源。 动态数组cmdNums中定义了命令处理函数和每个命令号的对应关系,然后由mdlSystem_registerCommandNumbers注册。我们没有像大多MDL例子中那样同时还定义一套命令名(需要用mdlSystem_registerCommandNames来注册),因为命令名的使用远没有键入命令来得方便。只有在您没有定义命令表的情况下才有必要使用命令名。
c. 对createALine、createAComplexShape、createAProjectedSolid和createABsplineSurface进行一些改造以满足作为命令处理函数的要求。同时,将basePt的赋值内置在每个函数中。修改后的代码如下(省略掉了未改动部分):
以上代码中的mdlResource_openFile会打开资源文件HelloWorld.ma,然后mdlParse_loadCommandTable从中装载命令表资源。 动态数组cmdNums中定义了命令处理函数和每个命令号的对应关系,然后由mdlSystem_registerCommandNumbers注册。我们没有像大多MDL例子中那样同时还定义一套命令名(需要用mdlSystem_registerCommandNames来注册),因为命令名的使用远没有键入命令来得方便。只有在您没有定义命令表的情况下才有必要使用命令名。 c. 对createALine、createAComplexShape、createAProjectedSolid和createABsplineSurface进行一些改造以满足作为命令处理函数的要求。同时,将basePt的赋值内置在每个函数中。修改后的代码如下(省略掉了未改动部分):
4、回到MicroStation CONNECT Edition SDK黑窗口界面,键入bmake生成项目。在生成项目的过程中,如果出现任何黄色或红色的提示信息则表示有警告或错误存在,需要消除后才能最终生成可执行的ma和dll。
【注】:在执行bmake前一定要先到MicroStation软件中键入mdl unload helloworld卸载加载的应用,否则bmake时会出现无法覆盖原来的DLL的错误提示!!!
5、回到MicroStation中打开键入命令对话框,键入MDL LOAD HelloWorld装载应用,此时再输入HelloWorld后会看到如下图所示的命令键入树,这与我们在HelloWorldCmd.r中定义的完全对应。此时输入其中的一个命令并回车就能绘出相应的一部分图形。