譚 冬,唐志廣
(大連中遠海運重工有限公司,遼寧大連 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語言拓展更加豐富的實用功能。