谭 冬,唐志广
(大连中远海运重工有限公司,辽宁大连 116113)
可编程的宏语言(Programmable Macro Language, PML)是Aveva Marine(AM)软件提供的一种用于二次开发的编程语言,其广泛应用于AM软件Outfitting模块的二次开发。最新版的PML提供了面向对象的特性,具有丰富的内置函数、方法及对象,支持用户自定义对象类型[1]。在AM的二次开发中,PML语言以其简单易学、无缝对接的特性吸引了众多开发者[2]。
PML与AM软件的关系类似于LISt Processor(LISP)语言和AutoCAD,虽然语言与宿主软件之间可无缝集成,但是对涉及到用户界面、文件操作、外部数据交互等方面时会十分为难,甚至无法实现[3]。与此同时,众多的高级语言如C#、VB.NET、C++CLI等具有强大的可视化集成开发环境(Integrated Development Environment, IDE),在编写图形用户界面、与操作系统交互、操纵数据库等方面又天然具有优势,但是让众多的PML开发者重新学习高级语言又受各种现实情况的制约。
为弥补PML在二次开发中的不足,本文介绍了一种通过为PML开发者提供一个可以连接PML和高级语言的互操作中间件,使PML程序和其他高级语言进行互操作,以拓展PML功能的思路和方法,并以实际应用中的开发项目为例,对该方法的效果进行介绍。
为方便客户化开发,AM软件的应用程序编程接口(Application Programming Interface, API)允许用户自定义PML模块,拓展PML语言的功能以满足特定需求[4]。利用AM提供的拓展PML语言的方法,可使用C#、C++ CLI或其他.NET语言编写1个动态链接库,然后在PML中调用此动态链接库(Dynamic Link Library, DLL)中提供的类、或者函数,软件架构见图1。
图1 PML程序中引用其他DLL的架构
.NET类库提供了强大的基础函数与图形用户界面(Graphical User Interface, GUI)控件,利用C#语言开发动态链接库,并作为互操作中间件提供PML和.NET类库之间的连接[5]。将可被PML调用的C#动态库称为PMLNetCallable动态库,将动态库中可被PML调用的C#类称为PMLNetCallable类,将类中可被PML调用的方法称为PMLNetCallable方法。下文对利用C#语言开发DLL扩展PML功能的方法进行研究。
要创建PMLNetCallable动态库,首先需要创建1个普通的.Net类库程序集PMLNet.dll,然后引用AM中的PMLNet.dll,并对程序集中需要被PML调用的类或者方法附加[ PMLNetCallable( ) ]特性,见图2。
图2 在程序集中引用PMLNet.dll
在C#中可以简单把一个程序集对应一个命名空间,在这个命名空间里定义功能类供外部调用,该步骤的目的在于简化概念。本文所开发的程序集命名空间名称为CoscoDL.NetPML.UI,命名规则为<公司名>.<模块名>.<功能>。
普通的C#类代码如下:
public class ExamplePMLClass
{
public ExamplePMLClass ( )
{…}
public void ExampleFun ( )
{…}
}
类中有1个默认构造函数和1个ExampleFun方法。经过简单修改,在类上或方法上附加[ PMLNetCallable( ) ]特性(见斜体部分)。修改后的类即可被PML调用。
[PMLNetCallable( )]
public class ExamplePMLClass
{
[PMLNetCallable( )]
public ExamplePMLClass ()
{…}
[PMLNetCallable( )]
public void ExampleFun()
{…}
[PMLNetCallable( )]
publicvoidAssign(ExamplePMLClassthat)
{…}
}
在使用[PMLNetCallable( )]特性前,还需要在using语句后添加如下代码:
using Aveva.PDMS.PMLNet;
利用互操作拓展PML功能的方法可总结为如下6个步骤:
1)为类附加特性(Attribute),即在类名前一行附加[PMLNetCallable( )]特性。
2)为类的默认构造函数附加[PMLNetCallable( )]特性。
3)为需要在PML中调用的类方法附加特性[PMLNetCallable( )]。
4)为类添加Assign()方法,添加过Assign()方法的类才能在PML中互相赋值。
5)在“解决方案资源浏览器”窗格中,双击打开AssemblyInfo.cs,并在using语句之后添加如下代码:
using Aveva.PDMS.PMLNet;
[assembly: PMLNetCallable()]
6)编译工程,生成PMLAddin.dll。
利用互操作拓展PML功能时必须对调用双方的数据类型进行约束,否则调用传递数据时会导致错误的结果[6]。
被调用C#方法的参数和返回值的数据类型见表1。
表1 PML与C#中的数据类型对照表
在PML中调用C#生成的PMLNetCallable动态库,或使用PMLNetCallable/PMLNetCallable方法时,需要先将生成的PMLAddin.dll文件拷贝到AM的安装目录下,然后在PML文件中按如下4个步骤使用。
1)引用此DLL
import 'PMLAddin'
2)使用此DLL的命名空间
using namespace 'CoscoDL.NetPML.UI'
3)定义一个变量,创建类的实例
!m = object ExamplePMLClass ( )
4)调用类中的方法
!m.ExampleFun ( )
可以在CommandWindow中直接输入命令,也可以编写PML程序文件。在CommandWindow中直接输入以下代码,可引用AM软件MarAPI.dll中的打开图纸功能:
若要编写PML程序,可以参考下面的示例代码。PML窗体仅创建了一个按钮,点击按钮调用ExampleFun( )方法,执行C#中ExamplePMLClass类的ExampleFun函数[7-8]:
程序运行的最终效果见图4。在C#中将界面开发完成,再利用PML调用效果画面。如此复杂、美观的界面,仅靠使用PML代码是不可能开发出来的。由此可见,研究PML调用C#或其他高级语言的互操作方法具有较好的实用意义。
图4 程序运行的最终效果
本文通过PML调用C#的动态链接库这一实例,利用C#丰富的类库、控件库,生成了优质的用户界面,并且实现了和后台接数据库的连接功能,用数据库作为数据源,对AM项目中的模型进行自动化修改,大大拓展了PML使用范围。基于.NET平台的强大功能,C#不仅有丰富的类库、控件库可以使用,还可以借助Visual Studio开发工具进行编译,增强了代码保密性,甚至可以通过C#对Windows的API的调用来实现和其他应用程序互动以及对Window底层进行控制,具有丰富的想象空间和广泛的实用性。C#本身还可调用其他语言开发的库和程序,可以为PML语言拓展更加丰富的实用功能。