Professional Documents
Culture Documents
中文MDL tutorial PDF
中文MDL tutorial PDF
第一章 MDL 介绍
一、MicroStation的开发工具
二、何为 MDL
三、MDL 的组成
1. 标准 C (ANSI C) 程序设计语言(当然有某些限制和扩展);
2. 一整套开发工具(包括 C 编译器、连接器、链接库、资源编译器和资源库、Make程序以及调试工具);
5. 大量的运行库函数;
8. 资源管理器;
图 1-1、MDL 对话框
五、MDL 的高级调用方式
六、MDL 的高级卸载方式
1. 在程序中使用标准 C的 “exit”函数卸载程序;
3. 应用程序发生严重错误时会自动退出;
MDL开发环境使用一些变量来定义各种环境参数(表 1-1)。
表 1-1、MDL 开发环境变量列表
变量 描述 类型 缺省值
MS MicroStation系统目录 环境变量
MS_MDL 搜寻 MDL 应用的路径 配置变量
MS_MDLAPPS 在 MDL对话框中列出的应用程序 配置变量
图 2-1、通过菜单激活变量设置对话框
图 2-2、变量设置对话框
二、MDL 应用的结构
一个 MDL 应用由两个主要的部分组成,即程序部分与资源部分。其中程序部分是必须的,而资源部分是可选的。
三、程序代码(Program Code)
1. 主函数(Main Function)
与标准 C语言不同,MDL中的主函数可以缺省。主函数通常用于应用程序的初始化,在该应用载入时执行。
该函数基于用户事件(User Events)定义应用程序的执行命令。
3、钩子函数(Hook Function)
四、资源代码(Resource Code)
3. 消息列表(Message Lists)用于存储处理期间的消息及提示信息的文本字符串。
五、头文件(Head Files)
头文件以 .H 为扩展名,用于给程序常量设置识别名以及定义将要在多个源码(程序)文件中使用的变量。使用时将头文件
包含(Include)到程序文件中。
六、函数声明文件
七、MDL 工具列表
工具 描述
mcomp MDL源程序编译器(生成目标代码)
mlink 链接器(链接库文件中的有关目标代码到程序中)
mlib 对象库管理器(用于维护库文件中的目标代码)
rcomp 资源编译器
rlib 资源库管理器(比如把多个资源文件链接到一个资源文件或者程序文件)
参数: -c 只编译,不联结;
-g 生成调试信息;
-idir 使用 dir 目录中的头文件 ;
-pi 显示头文件
.R ---> .RSC, .H
参数: -h 产生头文件;
-idir 使用 dir 目录中的头文件;
-pi 显示头文件
? 参数
-ofile 指定输出文件(默认为输入文件名.MA)
-v 冗余开关(若指定,将产生较多的输出信息)
? 语法
? 参数
-pi 显示头文件
? 编译参数的环境变量设置
十四、文件类型
在 MDL开发应用过程中的不同阶段,将有不同类型的文件产生或使用到,不同的文件类型通过相应的文件扩展名来区别。
1、创建资源时用到的文件类型
表 2-2、创建资源时用到的文件类型
扩展名 描述
cmd.r 包含命令表的资源源文件
cmd.rsc 编译后的命令表资源文件
扩展名 描述
typ.mt 包含 C结构和联合的类型文件
typ.r rsctype产生的资源源文件
typ.rsc 编译后的类型资源文件
扩展名 描述
.r 资源源文件
.rsc 编译后的资源源文件
扩展名 描述
msg.r 包含消息资源的资源源文件
msg.rsc 编译后的消息资源文件
扩展名 描述
2、创建程序时用到的文件类型
表 4、创建程序时用到的文件类型
扩展名 描述
.h 源程序用到的标准头文件
txt.h 包含文本串的头文件
.fdf 包含函数原型的函数声明文件
.ml 用 mlib生成的包含目标代码的库文件
.mi rlib产生的中间文件
十五、MDL 文件类型及相互其关系
图 4 表明了不同的 MDL应用组件是如何编译到一起的。
图 4、MDL 文件类型及其相互关系
十六、间接命令行参数
以上提到的这些开发工具,在实际使用过程中都要键入大量命令行参数,有没有减少这种烦琐的参数输入的方法呢?有,那
就是使用参数文件(option files)把经常使用的参数设置写到一个文本文件中,然后在命令行中加上 @option_file,即:
command @option_file
第三章 bMake 工具
bMake 工具允许用户使用工程文件编译整个 MDL 应用。工程文件定义了组成一个 MDL应用的各种宏并指定了各从属文件
的编译关联。bMake工具通过判断文件创建的时间可以识别工程文件中是否有文件被改变、删除等。
一、工程文件的文件格式
? 工程文件中包含一系列描述应用将如何编译的语句,这些语句有以下几种类型:
1. 宏(Marco)
2. 条件(Conditionals)
3. Build命令
4. 从属(Dependencies)
5. 规则
? 工程文件的几个通用规则:
1. 规则和从属语句之后必须有一空行;
2. 如果一条语句分几行写,用“\”表示后续;
3. 在任何操作系统中,目录的分隔符一律采用“/”(不用“\”);
4. 注释用“#”符号打头。
二、宏(Macros)
宏是一种定义,它给字符串定义一个宏名,在使用时,这个宏名就代表该字符串。您可以引用已有的宏,当然也可以建立自
己的宏。下面是一些预定义的宏:
表 3-1、预定义的宏
宏 定义
$@ 当前目标文件
$? 所有从属文件新于目标文件
$= 最新从属文件
$< 当前从属文件
$* 目标文件的基名(忽略后缀)
$% 第一个从属文件所在目录
msdos.IP32.unix.macintosh.vax.etc. 指定操作系统的各种宏
? 宏定义的几种方式:
1. 在工程文件内定义;
2. 工程文件以外的可被作为宏引用的环境变量;
3. 在命令行中使用-D 开关。
宏定义的语法:macroname = string
例如:BaseDir = $(MS)/mdl/example/basic
三、条件(Conditionals)
条件是工程文件中的流控制语句,条件语句必须以“%”打头。
表 3-2、条件语句的关键字
条件 描述
%include文件名 包含工程头文件
%ifndef 宏 如果宏未定义,执行后面的语句
%elif 在 if条件为假时再判断另一条件
%endif 结束 if 条件
四、 Build 命令
表 3-3、各种 Build命令标志
标志 描述
@ 命令不回显
$ 强制回显,即使使用了 silent 模式
> 文件 把所有的命令行写入指定的文件中,直到出现“<”标志
< 关闭“>”标志指定的文件
五、从属(Dependencies)
从属语句指定了用那些源文件生成目标文件。当任一个源文件被改变时会执行从属语句。
六、规则(Rules )
环境变量:
BMAKE_OPT 可用于指定编译命令行参数。以下是 DOS & Windows NT 操作系统 autoexec.bat 文件中的环境变量设置示范。
SET BMAKE_OPT=-I\WIN32APP\INGR\USTATION\MDL\INCLUDE
八、bMake涉及到的文件类型
在使用 bMake进行编译时,除了源程序文件外,还涉及到两种类型的文件:工程文件和工程包含文件(或工程头文件)。
工程文件以“.MKE”为扩展名;工程包含文件以“.MKI”为扩展名。一般而言,规则在工程文件中定义;从属在工程包含文件
中定义。
basic.mke 文件
#----------------------------------------------------------------------
#
# MDL Make File
#
# $Workfile: basic.mke $
# $Revision: 5.3 $
# $Date: 01 Apr 1993 07:39:06 $
#
# Copyright (1993) Bentley Systems, Inc.
#
# Limited permission is hereby granted to reproduce and modify this
# copyrighted material provided that the resulting code is used only in
# conjunction with Bentley Systems products under the terms of the
# license agreement provided therein, and that this notice is retained
# in its entirety in any such reproduction or modification.
#
#----------------------------------------------------------------------
#---------------------------------------------
# Define macros specific to this example
#---------------------------------------------
BaseDir = $(MS)/mdl/examples/basic/
privateInc = $(BaseDir)
#---------------------------------------------
# mdl.mki contains the default rules for creating .rsc, .mo, etc files
# mdlexmpl.mki contains the output directory overrides used by examples
#---------------------------------------------
%include mdl.mki
%include mdlexmpl.mki
#----------------------------------------------------------------------
# Define macros for files included in our link and resource merge
#----------------------------------------------------------------------
basicObjs = \
$(o)basic.mo \
$(mdlLibs)ditemlib.ml
??
basicRscs = \
$(o)basic.mp \
$(o)basiccmd.rsc \
$(o)basictyp.rsc
??
#---------------------------------------------
# Generate command table include & resource file using rcomp
#---------------------------------------------
$(genSrc)basiccmd.h : $(BaseDir)basiccmd.r
$(o)basiccmd.rsc : $(BaseDir)basiccmd.r
#---------------------------------------------
# Create & compile the application's type resource file using rsctype
# and rcomp
#---------------------------------------------
$(o)basictyp.r : $(BaseDir)basictyp.mt $(BaseDir)basic.h
$(o)basictyp.rsc : $(o)basictyp.r $(BaseDir)basic.h
#---------------------------------------------
# Compile the MDL source file using mcomp
#---------------------------------------------
$(o)basic.mo : $(BaseDir)basic.mc $(BaseDir)basic.h
#---------------------------------------------
# Link MDL program file from basic.mo & ditemlib.ml using r link
#---------------------------------------------
$(o)basic.mp : $(basicObjs)
$(msg)
> $(o)make.opt
$(linkOpts)
-a$@
$(basicObjs)
<
$(linkCmd) @$(o)make.opt
~time
#---------------------------------------------
# Merge the dialog resources & MDL program file using rlib
#---------------------------------------------
$(reqdObjs)basic.mi : $(basicRscs)
$(msg)
> $(o)make.opt
-o$@
$(basicRscs)
<
$(rscLibCmd) @$(o)make.opt
~time
# complete construction of the .ma by getting the last resource.
%include $(BaseDir)
basicrsc.mki 文件
#----------------------------------------------------------------------
#
# MDL Make File
#
# $Workfile: basicrsc.mki $
# $Revision: 5.0 $
# $Date: 01 Apr 1993 07:33:12 $
#
# Copyright (1993) Bentley Systems, Inc., All rights reserved
#
# Limited permission is hereby granted to reproduce and modify this
# copyrighted material provided that the resulting code is used only in
# conjunction with Bentley Systems products under the terms of the
# license agreement provided therein, and that this notice is retained
# in its entirety in any such reproduction or modification.
#
#----------------------------------------------------------------------
basicRscs = \
$(reqdObjs)basic.mi \
$(rscObjects)basic.rsc \
$(rscObjects)basicmsg.rsc
$(rscObjects)basic.rsc : $(BaseDir)basic.r $(langSpec)basictxt.h \
$(privateInc)basic.h
$(rscObjects)basicmsg.rsc : $(langSpec)basicmsg.r $(privateInc)basic.h
$(mdlapps)basic.ma : $(basicRscs)
$(msg)
> $(rscObjects)make.opt
-o$@
$(basicRscs)
<
$(rscLibCmd) @$(rscObjects)make.opt
~time
第四章 创建对话框
许多 MDL 应用都使用对话框。对话框实际上就是作为用户和 MDL应用之间交互界面的一种窗口。对话框元素是嵌入对话
框中的一种资源,用户通过它可以方便直观地修改特定的数据以及执行特定的动作。
一、资源
最简单的定义就是:资源是在源文件中声明并初始化以备后用的变量,但与作为一块内存区域的在程序中用来存储数据的变
量不同。
1. 资源管理器可以使用户快速存取资源文件而不必考虑其文件格式的细节;
2. 把数据同程序分离开来有助于方便的修改诸如消息和提示信息之类的元素而不必重新编译源程序;
3. 资源只是在需要的时候才调入内存,节省了内存空间;
三、资源的结构
资源结构采用了类似 C 语言的结构定义。
表 4-1 资源结构的组成部分
组件 描述
C 类型定义或资源类型 C类型定义(Typedef)用于定义特定类型的资源实例(比如对话框或按钮);资源类型
是与一个特定资源类型相关联的唯一识别码。 C类型定义用于声明一个资源实例而不是
资源类型。
属性 指定资源属性的参数
数组 通常情况下资源有一系列的成员。在初始化时,资源编译器会为数组中的每一个成员数
产生一个内部长整型值。
每个资源类型都有自己的定义,因此,不同资源类型中各组件的类型和值都不相同。下例是资源文件的一部分:
四、对话框的坐标单位
在对话框上放置对话框元素时自然会涉及到该元素在对话框中的位置和大小,那么度量这种位置和大小的单位是什么呢?
MDL中的默认规定是把当前字体高度的 1/12作为对话框的纵坐标单位,当前字体的 1/6 作为对话框的横坐标单位。在
$(MS)/MDL/INCLUDE/DLOGBOX.H 文件中存放了有关的声明。
五、对话框
所有的对话框都由对话框管理器控制,对话框管理器控制调入对话框资源、创建对话框、显示对话框以及维护对话框。
六、对话框的类型
对话框有模态和非模态两种。模态对话框要求用户必须作出响应后才能执行其它的任务,而非模态对话框则不然。一般警告
信息提示框使用模态对话框。
七、对话框的结构
八、定义对话框
定义对话框实际上就是定义对话框结构的各项成员变量。下面的例子仅仅定义一个没有任何元素的空对话框,其标题(Title)
为 “示范对话框”
十、打开对话框
定义了对话框,也包含了头文件,现在只差最后一步 — 打开(显示)对话框了。打开对话框有两个函数可以使用:
mdlResource_openFile 或
mdlDialog_open
以下是一个在 main()函数中显示对话框的示例:
第五章 对话框元素(Items)
上一章讨论了如何创建对话框,本章将集中讨论如何在对话框上放置对话框元素(Items)。
一、对话框元素
MicroStation 中有几种类型的对话框元素,每一种实现特定的功能。
二、对话框元素的类型
1、标签(Label)
标签是一种静态文本,只显示一个文本字符串,并不接收用户输入。使用
2、组合框(Group Box)
组合框是一个带标题的矩形图形框,用于把相 关联的一组元素框起来。
组合框不接收用户输入,使用时不需要引用资源,只需将对话框元素的 type 设置
为 GroupBox即可。
3、分隔线(Separator)
分隔线是一个垂直或水平的线段,用于分隔对话框上的元素。分隔线不接收用户输
入,使用时不必引用资源,元素列表中的 type 字段等于 Separator。
5、命令按钮(Push Button)
命令按钮用于激活一个操作,用户选择此按钮后,与之相关联的代码就会被执行。元素列表中的 type 字
段等于 PushButton。
6、选项按钮(Option Button)
选项按钮允许用户在给出的多个选项中作出选择,选项菜单只显示当前的选择,占用较少的屏幕空
间。元素列表中的 type 字段等于 OptionButton。。
7、滚动条(Scroll Bar)
滚动条用于显示有 连续取值范围的值,如果滚动条代表某一值的话,必须有钩子
函数与之相连。元素列表中的 type 字段等于 ScrollBar。
8、文本框(Text)
文本框允许用户键入并编辑文本,不过只允许一行,文本类型可以是字符串、整型值或者浮点数。元素列表中的 type 字段
等于 Text
功能与文本框相似,正如其名称所暗示的那样,多行文本
框允许编辑多行
文本。元素列表
中的 type 字段
等于 MLText 或 MultiLineText。
10、颜色拾取框(Clor Picker)
11、图层控制(Level Map)
图层控制用于设置各个图层的打开或者关闭,以及设置当前激活图层,结果存于一个变量
中。元素列表中的 type 字段等于 LevelMap。
12、菜单条(menu Bar)
菜单条在对话框上创建一个基本的菜单。菜单
上有 3 个下拉菜单:Text、Option 和 Color。元素列表中的 type 字段等于 MenuBar, dlogbox.h中文件还新定义了另外一个菜
单资源类型:Ditem_MenuItemXRsc。
13、Text 下拉菜单
Text 下拉菜单包含数个文本字符串,选择一个字符串将激活一个操作,或者弹出下一级菜单。所以下拉菜单既可以放在
Menu Bar 上,也可以放在另一个下拉菜单里。元素列表中的 type 字段等于 PulldownMenu或 PDTextMenu,dlogbox.h 中文件
还新定义了另外一个下拉菜单资源类型:PulldownMenuX 或 PDTextMenuX 。
14、Option 下拉菜单
16、列表框(List Box)
列表框列出几个文本字符串以供用户选择,其功能同于选项按钮,不同点在于列表框可以同时显示多行字符串。元素列表中
的 type 字段等于 ListBox。
17、通用元素(Generic)
18、按钮组(Button Group)
19、活动分隔线(Sash)
活动分隔线用于分隔对话框,与分隔线不同的是,活动分隔线可以允
许用户改变被活动分隔线分隔的对话框两块区域的大小比例。该元素需要钩子函数。元素列表中的 type 字段等于 Sash。
21、弹出式菜单(Popup Menu)
22、无线按钮(Radio Button)
三、定义对话框元素
定义对话框元素需要对话框元素的资源规格说明。这种资源可以在一个应用的资源文件中定义,也可以从其他任何已经打开
的资源文件中引用。在对话框上放置一个元素需要在对话框的 itemList 数组中指定一个资源描述列表。
四、对话框元素的资源规格
要执行的命令、欲改变的变量以及标签等是对话框元素的资源规格中的典型信息。对大多数元素来说,资源规格代码存放于
资源文件中。资源规格描述涉及到很多参数,详情请参考《MDL 程序员手册》。以下是各种参数的列表和说明(表 5-
1)。
表 5-1、对话框元素的资源规格参数
参数 描述
unparsed 命令参数(””表示无参数)
itemHookID 元素的钩子函数(NOHOOK-无钩子函数)
itemHookArg 元素钩子函数的参数(NOARG-无参数)
label 元素的标签(标题)
accessStr 指定与元素相关联的变量
synonymsID 指定同义元素的同义列表(NOSYNONYM-无同义列表)
每一类元素在 dlogbox.h中都有自己的定义。不同的对话框元素类型有区别于其他元素类型的数据结构,比如文本框需要有
一个变量来描述允许的文本长度,而无线按钮就不需要。下表(表 5-2)中左边是文本框的类型定义,右边是一个文本框的
资源规格说明范例。
表 5-2 文本框的结构定义及资源规格说明范例
文本框有一些其他元素都有的公共属性参数,但也有一些特有的参数。比如
maxSize,formatToDisplay,formatToInternal,mininum,maxinum,mask,attributes 等。
五、对话框元素列表规格
对话框元素列表的规格描述了该元素的大小和位置等信息。它可以没有标签、访问字符串,也可以使元素有效或者无效。对
话框元素列表规格的格式如表 5-3 所示。
Label, GroupBox, Seperator, ToggleButton or CheckButton, PushButton, OptionButton, ScrolBar, Text, MLText or MultiLineText,
ColorPicker, LevelMap, MenuBar or MenuBarX, ListBox, Generic, ButtonGroup, Sash, Scale, PopupMenu, or RadioButton.
下面的例子显示了一个加入对话框定义中的元素列表规则。示例中创建的对话框有 5 个元素:一个文本框、选项按钮、颜色
拾取按钮、检查按钮以及一个命令按钮。
DialogBoxRsc DIALOGID_Samples=
DIALOGATTR_DEFAULT | DIALOGATTR_SINKABLE,
DIALOG_WIDTH,DIALOG_HEIGHT,
NOHLEP,MHELP,NOHOOK,NOPARENTID,
“示范对话框”,
{{XC*12,GENY(1),XC*10,0},
Text,TEXTID_Samples,ON,0,””,””},
{{XC*12,GENY(2),XC(10),0},
OptionButton,OPTIONBUTTONID_Samples,ON,0,””,””},
{{XC*12,GENY(3),0,0},
ColorPicker,COLORPICKERID_Samples,ON,0,””,””},
{{X C*12,GENY(4),0,0},
ToggleButton,TOGGLEID_Samples,ON,0,””,””},
{{XC*12,GENY(5),PUSHBUTTONID_Samples,ON,0,””,””},
}
#undef DIALOG_WIDTH
#undef DIALOG_HEIGHT
六、对话框风格建议
1. 对话框不要太大;
2. 尽可能使用非模态对话框;
3. 尽量少用字体类型;
4. 限制使用的颜色数量;
5. 尽可能使垂直对齐的元素有相同的宽度;
6. 使用相同宽度的命令按钮;
7. 使用 GENY宏来保持垂直距离的一直性;
8. 不要把文本框、选项按钮和命令按钮的宽度设置为 0;
参考 MicroStation本身的设计。
一、工具条的组成
工具条由以下几个部分组成:
3. 图标(Icon Command),工具条中的最小组成单位,是一种图形按钮;
4. 下拉区(Pop-Down)。
图 6-1 工具条的组成
图标框架内既可以放置图标,也可以放置图标模板。我们建议最好垂直排放图标框架,也就是说行多于列比较好。如果要与
MicroStation 保持一致的话,图标框架最好排列成两列。
图标模板通常包含几组相关的图标,与图标框架一样,最好竖直排列。图标模板中只能放置图标,而不能放置另外的图标模
板。图标模板可以从图标框架中拉出来,以使其包含的所有图标都显示出来。
图标实际上是一种图形按钮,用户可以通过选择图标来激活某种操作。如果一个图标有一组对话框元素相关联,那么这些元
素都放在下拉区,当图标选中时就可以显示出来。
二、创建工具条
创建工具条时需要几种资源,别忘了在头文件中定义资源识别码。
1、创建对话框
为工具条创建对话框类似于为其他的对话框元素创建对话框,主要的区别在于在对话框元素列表规格描述中只有一个元素,
即:图标框架或者扩展的图标框架,分别用 IconCmdFrame 或者 IconCmdFrameX 来识别。尺寸字段没有意义,系统会根据
图标的数量来计算对话框的大小。
2、创建框架
创建框架需要创建一个图标框架的资源规格描述。框架资源主要说明框架中有那些图标或者图标模板。在图标框架中可以有
3 种类型的元素。首先,可以将图标(以 IconCmd识别)直接放置在框架上,不过如果图标带有下拉区的话,最好不要把它
直接放在框架上,
3、创建图标模板
程序员也可以创建自己的模板而不用从其他应用中引用。若使用 IconCmdPalette 定义模板,应当使用下例中的格式。其中的
图标可以来源于 dlogbox.h或者其他的应用。
4、创建图标
如果要创建自己的图标,有三种资源必须创建:图标命令、小图标(icon)、大图标(icon)。图标命令定义了图标的属性,比如
定义了选择图标后要执行的代码。
三、工具条使用建议
1. 当要引用已有图标或图标模板时,首先从“共享资源号”目录(shareids)中去查找;
3. 如果使用 shareids目录或其他应用中的定义,必须做到:
1. 在资源中包含 .ids头文件;
一、对话框元素的同步
对话框元素的内部值用于决定元素的外观显示,而元素的外部值是元素所控制的应用程序中使用的变量。“访问字符串”
(access string)是一个 C 表达式,用于指定应用程序变量名称,并用于获取元素的外部值。保持元素的内部值(或外观显
示内容)跟外部值一致的操作就是对话框元素的同步,也就是说,一旦某元素被同步,其内值和外值将是一致的。
如果同一个资源在屏幕上有多个显示实例,这些实例将自动保持一致。
二、有关同步的函数
有关同步操作的的函数有 3 个:
1. mdlDialog_itemSynch强制一个元素的内值等于外值;
2. mdlDialog_itemsSynch 强制对话框中的所有元素的内值等于外值;
3. mdlDialog_synonymsSynch强制同义列表中的所有元素的内值等于外值。
三、同义资源
在某种情况下,不仅需要在元素的外值改变时更新其内值及外观显示,还需要同步更新其它一系列元素的内部状态。这种同
步改变可以通过同义资源来实现。
同义资源是一个简单的元素列表,列表给每一个元素指定了元素的类型和资源识别码。有些类型元素(比如检查按钮、文本
框、选项按钮)可以在其元素资源规格描述中包含同义资源识别码。无论何时这些类型元素的外值发生变化,将会发送一个
同步消息到所有与之相连的同义资源中,这就会强制使每一个同义资源的外观显示与相应的程序变量相匹配。
四、使用同义资源
使用同义资源有几个步骤。这个来自第五章《对话框元素》的例子将被用于示范同义资源如何合并到应用中的。
1、定义同义识别码
和其它资源一样,同义资源也必须有一个识别码。完成定义的方法如下:
#define SYNONYMID_Sample 1
2、创建同义列表
同义列表是在资源文件中定义的。列表中指定了当一个元素改变时要被同步的元素。下例示范如何同步文本框和选项按钮:
3、更新元素资源
还有一步必须完成,那就是增加同义识别码到相应的元素资源规格描述中。
需要注意的是必须设置访问字符串字段,访问字符串包含了与元素相关的数据。如果同义列表中的一个元素的值被改变,其
它的元素会收到一个消息,并且其外观显示将被更新,使其与访问字符串中的值一致。
第八章 消息列表与命令表
消息列表和命令列表是另外两个用于增强 MDL 应用的资源类型。消息列表集中了应用中要显示的消息字符串。命令表是一
系列层状定义 MDL 应用中键入命令的结构。
一、消息列表
消息列表用于定义命令、提示信息和错误信息的文本字符串,消息列表中的每个字符串都有一个唯一的消息码。
使用消息列表有两个原因:首先,可以改变消息内容(比如翻译成其它国家的语言)而不用重新编译程序,只需要改变资源
文件就可以了;第二,消息只在需要时才调入内存,节省了 MDL 应用的使用内存。
1、创建消息列表
2、定义资源识别码
和其它资源一样,消息列表资源的识别码必须在头文件中定义,而且号码要以升序排列。
一个应用可以使用 MDL函数直接显示消息列表中的字符串,这些函数有:mdlOutput_rscPrintf、mdlState_startPrimitive、
mdlState_startModeifyCommand 等。下例是使用 mdlOutput_rscPrintf 函数的示范
有些函数,(比如 mdlOutput_rscPrintf)不仅需要消息识别码,同时还需要消息列表识别码作为参数。另一些函数(比如
mdlState_startPrimitive)只需要消息识别码作为参数。如果没有指定消息列表,系统会自动使用当前注册的消息列表。至于
如何注册消息列表,将在后面讨论。
3、注册消息列表
注册消息列表使用 mdlState_registerStringIdss函数。一般这种注册都在主函数中进行,以便以后可以使用消息字符串。
二、命令表
三、命令表实例
#include <rscdefs.h>
#include <cmdclass.h>
/* Version 100 */
/*----------------------------------------------------------------------+
| Local Defines |
+----------------------------------------------------------------------*/
#define CT_NONE 0
#define CT_CALCULATOR_HEADER 1
#define CT_CALCULATOR 2
#define CT_TYPE 3
#define CT_CLASSES 4
#define CT_PREPROCESSOR 5
/*--------------------------------------------------*/
/*--------------------------------------------------*/
Table CT_CALCULATOR_HEADER =
}; /* Endtable exampleChangeCommands */
/*--------------------------------------------------*/
/* Caclulator options */
/*--------------------------------------------------*/
Table CT_CALCULATOR =
}; /* Endtable changeType */
/*--------------------------------------------------*/
/* Data types */
/*--------------------------------------------------*/
Table CT_TYPE =
}; /* Endtable declare */
/*--------------------------------------------------*/
/* Symbol classes */
/*--------------------------------------------------*/
Table CT_CLASSES =
{
{ 1, CT_NONE, INHERIT, 0, "VARIABLES" },
}; /* Endtable declare */
/*--------------------------------------------------*/
/* Preprocessor options */
/*--------------------------------------------------*/
Table CT_PREPROCESSOR =
}; /* Endtable changeType */
四、命令表语法
命令列表的语法通过建立一系列层状表来定义的(如下所示)。
Table <识别码>
/*初始化语句*/
识别码是一个 32 位的无符号整型数。主表必须给识别码赋值,这个表包含了可以在应用命令中用作词头的每一个关键字。
另外还有一些表资源包含命令中的其它后续字。命令中的每个关键字都有一个初始化语句。初始化语句的格式如下:
{<num>,<subtable>,<classname>,<options>,”<name>”},
1、num 字段
{<num>,<subtable>,<classname>,<options>,”<name>”},
2、subtable字段
{<num>, <subtable>,<classname>,<options>,”<name>”},
subtable字段指定命令中一个表的下一个词,并建立命令的后续表层次。如果命令中没有下一个词,则设置该字段位零。
3、classname 字段
{<num>,<subtable>,<classname>,<options>,”<name>”},
4、options 字段
{<num>,<subtable>,<classname>, <options>,”<name>”},
options字段是一个一位的数,几个二进制状态符可以用逻辑或(|)操作符联结起来,也可以将该字段指定为 NONE。
HID –Hidden;
DEF –Default,如果没有给出下一词,指定将从子表(subtable)中选出的命令词;
REQ – Required,指定需要子表中的命令词;
IMM –Immediate(已过时)
5、name 字段
{<num>,<subtable>,<classname>,<options>,”<name>”},
name<name>”},
name字段是可以键入的关键词。在有的平台上,关键词区分大小写。关键词要用引号括起来,其中不允许有空格、斜杠
(/)和等号(=)。如果语法分析器找到两个匹配的命令表,MicroStation 将使用匹配得最好的那一个。如果几个应用中包
含同一个命令名称,MicroStation将忽略后调入的应用中的命令。
五、编译命令表
编译命令行语法为:
rcomp -h filecmd.r
六、联结命令到函数
该命令名不能用来建立另外的命令表。命令名被设计来用于帮助程序员测试函数。
七、调入命令表
同消息列表一样,命令表也需要调入才能使用。一般都在主函数或者被主函数调用的初始化函数中调入。下例示范了如何使
用 mdlParse_loadCommandTable 函数调入命令表。
第九章 事件驱动程序设计
本章将介绍创建功能强大的应用程序的其他一些程序设计工具和技术,这些功能强大的新的特征均为 MicroStation 所提供。
目标:
1、明了事件驱动程序设计的基本概念
2、创建自己的简单应用
一、程序设计工具
MicroStation 定义了很多变量、常量以及函数可供编程者调用,使用系统提供的工具可以大大加快程序开发的进程。
二、内置变量
类型 变量名 描述
short dgnBuf[] 在很多操作中的当前元素。DOS 和 Windows NT 下数组大小为 768,CLIX 下
为 780。
MicroStation 还包含内置的可称为浮点常量的变量,可作为只读的变量使用。
常量 值 常量 值
三、函数
MDL的强大功能在于它的很多内置的函数。MDL 应用提供了通过这些函数直接存取 MicroStation的“CAD引擎”的能力。其
中有几千个函数可供使用,以提供直接创建和操纵元素以及界面的功能。这些函数与 MicroStation 内部使用的函数是完全一
致的。
命名规则
MicroStation 的函数使用它自己的特别的命名风格,而且建议使用者创建新的函数时也采用类似的规则,以形成良好的程序
设计风格。
• 内置函数、MicroStation函数使用下列格式:mdlFunctionType_operationDescription
• 用户自定义函数使用下列格式:userFuntionType_operationDescription
• 来自于外部程序与 MDL通讯的函数使用下列格式:extprg_description
四、程序设计方法
• 顺序化程序设计
第一种方法可以称为顺序化程序设计方法。这种方法不善于完成复杂的任务。MicroStation倾向于采用事件驱动的程序设计
方法。如果您采用顺序化程序设计方法,那么您的应用看起来将不象一个 MicroStation 的应用程序。
优点
• 容易完成简单的任务;
• 对 MicroStation的内部处理过程了解的程度要求较低。
缺点
• 要求了解命令的输入;
• 难于使命令透明地使用;
• 多个应用的交互相当复杂;
• 事件驱动程序设计
与第一种方法相比有较大的优势。MicroStation 主要有以下几种事件:
• 数据点
• 键盘输入
• 复位
• 光标移动
在 MicroStation中,所有的事件都由输入处理器(input handler)进行收集。每一种输入处理器收集特定的输入到“输入包”
中,“输入包”验证事件并以标准格式将之放入输入队列中,事件就被发送到到输入队列中。当事件到达队列头部,任务调度
器开始处理该输入消息。调度器将该事件发送到相应的任务之中。整个事件处理的过程称为 MicroStation 输入主循环。
MicroStation主输入循环
数据 键入 复位 其它
五、MicroStation 的命令类型
Utility 命令
Primitive 命令
Modification 命令
Immediate 命令
Immediate命令主要用于修改设置,因此常常带有一个或更多的参数。它不调用函数,也不对事件进行响应。Immediate命令
的运行不影响其他命令的执行的状态.
View 命令
六、创建命令
**************************************************************************
main
DialogBox *dialogP;
RscFileHandle rscFileH;
/*打开资源文件*/
mdlResource_openFile(&rscFileH,NULL,0);
/*装载命令表*/
if (mdlParse_LoadCommandTable(NULL)==NULL)
/*登记字串表*/
mdlState_registerStringIds(MSGLISTEDID_Commands,MSGLISTID_Prompts);
/*打开对话框*/
if ((dialogP=mdlDialog_open(NULL,DIALOGID_Samples))==NULL)
**************************************************************************
初始化
命令的初始化函数对所有的命令都是相同的,它是所有命令的入口点,当用户或应用激活命令时被调用.任何执行命令的初始化
均应在该函数中完成.
**************************************************************************
cmdNumber CMD_PLACE_LINE
mdlState_startPrimitive(userState_PlaceLineFirstPoint,
userCommandInitia lization_placeLine,
MSGID_PlaceLine,
MSGID_FirstPoint);
**************************************************************************
在命令之后键入的任何参数将被传递给 unparsedP 。
如果想在建立命令表之前测试命令的执行,可以用 cmdName来修饰命令。在提示符下键入:
mdlState_startPrimitive 函数被调用来设置数据点、复位等状态函数,显示命令名和提示信息等。第一个参数指定当用户输入
第一个数据点时被调用的函数。第二个参数指定当用户复位时被调用的函数和使用 mdlState_restartCurrentCommand函数被
调用的函数。
**************************************************************************
/*保存当前数据点到栈中*/
statedata.dPointStack[0]=*PointP;
/*设定数据点函数*/
mdlState_setFunction(STATE_DATAPOINT,userState_placeLineSecondPoint);
/*设置动态显示线的函数*/
mdlState_dynamicUpdate(userState_placeLineDynamics,FALSE);
/*显示第二点的提示信息*/
mdlOutput_rscPrintf(MSG_PROMPT,0,MSGLISTEDID_Prompts,MSGID_SecondPoint);
**************************************************************************
mdlState_dynamicUpdate设置 userState_placeLineDynamics作为新的动态显示函数,第二个参数确定有效的元素数据,是否已
在 dgnBuf 之中。
**************************************************************************
_________________
Private void userState_placeLineSecondpoint
MSElementUnion myElement;
/*保存当前数据点到栈中*/
statedata.dPointStack[1]=*PointP;
/*在元素结构中创建线*/
mdlLine_create(&myElement,NULL,statedata.dPointStack);
/*显示线*/
mdlElement_Display(&myElement,NORMALDRAW);
/*加线到设计文件*/
mdlElement_add(&myElement);
/*保存当前最后点,为以后作土使用*/
statedata.dPointStack[0]=statedata.dPointStack[1];
**************************************************************************
userState_placeLineSecondPoint 不仅在第二点中调用,而且在其它点中被调用。
动态显示
动态显示靠指定被光标显示循环调用的函数来实现。光标位置被转换为设计文件坐标,被加以当前捕俘锁定处理,然后转交
给动态显示函数例程。
**************************************************************************
动态显示例程
_________________
/*保存当前数据点到栈中*/
statedata.dPointStack[1]=*PointP;
/*在 dgnBuf中创建线*/
mdlLine_create(dgnBuf,NULL,statedata.dPointStack);
**************************************************************************
第十章 对话框与应用的连接
目标
学会将对话框与应用连接起来的几种方法。要在应用中使用对话框,必须将它们连接起来。有三种方法将应用与对话框连接
起来。
一、命令号
使用对话框元素的命令号发送命令到输入队列中。
**************************************************************************
Ditem_ToggleButton TOGGLE_LockGrid=
CMD_LOCK_GRID_TOGGLE,MCMD
NOSYNONYM,NOHELP,MHELP,
NOHOOK,NOARG,NOMASK,NOINVERT,
"GRID LOCK",""
**************************************************************************
二、存取串
存取串允许对话框直接操纵应用中的单个变量。
**************************************************************************
Ditem_ToggleButton TOGGLE_LockGrid=
CMD_LOCK,MCMD
NOSYNONYM,NOHELP,MHELP,
NOHOOK,NOARG,NOMASK,NOINVERT,
"GRID LOCK","tcb- >control.grid_lock"
**************************************************************************
三、对话框钩子函数
对话框钩子函数包括对话框钩子函数和对话框元素钩子函数两种。
**************************************************************************
Ditem_ToggleButton TOGGLE_LockGrid=
CMD_LOCK,MCMD
NOSYNONYM,NOHELP,MHELP,
HOOKITEMID_GridLock,NOARG,NOMASK,NOINVERT,
"GRID LOCK",""
**************************************************************************
第十一章 命令号与存取串
目标
• 使用命令号连接一个对话框和应用。
• 输出变量与结构
• 整合存取串到应用
• 废弃存取串
作为对话框所用的存取串必须是为之可用的变量。
一、命令号
二、存取串
连接存取串到应用有几个步骤:
1、定义结构或联合变量
*****************************************
int parameter1;
int parameter2;
} SamplesGlobals;
*****************************************
2、输出结构到类型定义文件
输出结构到类型定义文件,然后使用 rsctype 创建资源。
*****************************************
/*结构定义文件(???typ.mt)部分/
#include "???typ.h"
publishStructures(samplesglobals);
*****************************************
3、声明并输出变量
除此之外,其相应的资源文件必须已经打开。
**************************************************************************
SamplesGlobals myGlobals;
Public main
int argc;
char *argv[]
.......
/*打开资源文件*/
.......
/*设置将被求值的 c 表达式变量*/
setP=mdlCExpression_initializeSet(VISIBILITY_DIALOG_BOX,0,FALSE);
mdlDialog_publishComplexVariable(setP,"samplesglobals","myGlobals",&myGlobals);
.......
/*打开对话框*/
......
**************************************************************************
4、更新资源
如果对话框元素使用了应用的变量,对话框的存取串必须被修改以引用该变量。
**************************************************************************
/*资源文件 .r 部分*/
DItem_TextRsc TEXTID_Samples=
NOCMD,MCMD,NOSYNONYM,NOHELP,MHELP,NOHOOK,NOARG,
1,"%-ld","%ld","1","3",NOMASK,NOCONCAT,
TXT_Parameter1,
"myGlobals.parameter1"
};
**************************************************************************
5、废弃存取串
"access=\"newAccessString\""
**************************************************************************
/*.r 文件部分*/
DialogBoxRsc DIALOGID_Samples=
......
{{XC*12,GENY(1),XC*10,0},Text,TEXTID_Samples,
ON,0,"","access=\"otherstruct.value\""},
......
};
......
DItem_TextRsc TEXTID_Samples=
NOCMD,MCMD,NOSYNONYM,NOHELP,MHELP,NOHOOK,NOARG,
1,"%-ld","%ld","1","3",NOMASK,NOCONCAT,
TXT_Parameter1,
"myGlobals.parameter1"
};
**************************************************************************
第十二章 对话框钩子函数
对话框钩子函数是对话框及其元素设计功能最强大的工具之一。它提供了更为强大的功能和更大的灵活性。
目标
• 创建并连接对话框钩子函数。
• 创建并连接对话框元素钩子函数。
一、实现步骤
1、定义对话框标志号
对话框标志号为长整型,MicroStation 的对话框标志号为负值。自定义的对话框标志号应该使用正值,以避免与系统冲突。
对话框和对话框元素的钩子函数不能使用相同的标志号。对话框标志号通常在头文件中定义。
**************************************************************************
#define HOOKITEMID_ToggleButton_Samples 1
#define HOOKDIALOGID_Samples 2
**************************************************************************
2、将标志号与函数相关
通过创建数组 DialogHookInfo来将标志号与函数相关。
**************************************************************************
/* .mc 文件的部分*/
{HOOKITEMID_ToggleButton_Samples,ssamples_toggleButtonHook},
{HOOKDIALOGID_Samples,samples_dialogHook},
**************************************************************************
3、输出对话框到对话框管理器
**************************************************************************
Public main
int argc,
char *argv[]
......
mdlDialog_hookPublish(sizeof(uHooks)/sizeof(DialogHooInfo),uHooks);
.....
/*打开对话框*/
**************************************************************************
4、编写函数
对话框钩子函数示例:
**************************************************************************
/* 忽略所有送到模式对话框的消息*/
if (dmP->dialogId != DIALOGID_Basic)
return;
dmP->msgUnderstood = TRUE;
switch (dmP->messageType)
case DIALOG_MESSAGE_DESTROY:
mdlSystem_getCurrTaskID(), TRUE);
break;
};
default:
dmP->msgUnderstood = FALSE;
break;
**************************************************************************
对话框元素钩子函数示例:
**************************************************************************
dimP->msgUnderstood = TRUE;
switch (dimP->messageType)
case DITEM_MESSAGE_CREATE:
basicGlobals.parameter2 = 0;
break;
default:
dimP->msgUnderstood = FALSE;
break;
**************************************************************************
5、添加对话框到资源
创建了对话框钩子函数之后,必须将它与对话框资源相连,才能产生交互式的应用。
**************************************************************************
DialogBoxRsc DIALOGID_Basic =
DIALOGATTR_DEFAULT | DIALOGATTR_SINKABLE,
25*XC, 7*YC,
TXT_BasicDialogBox,
};
DItem_ToggleButtonRsc TOGGLEID_Basic =
TXT_IncrementParameter1,
"basicGlobals.parameter2"
};
**************************************************************************
2. 对话框钩子的消息结构
**************************************************************************
boolean msgUnderstood;
Union
…… /* 消息结构联合(随消息类型的不同而不同) */
} u;
} DialogMessage;
**************************************************************************
3. 对话框钩子消息类型
对话框钩子消息类型定义在 dlogitem.h中。
**************************************************************************
#define DIALOG_MESSAGE_SYNCH 7
#define DIALOG_MESSAGE_KEYSTROKE 9
#define DIALOG_MESSAGE_FOCUSIN 10
#define DIALOG_MESSAGE_FOCUSOUT 11
#define DIALOG_MESSAGE_ITEMFOCUSIN 12
#define DIALOG_MESSAGE_ITEMFOCUSOUT 13
#define DIALOG_MESSAGE_ACTIONBUTTON 15
#define DIALOG_MESSAGE_USER 16
#define DIALOG_MESSAGE_ANOTHEROPENED 17 /* 在 INIT 消息之后发送 */
**************************************************************************
缺省情况下,只有六种消息类型被发送到对话框钩子函数:DIALOG_MESSAGE_CREATE,DIALOG_MESSAGE_INIT ,
DIALOG_MESSAGE_DESTROY,DIALOG_MESSAGE_BEFOREDESTROY,DIALOG_MESSAGE_HIDE,
DIALOG_MESSAGE_USER。
**************************************************************************
font.
BUTTON 按钮消息发送到对话框元素之后发送。
FOCUSIN 当对话框在对话框元素之前收到焦点时发送。(sent when dialog receives focus before item focus in.)
FOCUSOUT sent when dialog loses focus after item focus out.
**************************************************************************
**************************************************************************
dialogMessage *dmp
{
dmp->msgUnderStood=TRUE;
SWITCH (dmp->messageType)
case DIALOG_MESSAGE_CREATE:
dmp->u.create.interests.updates=TRUE;
dmp->u.create.interests.mouses=TRUE;
...
break;
case DIALOG_MESSAGE_DESTROY:
...
break;
default:
dmp_msgUnderstood=FALSE;
...
**************************************************************************
4. 对话框元素消息结构
boolean msgUnderstood;
Union
{
…… /* 消息结构联合(随消息类型的不同而不同) */
} u;
} DialogItemMessage;
**************************************************************************
五、对话框元素消息类型
**************************************************************************
#define DITEM_MESSAGE_CREATE 50
#define DITEM_MESSAGE_DESTROY 51
#define DITEM_MESSAGE_DRAW 52
#define DITEM_MESSAGE_FONTCHANGED 53
#define DITEM_MESSAGE_BUTTON 54
#define DITEM_MESSAGE_SETSTATE 55
#define DITEM_MESSAGE_HIGHLIGHT 57
#define DITEM_MESSAGE_KEYSTROKE 58
#define DITEM_MESSAGE_FOCUSIN 60
#define DITEM_MESSAGE_FOCUSOUT 61
#define DITEM_MESSAGE_SETENABLEDSTATE 62
#define DITEM_MESSAGE_MOVE 63
#define DITEM_MESSAGE_SETEXTENT 64
#define DITEM_MESSAGE_SETLABEL 65
#define DITEM_MESSAGE_QUEUECOMMAND 70
#define DITEM_MESSAGE_USER 72
**************************************************************************
六、跟踪钩子函数
关闭 Messages窗口将关闭所有的消息跟踪,要继续跟踪必须重新键入使用的命令。
第十三章 启动应用的几种高级方法
通过设置环境变量 MS_DGNAPPS和 MS_INITAPPS可以指定 MicroStation 自动启动的应用程序。
目标
• 配置自动装入的应用程序
• 了解 OFF_Line方法的程序设计
• 学会怎样存取应用程序参数
一、MS_DGNAPPS
MS_DGNAPPS变量可以通过用户配置菜单来设置,该菜单允许用户选择自动启动的应用程序。
MS_DGNAPPS指定的应用在 MicroStation启动到设计文件打开的时间内运行。当用户打开设计文件或从文件菜单中选择了
关闭并打开另一个设计文件是运行该程序。
如果用户键入 rd=command或从文件菜单中选择了打开时,该指定应用程序将不被运行。
典型处理
1. 打开资源文件
2. 装入命令表
3. 打开工具条或其他非模式窗口,MS_DGNAPPS不支持模式窗口.
4. 控制返回到 MicroStation.
二、MS_INITAPPS
MS_INITAPPS=<APPICATION>,[TASKID],[/d];...
多个应用名以分号隔开,如要跟踪执行,加入 /D 选项。
被 MS_INITAPPS指定的应用的 MicroStation启动到进入图形模式之前执行。
图形和设计文件在 MS_INITAPPS应用初始化时并不被激活。应用程序自身决定是否初始化图形模式并激活设计文件或装入
cell 库。
MS_INITAPPS与 Off_line程序设计
Off_line程序处理过程
1. 命令行参数被传递
2. 设计文件被使用 mdlSystem_newDesignFile函数打开.
3. 被指定的设计文件或一系列设计文件被打开并处理.
Off_line程序设计要点
如果要使用对话框,使用 mdlSystem_enterGraphicsExtended函数。
当没有设计文件打开时,应用将退出到操作系统下。
三、MicroStation 命令行参数
-r 以只读方式打开文件。
-o 不连接引用文件。
- widir 指定用户界面文件所在目录。
- wpfile 定义工程配置文件。
- wdfile 指定数据库配置文件。
命令行处理过程
1、标准 C 方式
main(argc,argv[])
argc 命令行参数个数
argv[] 命令行参数串数组指针。
2、MS_INITAPPS 方式
================================================================
3、MS_DGNAPPS
参数不能传递给 MS_DGNAPPS启动的应用.其存取参数如下:
=================================================================
=================================================================
4、从启动元素装入的应用
当应用从启动元素装入时,将忽略从命令行传入的参数。启动元素可用函数 mdlSystem_createStartupElement函数,然后使用
mdlElement_add 函数加到设计文件。它将存取如下所示的参数:
=================================================================
=================================================================
5、从命令窗口提示符装入的应用
=================================================================
=================================================================
6、从 MDL 对话窗口装入的应用
参数将不被传递。
=================================================================
第十四章 元素描述符
元素描述符(Element Descriptors)为程序员提供了另一种访问文件中元素的方法。它们实际上是一系列简单或复杂元素的
多连接列表,元素描述符中的指针允许程序员访问列表中的元素。
一、什么是元素描述符
元素描述符是一个多连接的元素列表。这种多连接给程序员提供了从多个方向纵横浏览列表的能力。
复杂元素不能使用简单的结构来描述,它们拥有大小不等的各种元素。如果一个复杂元素的数据存放在 MSElementUnion结构
或者 dgnBuf 中,只能访问元素的头部信息,要访问整个元素的所有信息,则需使用元素描述符。
二、元素描述符的结构
元素描述符的结构定义在$(MS)/mdl/include/mselems.h文件中。对于复杂元素头(比如要素头和文本节点)h.isHeader 应设置
为 TRUE。
三、简单的元素描述符
图 14-1、Simple Cell 图 14-2、Nested Cell
图 14-3、Selection Set
四、递归
元素描述符因为其多连接特性,导致了它们自身被递归浏览。递归和元素描述符非常适合嵌套状的复杂元素,因为对于嵌套的
每一层,应用会简单地调用递归函数进行任何处理。因为难于确定嵌套级数,所以调试递归程序比较麻烦。
当连接一个递归程序时,可能不得不增加堆栈的大小,至于增加多少,这得看自动变量的数量。
1、创建元素描述符的两种基本方法
或
2、需要记住的几件事
? 使用完元素描述符后,一定要释放其内存;
? 元素描述符可能会使用大量内存;
? 千万别使用 sizeof(MSElement)来复制元素描述符。
五、 AppCelement应用例程
/*----------------------------------------------------------------------+
||
||
||
||
+----------------------------------------------------------------------*/
/*----------------------------------------------------------------------+
||
| $Logfile: J:/mdl/examples/applcelm/applcelm.mcv $
| $Workfile: applcelm.mc $
| $Revision: 1.6 $
||
+----------------------------------------------------------------------*/
/*----------------------------------------------------------------------+
||
| Function - |
||
| element manipuation. |
||
| This example application shows how to use the IGDS type 66 level 20 |
| except for the element headers. This application also shows the |
| routines. |
||
| the design file specified, then find and read the element back |
| and display the contents on the screen. The application does not |
||
||
||
||
|-- -- - -- -- -- -- - -- -- -- - -- -- -- -- |
||
||
| header |
| design file |
| design file |
||
+----------------------------------------------------------------------*/
/*----------------------------------------------------------------------+
||
| Include Files |
||
+----------------------------------------------------------------------*/
#include <mdl.h>
#include <mselems.h>
#include <scanner.h>
#include <cexpr.h>
#include <rscdefs.h>
#include <msbnrypo.fdf>
#include <stdarg.h>
#include "applcelm.h"
/*----------------------------------------------------------------------+
||
| Local defines |
||
+----------------------------------------------------------------------*/
/* The following macros evaluate to function calls for the BIG ENDIAN */
/* machines (680x0, Sun, etc) and to nothing for other systems. They */
/* are used to swap the byte order of two - byte integers to accommodate */
#else
# define SWAP_BYTE(arg1)
# define SWAP_BYTE_ARRAY(arg1,arg2)
#endif
/*----------------------------------------------------------------------+
||
||
+----------------------------------------------------------------------*/
short offset;
short sector;
ApplElement appEl;
} ScanBuffer;
/*===============================================================
||
||
+===============================================================*/
/*----------------------------------------------------------------------+
||
||
||
+----------------------------------------------------------------------*/
short *signatureP;
/* ------------------------------------------------------------------
------------------------------------------------------------------ */
elP->ehdr.type = MICROSTATION_ELM;
elP->ehdr.level = APPLICATION_LEVEL;
mdlCnv_toScanFormat (MINI4);
mdlCnv_toScanFormat (MAXI4);
/* ------------------------------------------------------------------
------------------------------------------------------------------ */
elP->dhdr.attindx = elP ->ehdr.words - WORDS_BTWN_WTF_ATTRINDX;
/* Set the signature word in the element. We need to swap the signature */
*signatureP = EXAMPLE_SIGNATURE;
SWAP_BYTE (signatureP);
/*----------------------------------------------------------------------+
||
||
||
+----------------------------------------------------------------------*/
Scanlist scanList;
ScanBuffer *sbP;
ULong filePos;
short possibleSignature;
ULong scanBuf[1024];
mdlScan_initScanlist (&scanList);
mdlScan_noRangeCheck (&scanList);
do
if (scanSize)
/*-----------------------------------------------------------
-----------------------------------------------------------*/
SWAP_BYTE (signatureP);
if (*signatureP == signature)
return SUCCESS;
return ERROR;
/*================================================================
||
||
+===============================================================*/
/*----------------------------------------------------------------------+
||
||
||
+----------------------------------------------------------------------*/
ULong ddbId
int status;
ApplElement el;
ddbId))
== SUCCESS)
return status;
/*----------------------------------------------------------------------+
||
| in file |
||
+----------------------------------------------------------------------*/
ApplElement el;
ULong filePos;
short *fileDataP;
/* Initialize element. */
EXAMPLE_SIGNATURE);
(byte *)fileDataP,
if (status != SUCCESS)
return status;
/* problem occured with the write, and mdlErrno has the error */
if (filePos == 0L)
return mdlErrno;
else
return SUCCESS;
/*----------------------------------------------------------------------+
||
| Name applcelm_rscSprintf |
||
||
+----------------------------------------------------------------------*/
int messageNumber, /* => Index into msg list for format str */
va_list ap;
char tempStr[1024];
messageNumber);
va_end (ap);
/*================================================================
+===============================================================*/
Public main
int argc,
char *argv[]
void *setP;
RscFileHandle rfHandle;
short status;
char fileName[MAXFILELENGTH],
fileToOpen[MAXFILELENGTH],
msgBuffer[128];
mdlSystem_enterGraphics ();
if (argc < 4)
MSGID_Usage);
exit (0);
else
MSGID_CantOpenResource);
exit (1);
fileToOpen);
if (status)
MSGID_ErrorOpeningDGN);
exit (1);
savedAppData.longValue1 = 44;
savedAppData.doubleValue1 = 120.45;
savedAppData.doubleValue2 = 145.72;
savedAppData.shortValue1 = 60;
savedAppData.shortValue2 = 30;
RSCID_AppData_DataDefBlock))
RSCID_AppD ata_DataDefBlock))
MSGID_ErrorWritingApplElem);
exit (1);
}
RSCID_AppData_DataDefBlock))
MSGID_ErrorReadingApplElem);
exit (1);
/* compare data we set and data we retrieved to make sure they are */
/* the same. */
MSGID_FormatStr01);
MSGID_FormatStr02);
appData.longValue1);
mdlDialog_dmsgsPrint (msgBuffer);
appData.doubleValue1);
mdlDialog_dmsgsPrint (msgBuffer);
appData.doubleValue2);
mdlDialog_dmsgsPrint (msgBuffer);
appData.shortValue1);
mdlDialog_dmsgsPrint (msgBuffer);
appData.shortValue2);
mdlDialog_dmsgsPrint (msgBuffer);
appData.string);
mdlDialog_dmsgsPrint (msgBuffer);
exit (0);
第十五章 交互式元素操纵
MDL应用最常用的一个操作就是定位和修改已有的元素或者元素组。
一、交互式元素操纵
二、执行操纵命令
编写操纵命令有几个步骤,以下是几个基本的步骤:
1、设置查询判别式
2、初始化定位处理
3、传送元素到处理函数
4、元素处理
5、重新开始定位操作
mdlLocate_restart 函数可以用于重新开始定位处理。它将重新初始化定位逻辑并提示用户标定下一个元素。栅栏操作不需要
这一步。
三、交互式操纵命令的源码
下例中示范了如何使用操纵命令查找线和线串并把它们的颜色和风格修改成当前的激活值。
1、初始化定位操作
mdlState_startModifyCommand的参数:
参数 2— 数据点函数(Datapoint Function):当用户接受一个元素时调用的函数;
参数 3— 动态函数(Dynamics Function):在一个简单的动态元素显示时调用;
参数 4— 显示函数(Show Function):在元素被确定之后、被接受之前调用,典型的情况是,该函数用于显示一些附加信息,
凭借它用户可以决定是否接受一个元素,它们还可以用于设置复杂动态元素;
参数 5— 清除函数(Clean Function):在选择元素之后调用来做清除工作的函数;
参数 6— 用于从注册的命令名称消息列表中指定一个命令名称字符串的消息识别码;
参数 7— 用于从注册的提示信息列表中指定提示信息的消息识别码;
参数 8— 指定处理选择的元素集;
参数 9— 指定选择操作命令所需的附加点的数量。
表 15-1 设置查询判别式的有关函数
另外,为扫描器(静态判别式)使用查询模板后,应用可以在定位处理的不同时间执行附加的处理,如元素类型过滤处理。
在使用 mdlLocate_setFunction函数定位元素时,可以建立用户自定义函数来进行事务处理。
mdlLocate_setFunction(LOCATE_POSTLOCATE,userFilterCells);
userFilterCells函数是写来检查当前元素的类型并排除那些不是 cell类型的元素。
3、传送元素到处理函数/重新开始定位
一般而言,操纵命令一次只修改一个元素,但是 mdlModify_elementMuti函数可以通过对选择集中的每一个元素调用一次
mdlModify_elementSingle,从而实现在一次操作中修改选择集或图形组(graphic group )中所有元素的功能(不过 doGroup
参数必须设置为 TRUE)。同时,为了让图形组作为一个组来处理,还需要把图形组的锁“打开”(turn on)。值得注意的
是,选择集(selection set)和图形组(graphic group)是相互排斥的,并且选择集优先。比如,有一个激活的选择集,但选择集中
的一个成员正好在一个图形组中(而且图形组的锁有效),那么,只有选择集中的元素才会被处理。另一方面,如果没有选
择集,并且标定用于修改的元素属于一个图形组(同时,图形组锁为 on),那么属于这个组的其他元素将连同这个元素将
一起被修改。
参数 1— 处理的文件号;
参数 2— 元素在文件中的位置;
参数 3— 为复杂元素调用元素函数的标志;
参数 4— 表明修改元素所用步骤的修改标志;
参数 5— 元素函数:在修改元素时为每一个成员调用的函数;
参数 6— 指向包含元素参数的结构的指针;
尽管 mdlModify_elementSingle和 mdlModify_elementMuti经常使用,有时也可以使用稍微低级一点的
mdlModify_elementDescr 函数来编写操纵函数。所有这 3 个函数最终都调用一个在应用中定义的元素函数(element
Func(tion))来执行实际的元素修改操作(图 15-1 显示了这种层次结构)。
图 15-1、各修改函数之间的层次示意图
4. 元素处理
元素函数的具体说明参见《MDL参考手册》中有关 mdlModify_elementSignle 函数的说明,元素函数必须有返回值,返回值
可能是:
MODIFY_STATUS_NOCHANGE— 元素没有被修改;
MODIFY_STATUS_REPLACE— 用新元素替换了已有元素;
MODIFY_STATUS_DELETE— 元素被删除;
MODIFY_STATUS_ABORT 、MODIFY_STATUS_FAIL、
MODIFY_STATUS_ERROR— 修改失败;
MODIFY_STATUS_REPLACEDSCR— 元素描述符被替换。
5、栅栏操作命令的源码
栅栏处理与单元素/选择集处理之间的差别是很微妙的。单元素 /选择集处理中必须在初始化修改函数之后设置查询判别式,
下例中使用栅栏操作改变线的颜色和风格,其用法与前面使用 CHANG_LINE_SINGLE 的例子类似,只不过这里使用
CHANGE_LINE_FENCE。
mdlState_startFenceCommand 的参数:
参数 2— 轮廓函数(outline function):处理完毕后调用。通常用于显示一个新的栅栏轮廓;
参数 4— 重置/重新开始函数(reset/restart function);
参数 5— 用于从注册的命令名称消息列表中指定一个命令名称字符串的消息识别码;
参数 6— 用于从注册的提示信息列表中指定提示信息的消息识别码;
1. 传递元素给栅栏处理函数
因为本例中调用 mdlState_startFenceCommand函数时,数据点函数的指针参数设置为空(NULL),MDL 会自动设置
mdlFence_process函数为数据点处理函数。在进行栅栏锁和
裁减模式检查之后,元素被一个一个地传递给内容函数 acceptFenceContents。
虽然本例中数据点函数的指针参数设置为空,但在有的应用中需要自己的栅栏函数来记录用于预先处理栅栏的附加信息,比
如栅栏移动和栅栏复制所需的其他数据点。因此,数据点函数将在数据点处理结束后直接调用 mdlFence_process。必须注
意,调用 mdlFence_process函数时,栅栏必须已经定义,否则将有错误发生。
7、轮廓( outline)函数的附加信息
在上面的例子中,轮廓函数都被设置为空(NULL),但是在通常情况下,设置为空并不是最好的选择。
轮廓函数是在所有栅栏处理完成后执行的唯一函数。如果栅栏命令在处理完成之后继续进行,倘若该处理针对大量元素的
话,会有一个时钟错误。只有当轮廓函数执行之后才能确信栅栏处理已经完成。尽管您的命令可能并不需要绘出栅栏的轮
廓,栅栏函数也可以用来执行一个需要在内容函数执行完毕后进行的进一步处理。确信您已经对大的设计文件进行了栅栏命
令测试,以保证您的命令操作适合大量元素。
第十六章 M D L 调试器使用指南
一、MDL 调试器环境变量
=================================================================
变量 描述 设置
-------------------------------------
MS_SYSTEM 是否可以返回操作系统 0 或 1
MS_DOSWINDOW 打开 DOS窗口 0 或 1
================================================================
可以采用下述方法之一来激活 MDL调试器:
1. 从 MicroStation装载一个应用并激活调试器。输入:
MS_INITAPPS=<应用程序名>
在同一时刻,只能有一个应用的调试信息被载入.
三、源码位置
四、调试器使用方法
五、调试器输入与输出
六、 C表达式求值器
MDL 调试器命令
选项: /delete;/<count>
• 函数调用栈跟踪:CALLS
选项: /<count>
• 求值:DISPLAY以不同格式显示数据.
选项: /CHAR;/SHORT;/LONG;/DOUBLE;/STRING,可与下列符号组合使用:HEX,OCTAL,DECIMAL。
• 继续:GO <函数名>继续执行到下一断点,或执行到一指定函数。
• 帮助:HELP /帮助命令主题
例如:help /calls
• 列出符号表:SYMBOLS选项:/FUNCTIONS;/VARIABLES;/STRUCTURES。
• 监视:WATCH 仅在 PC 上使用。
选项:/input;/output;/all;/append;/replace;/stop;default。如未指定文件名,则记录到缺省的 mdldebug.log文件。
• 别名:ALIAS <name> <substitution string>
• 条件:IF
• 上限:UP 设置 SCOPE上限。
• 调试级别变量:debugLevel Variable