Tcl/Tk 命令与C/C++的集成研究
Tcl/Tk 命令與C/C++的集成研究
1. 問題來源
????? 基于虛擬現實的維修性分析評價系統(以下簡稱 VMSAS)是為適應產品無紙設計、分析、評審的需要,以人機工效商業軟件JACK 為平臺,由本單位進行二次開發形成的一個維修性設計分析評價系統,主要功能包括樣機建模、動作建模、維修仿真與檢測、維修性分析與評價等。
????? VMSAS 的使用全過程涉及大量數據。為確保VMSAS 滿足并行設計和集成設計的要求,成為一種實用、先進的維修性設計分析工具,能夠與CAD 系統、工程分析系統緊密集成,就必須要解決數據獲取的授權、數據一致的保證、數據的集成、提交、審核與批準等統一管理及權限等問題。
?????? 以上要求 VMSAS 與產品數據管理(PDM)系統進行集成。二者之間的集成方案如圖1 所示。
PDM系統
應用程序接口
系統集成接口
產品配置管理
產品結構管理
變更管理
文檔管理
工作流管理
對象管理框架
RMS軟件
CAD軟件
Microsoft
Office
Adobe
Acorbat
VisView
VMSAS
系統
數據獲取
樣機準備
虛擬樣機成熟
拆卸過程仿真
維修性分
析與評價
仿真過程分析
仿真過程記錄
分析與評價結果
人機和諧界面
人機交互界面
虛擬場景生成
虛擬環境管理
拆卸過程控制
Oracle
產品基本信息
產品可靠性數據
產品故障信息
分析評價準則
虛擬設施工具等
產品CAD數據
維修性設計要求
虛擬人體模型
維修知識經驗
維修資源模型
維修任務及其
仿真分析數據
圖1 VMSAS 系統與PDM 系統集成框架
????? VMASA 以JACK 系統為平臺進行二次開發的,JACK 有一套應用程序開發接口(API)——JACKScript,JACKScript 提供了對JACK 場景進行有效控制的途徑,可以使用Tcl、Python、Lisp 三種語言進行交互以及二次開發。我們以Tcl/Tk 開發應用程序,以Python 開發仿真腳本。選用UGS PLM Solution 公司的TeamCenter Enterprise 系統進行開發來管理VMASA 中的數據。TeamCenter 系統中的應用程序接口API 函數都是以C/C++語言開發的,以DLL 文件形式提供給用戶調用。故要在Tcl/Tk 環境中調用這些API 函數,就要解決Tcl/Tk 命令與C/C++函數之間的接口問題。本文圍繞這個問題進行討論。
????? 基金項目:國家自然科學基金資助項目:并行設計中產品維修性模型研究(編號:50005023),“十五”武器裝備預研項目資助。
????? 作者簡介:梁偉杰(1980.05~),男,漢族,碩士生,研究方向為維修性理論與應用。通訊地址:石家莊軍械工程學院六系維修工程實驗中心,050003。聯系電話:0311-86879059。蔣科藝(1977~),男,漢族,博士生,主要研究方向為虛擬維修仿真以及應用。呂劍鋒(1981~),男,漢族,碩士生,研究方向為維修性理論與應用。
http://www.elecfans.com 電子發燒友 http://bbs.elecfans.com 電子技術論壇
2. Tcl/Tk 設計原理
在控制、仿真、檢測等多個領域,涉及大量專用系統的開發以及測試環境的建立,測試環境的建立異常繁瑣。人們力圖尋找一種新的編程語言,它既要有好的代碼可重用性,又要簡單易學,這樣就促成了Tcl(Tool Command Language,工具命令語言)的產生。其總體結構如圖1所示:
擴展層Tcl層應用層
剖析器
初始化
命令循環
擴展命令內建命令應用擴展命令
圖1 TCL總體結構簡圖
Tcl 讓應用程序由包含編譯代碼的大塊實體和一小部分用于配置和編寫高級命令的Tcl 代碼組成,把編程按照基于組件的方法來進行,不同的組件有不同的功能,用于不同的目的。Tcl 有良好的擴展性, 方便用戶為其增添新的功能模塊。Tcl 是一種集C/C++靈活強大的功能與BASIC 易學高效的風格于一身的通用程序設計語言。
Tcl 是一種可嵌入的命令腳本化語言 (Command Script Language)。“可嵌入”是指把很多應用有效,無縫地集成在一起。“命令”是指每一條 Tcl 語句都可以理解成命令加參數的形式:
????? Tk(Tool Kit)是基于Tcl 的圖形程序開發工具箱,是Tcl 的重要擴展部件。Tcl/Tk 提供了足夠的可編程特性(變量、流程控制和過程),使得現有程序可以組裝成符合自己需要的復雜的腳本程序。Tcl 解釋器可以很容易地添加到已有應用程序中去,這種能力將它與其他Shell 語言區分開來,它是一種擴展語言的語言,用來配置和定制應用程序。Tk 隱藏了許多C/C++ 程序的設計細節,可快速地開發基于圖形界面窗口的程序。Tcl/Tk 可快速開發應用程序及應用系統,在自控、仿真、測試系統、網絡管理、可視化應用、CAD
等方面都有大量的應用成果,在歐美的許多大學和實驗室中都有廣泛的應用。
????? 但Tcl/Tk畢竟是一種腳本語言,就象其它的一些腳本語言一樣,也有很多事情不能夠做或很難做。其解決途徑是聯合C/C++與Tcl/Tk共同開發。提供C/C++程序調用TCL/TK 的解釋器來運行TCL/TK腳本。
3. C/C++函數注冊為Tcl/Tk 命令
?????? 用 C/C++語言很容易實現Tcl/Tk 命令的擴展,而且用C/C++實現的命令比相應的Tcl 命令執行效率要高。在各種以C/C++實現的仿真檢測程序中可方便地調用Tcl/Tk 命令。實現Tcl 命令的C/C++代碼被稱之為命令過程(command procedure),命令過程的接口非常類似于主程序main 的接口,它的輸入是一個數組,包含了與Tcl 腳本命令變元確切對應的值,其結果就是Tcl 命令的結果。
?????? 在用戶的 C/C++程序中,為了能夠訪問TCL/TK 庫,必須在源代碼聲明兩個調用庫的頭文件,即"tcl.h"
和"tk.h"兩個文件。要建立混合Tcl/Tk 和C/C++應用程序,須按如下方式進行:
3.1 調用"Tcl_Main"函數(Tk_Main 原理相同)
????? Tcl_Main(argc, argv, Tcl_AppInit),用來控制整個Tcl 解釋器程序,沒有返回值。這是一種較為高級的接口,可以替用戶創建解釋器、處理命令行變元來執行腳本,提供交互式命令循環等。"Tcl_Main"函數有三個變量:第一個變量表示在這個數組的元素個數;第三個變量是指向初始化函數的指針;第二個變量是一個字符串型數組,每個字符串都有一個特殊的含義。字符串數組通"Tcl_Main"來通知Tcl/Tk 解釋器應用程序的名稱和Tcl/Tk 命令在腳本中的位置。這個數組實際上是傳給解釋器的命令行參數。數組的第一項給出應用程序名稱,第二項給出了運行的腳本位置。
命令 [參數 1] [參數 2] [參數 3] [參數 4] ...... [參數 N]
http://www.elecfans.com 電子發燒友 http://bbs.elecfans.com 電子技術論壇
3.2 初始化函數
????? "Tcl_Main"的調用控制了程序在Tcl/Tk 中的整個調用,但是在底部初始化之后和Tcl/Tk 腳本運行之前,能夠執行用戶自定義的函數。在從Tcl/Tk 腳本中使用命令過程之前,必須提供該命令過程的初始化注冊過程,為了使用Tcl 解釋器,應用程序首先產生一個稱之為解釋器(interpreter)的對象。此時,如果要將自己的擴展模塊創建為共享庫,此初始化過程的名稱必須以“_Init”來結束,如TclApi_Init,Random_Init等。當Tcl/Tk 腳本加載這個庫的時候就會自動調用這個過程。
3.3 C/C++函數注冊為Tcl/Tk 過程
????? C/C++函數在Tcl 中注冊時需調用一個特定的原型函數,此函數返回一個整數類型,并設置4 個變量,第一個是Tcl/Tk 庫文件類型"ClientData";第二個變量是指向解釋器的指針;最后的兩個變量類似于在C/C++ "main"函數中的"argc"和 "argv"這兩個變量被用于傳遞參數給Tcl/Tk 過程。參數"argc"包含了傳遞給Tcl/Tk 過程的參數個數"argv" 是字符串數組,每個字符串包含了一個參數。如下所示:
int TclApi(ClientData clientData, Tcl_Interp *interp,int argc,char *argv[]);
當一個函數被注冊作為Tcl/Tk 過程使用時需一個指針與之聯系,指針通過"ClientData"來傳遞進來。
"ClientData"的概念允許程序員聯系數據結構和對象,調用能引用這個對象的過程。3.2 中提到的注冊過程需要調用"Tcl_CreateCommand"函數,此函數有5 個參數:第一個參數是指向解釋器的指針;第二個參數是在Tcl/Tk 中的過程名;第三個參數是一個指向函數的指針,它在Tcl/Tk 過程被執行時調用;最后兩個參數是"ClientData"項和一個指針刪除例程。如下面例子所示,Tcl/Tk 將"TclApi"函數注冊為" tcl_app"命令:
Tcl_CreateCommand(interp, "tcl_app", TclApi, (ClientData)NULL,(Tcl_CmdDeleteProc *)NULL );
3.4 變量訪問
在執行Tcl/Tk 過程時能調用C/C++函數,并可從C/C++中通過一些函數獲得Tcl/Tk 的幫助。
"Tcl_GetVar"函數返回一個指向Tcl/Tk 變量的字符串指針。此Tcl/Tk 變量在執行腳本聯系到解釋器的當前范圍被訪問,如果在當前范沒有局部變量則訪問全局變量,如沒有匹配的全局變量存在則返報告錯誤。
下面是Tcl/Tk 腳本中被訪問的一部分代碼。
set a_prd_tree_name "1966PZ152"
下面是在C/C++代碼中訪問Tcl/Tk 變量:"a_prd_tree_name"
char PTName_001 [10];
strncpy(PTName_001, Tcl_GetVar( pInterp, "a_prd_tree_name", 0 ), 9 );
這樣,變量PTName_001 的值就變為了"1966PZ152"。
"Tcl_SetVar"函數允許程序修改Tcl/Tk 變量的值。
綜上所述,若要實現Tcl/Tk 命令調用C/C++ API,則被調用的API 需具有以上特定結構,可給此API構造一個具有以上特性的“外殼”,如圖2 所示:
擁有Tcl解釋器的C/C++函數
函數的Tcl初始化過程
Tcl/Tk腳本中要調用的DLL
中的C/C++函數
C/C++函數注冊為Tcl/Tk命令
Tcl/Tk命令C/C++過程
圖 2 Tcl/Tk 調用C/C++函數
4. Tcl/Tk 命令調用PDM 系統API 函數的一個實例
如何在 Tcl/Tk 命令實現的系統中調用C/C++ DLL 中的函數是筆者在VMSAS 系統與某PDM 系統進行集成時遇到的問題。有人寫過一個可以將C/C++ API 輸出為Tcl 命令的工具,叫做SWIG(Simple WrapperInterface Generator)。這個工具的缺點是C/C++的代碼必須可知,并且SWIG 生成的C 接口對于腳本編寫http://www.elecfans.com 電子發燒友 http://bbs.elecfans.com 電子技術論壇
人員并不友好,而手工編制的Tcl 接口要好得多。
例如,用戶要登錄 PDM 系統,首先必須要進行驗證,此時用到一個baseapi.dll 中的函數:
int clLogin2(char UsrName[], char Password[], int mfail)
要在Tcl/Tk 腳本中調用這個函數。可按如下方式進行:
1)、生成DLL 必要信息
#include "stdio.h"
#include "string.h"
#include "windows.h"
#include "tcl.h"
#ifndef DECLSPEC_EXPORT
#define DECLSPEC_EXPORT __declspec(dllexport)
#endif
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return TRUE; }
2)、引用這個函數
#pragma comment(lib, "/yourPath/baseapi.dll")
extern "C" _declspec(dllimport) int clLogin2(char UsrName[], char Password[], int mfail);
3)、對應的擁有Tcl 解釋器的形式
int clLogin2Cmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]);
4)、對此函數進行初始化
EXTERN_C int DECLSPEC_EXPORT clLogin2_Init(Tcl_Interp* interp) // 此處必須加“_Init”后綴
{ // 將此C 過程注冊為Tcl 命令
Tcl_CreateCommand(interp, " clloginto",
(Tcl_CmdProc *)ClLogin2Cmd, // 調用第4 步實現
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_PkgProvide(interp, " clloginto ", "0.1"); // 給此注冊的Tcl 命令一個版本號0.1
}
5)、具體的實現
int clLogin2Cmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[ ] )
{ char usr[]; char psword[];
int error1, error2, error3, mfail, dstat;
clLogin2_Init(interp); // 必須先調用函數初始化過程
if (argc > 4)
{ interp->result = "Usage: clloginto ?range?";
return TCL_ERROR; }
if (argc == 4)
{ // 使用 Tcl_GetString 接受字符串參數:
error1 = Tcl_GetInt(interp, argv[1], usr);
if (error1 != TCL_OK) return error1;
error2 = Tcl_GetString(interp, argv[2], psword);
if (error2 != TCL_OK) return error2;
error3 = Tcl_GetInt(interp, argv[3], mfail);
if (error3 != TCL_OK) return error3;
}
dstat = ClLogin2(usr, psword, mfail); // 在此調用C DLL 中的函數
return dstat; // 返回登錄狀態值,由此可以進行用戶登錄驗證
}
http://www.elecfans.com 電子發燒友 http://bbs.elecfans.com 電子技術論壇
可將上述實現在C/C++編譯器中生成一個DLL 文件,這個DLL 中的函數就可以由Tcl/Tk 經過pkg_mkIndex 和package require 命令處理就可調用了。以上只是一個簡單的示例,其它函數可以相應地進行處理,也可以用宏實現大量函數的轉化,此處不再贅述。
5. 小結
通過以上的分析,實現了在Tcl/Tk 腳本中調用C/C++ DLL 中的函數。并在VMSAS 與某PDM 系統集成中進行了驗證。
此種方法對于其它的以Tcl/Tk 實現的仿真或檢測系統中,為提高運行效率或提供新的功能而引入C/C++函數進行擴展的情況,都有一定的參考意義。
參考文獻:
[1] 郝建平,蔣科藝等,基于虛擬維修仿真的維修性分析評價及系統實現,數字制造科學,2004.12
[2] Brent B. Welch. Tcl/ tk 組合教程。王道義,喬陶鵬等譯。北京:電子工業出版社,2002.6
[3] 王堅,金革,Tcl/Tk 和 C 語言的接口,計算機應用,2000.12
[4] 周波,楊貫中,蔡宇輝,TCL/TK 語言結構分析及其在網絡教學中的應用,計算機工程,2002.4
[5] http://www.swing.org
[6] news://comp.lang.tcl
[7] http://www.tclchina.com
[8] http://etude.uwaterloo.ca/~ctrudeau/lessons/tcl_tk/tcl_C.html
總結
以上是生活随笔為你收集整理的Tcl/Tk 命令与C/C++的集成研究的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 科拓通讯IPO被终止:年营收7.19亿
- 下一篇: 【PHP】使用JpGraph绘制饼状图的
