技術頻道

      VC++和基于Lab Windows/CVI的DLL在測控技術中的應用

      摘 要:介紹了動態鏈接庫(DLL)的運行機制,闡述了基于Lab Windows/CVI的DLL的開發以及它和VC++程序的集成方法,對于兩種程序之間的通訊,給出了一種基于內存映射的實現方法。文章最后給出了一個技術上具體實現的例子加以說明。

      關鍵詞: 虛擬儀器;Lab Windows/CVI;DLL;內存映射

      1、引言

        大型測控系統的軟件系統通常采用高級語言結合專用測控軟件來開發。如何將不同的軟件程序加以集成,以及如何在它們之間進行通訊是必須解決的問題。

        虛擬儀器測控系統中關鍵工作就是對數據的采集、分析、處理并模擬真實儀器面板的功能。由于VC++等高級語言的非針對性,采用其實現起來不僅復雜(如創建儀器面板,數據分析等),而且有些功能無法實現,源代碼效率也較低;若采用Lab Windows/CVI,不僅開發方便,而且直觀,有些開發工作只需幾行代碼即可完成,可以大大提高系統開發的效率,節約時間。在筆者所參與的測控系統的開發中,采用的是用VC++開發系統軟件主干程序,負責系統軟件各方面的調度、管理,采用Lab Windows/CVI開發具體的測控功能,以具有不同功能的DLL形式組成測試功能模塊庫,集成到主干程序中實現各種不同的測控功能,采用內存映射實現兩種程序間通訊和數據傳輸。

      2、Lab Windows/CVI中DLL的開發

        2.1 Lab Windows/CVI中DLL的開發方式及其運行機制

        在CVI環境下,開發用于測控領域的動態鏈接庫,需將編譯目標文件類型設置為DLL,并設置DLL名稱、存儲路徑、DLL函數/變量導出方式等,才能通過Create Debuggable Dynamic Link Library生成DLL工程。

        DLL不是可執行文件,它需要由應用程和另外的DLL調用執行。一個程序使用DLL,它只能通過這個DLL的導出函數/變量訪問其內部。在Lab Windows/CVI下創建DLL,有兩種方式導出函數/變量:頭文件法和導出關鍵字法。頭文件法使用頭文件確定要輸出的標號,頭文件中必須包含要導出標號的聲明;導出關鍵字法把每一個要導出的函數和變量都標記一個關鍵字,如__cdecl、__stdcall等,根據不同的編譯器使用不同的導出關鍵字。在DLL中只有被導出的函數/變量才能被外界所使用,所以只有指定DLL的導出函數/變量,該DLL才具有實際的使用意義。

        DLL被調用時,它有自己的運行機制:每一個DLL都有一個DLLMain主函數,在進入和退出DLL時,應用程序分別調用這個函數,它常常被用來執行進程的初始化和清理工作。因為在該函數中定義了兩個事件句柄——DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH。當一個DLL被調用,即它被首次映射到進程的地址空間時,系統觸發DLL_PROCESS_ATTACH事件,一般在這部分執行特定進程的DLL初始化工作,如調用InitCVIRTE()函數初始化引擎等;當應用程序結束DLL的調用時,系統觸發DLL_PROCESS_DETACH事件,一般在這部分進行退出DLL時前的資源清理工作,如調用CloseCVIRTE ()釋放被DLL所占用的內存。另外,CVI還提供了一個RunStateCallback()函數來對程序的執行情況進行記錄,使用時通過該函數也可以控制程序的執行及系統資源分配。

        2.2工程中DLL的開發

        筆者所參與的測控系統的開發中, DLL開發采用的是另外一種方式,由于DLL本身的不可執行性,調試上沒有可執行文件方便,而且工程上需要在導出的DLL中包含虛擬儀器軟面板,且保持軟面板對虛擬儀器的控制性,因此,在實際的開發中,先編寫CVI用于實現具體測控功能的可執行文件,調試成功后,把該可執行文件改成具有相同功能的DLL。改編時,僅僅對源文件(.c文件)的main函數做一些改變,并在頭文件(.h文件)中輸出,而無需做多的改變即可導出儀器軟面板,這樣在VC++主干程序調用該DLL時就可以方便的進行測控工作。

        具體操作上:

        (1)首先編寫滿足測控要求的CVI的可執行文件并調試成功;

        (2)在工程文件中打開包含工程主函數main()的.c文件,向文件中插入DLL所必須的DLLMain函數。

        (3)改寫.c文件中的main函數。修改其函數名及參數,將其參數改為Windows的實例句柄HINSTANCE,它指向DLL被調用時DLL被映射到的進程的地址空間。另外由于調用時要使用儀器軟面板,就必須導出相應的.uir函數,因此main中的編譯環境默認的Loadpanel函數要用LoadpanelEx替代,因為使用Loadpanel函數時,用戶界面庫無法找到在.uir文件中定義的但沒有被DLL輸出的那些回調函數,從而使DLL在被調用時出錯。對于LoadpanelEx,因為使用CVI編寫DLL時,CVI自動在工程中生成一個.uir中的回調函數列表,DLL被調用時,LoadpanelEx首先在此列表中進行查找,它可以實現回調函數的導出,從而保證在DLL中軟面板對虛擬儀器的正常控制。

        (4)將修改后的main函數的聲明加入到原工程的頭文件。

        (5)選擇頭文件導出法,編譯成DLL文件。

        經過改編后原工程就變成了可以由VC++主干程序調用的DLL,而它的所有測試功能都沒有變。事實證明,因為這種創建DLL的方法不需要增加額外的程序進行代碼調試,它比一般的直接創建方法要有效的多。

      3 VC++應用程序對DLL的調用

        3.1 VC程序調用DLL的兩種方式

        VC中鏈接DLL到應用程序中有兩種方式:隱式鏈接和顯式鏈接。隱式鏈接時,使用DLL的可執行程序鏈接到DLL導入庫(.lib文件)中,導入庫中包含了DLL中的每個導出符合和序號。當加載使用DLL的可執行程序時,操作系統同時加載DLL。為了隱式鏈接DLL,可執行程序需要從DLL提供者獲取以下內容:包含導出函數聲明的頭文件(.h),導入庫(.lib)文件和實際的DLL(.dll)文件。顯示鏈接時,使用DLL的可執行程序在運行時通過函數調用來顯式加載或卸載DLL,并通過函數指針來調用DLL的導出函數,應用程序通過Loadlibrary函數來加載DLL并獲取模塊句柄;通過GetProcessAddress來獲取應用程序要調用的導出函數的指針。

        工程中筆者采用的是顯式鏈接方式調用DLL,與隱式鏈接相比,顯示鏈接較靈活,在這種方式下,我們可以決定什么時候裝載和卸去DLL,以及決定加載哪個DLL,可以節約系統資源,代碼執行效率高。

        3.2 VC程序與測試模塊間的通信

        在用VC++調用CVI的DLL時,存在著在不同軟件程序間的數據傳遞問題,工程中VC++程序是主干,它調用DLL,因此它的變量對DLL來說都是透明的、可用的;但是由Lab Windows/CVI開發的DLL文件生成的導出庫文件(.lib)不包含導出變量,因此DLL中的變量值,VC++不能直接獲得。工程中采用創建內存映射文件的方法來實現二者之間的數據傳遞。所謂內存映射文件是指在內存中申請一塊內存空間,將一個文件與這塊空間相聯系,再進行內存映射,這樣操作文件就有和操作內存一樣的效率,數據可以通過該映射文件進行中轉(寫入和讀出),幾個進程可通過操作該映射文件,實現進程間在內存一級的高速數據交互。

        具體方法為:首先在DLL中通過API函數CreateFileMapping及MapViewOfFile在內存中建立一個文件映射對象并產生它的一個視,然后通過CopyMemory將測控數據存入

        該視中,然后應用程序就可使用OpenFileMapping打開該映射文件并對其進行讀寫操作,從而實現二者間通信。

      4 代碼實例

        限于篇幅,文中只給出部分重要的程序代碼。

        4.1 CVI中程序代碼

        1)對源文件的main函數進行改寫:

        int main1 (HINSTANCE CVIUserHInst)// 修改函數名以及參數

        {

        if ((panelHandle = LoadPanelEx (0, "get.uir", PANEL,__CVIUserHInst)) < 0) //使用loadPanelEx函數可導出回調函數

        return -1;

        ……

        return 0;

        }

        (2)創建內存映射文件并拷入數據

        hValue=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,0x300,"MapFile");//建立文件映射對象,MapFile為 映射文件名

        ……

        ipmid=(mid*)MapViewOfFile(hValue,

        FILE_MAP_ALL_ACCESS,0,0,0);//創建映射對象的一個視,mid為測控數據類型

        ……

        CopyMemory(ipmid,&data,sizeof(mid));//將數據拷貝到共享的內存中

        (3)在.h文件中加入修改后的main函數的導出聲明

        int main1 (HINSTANCE CVIUserHInst);

        4.2 VC中程序代碼

        typedef int(*main1)(HINSTANCE); HINSTANCE USEInst;

        USEInst=LoadLibrary("sousuoleidafashe_dbg.dll"); //加載DLL

        main1 main; main=(main1)GetProcAddress(USEInst,

        "main1");//得到DLL中導出函數main1的地址

        main(USEInst);//執行main1,調出儀器軟面板進行測試,測控數據寫入”MapFile”中

        FreeLibrary(USEInst);

        HValue=OpenFileMapping(…);//打開映射文件”MapFile”

        ipmid=(mid*)MapViewOfFile(hValue;

        FILE_MAP_ALL_ACCESS,0,0,0); //得到測試數據

        至此,就完成了LabWindows/CVI中的DLL開發和VC++主干程序對它的調用工作以及數據傳送工作。

      5 結束語

        本文介紹了一種把VC++和LabWindows/CVI結合起來進行測控系統開發的方法,根據兩種開發工具各自的優缺點,取VC++對數據庫、多媒體等的強大的開發能力和它廣泛的適用性,結合LabWindows/CVI對測控數據強大的分析處理能力和它簡單直觀的儀器軟面板設計方法。實踐證明這種方法是完全可行的。

      6 參考文獻

        [1]NI Corporation.LabWindows/CVI User Interface Reference Manual [M/CD], 1996.

        [2] 張磊, 虛擬儀器測試系統中實現數據共享的方法[J],計算機自動測量與控制, 2000年第05 期:58-60

        [3] 白鳳山,動態連接庫(DLL)在虛擬儀器中的應用[J],自動化與儀表,第16卷,2001年第01期:21-22

        [4] [美]David J.Kruglinski,Visual C++ 技術內幕[M],北京,清華大學出版社,1999年

      文章版權歸西部工控xbgk所有,未經許可不得轉載。

      主站蜘蛛池模板: 久久国产精品一区免费下载| 欲色影视天天一区二区三区色香欲| 日韩少妇无码一区二区三区| 亚洲AV永久无码精品一区二区国产| 69福利视频一区二区| 无码毛片一区二区三区视频免费播放| 人妻少妇精品视频一区二区三区 | 亚洲无删减国产精品一区| 亚洲一区二区高清| 色一乱一伦一区一直爽| 夜精品a一区二区三区| 欧美亚洲精品一区二区| 久久精品无码一区二区无码| 亚洲综合无码AV一区二区| 清纯唯美经典一区二区| 高清一区二区三区| 波霸影院一区二区| 一区二区三区视频在线播放| 国产女人乱人伦精品一区二区| eeuss鲁片一区二区三区| 国产精品视频免费一区二区| 亚洲欧美一区二区三区日产| 黑巨人与欧美精品一区| 国产精品无码一区二区在线观 | 成人精品视频一区二区三区不卡| 一区二区三区91| 激情综合一区二区三区| 国产一区二区精品| 亚洲国产情侣一区二区三区 | 一区二区三区精品高清视频免费在线播放 | 国产精品亚洲一区二区在线观看| 亚洲AV无码一区二区三区性色| 国产乱码一区二区三区四| 亚洲一区二区三区在线观看网站 | 亚洲国产精品无码久久一区二区| 国产裸体歌舞一区二区| 久久无码人妻一区二区三区| 亚洲高清毛片一区二区| 视频一区二区三区免费观看 | 波多野结衣AV一区二区三区中文| 国产一区二区影院|