2014年6月9日 星期一

[原創] LabVIEW wrapper Callback from dll (1) Introduction

LabIEW 的 Call Library Function.vi 提供了介面讓LabVIEW使用者得以呼叫其他語言開發的程式,網路上相關教學資源算是豐富,可以參考下面連結:
官方文件:
How Do I Call a Dynamic Link Library (DLL) from LabVIEW?
Call Library Function Returns the Wrong Function Prototype and Function Parameters for DLLs
Creating Dynamic Link Library (DLL) in Microsoft Visual C++ 6.0 for use in LabVIEW

官方論壇文章:
Calling C/C++ DLLs Containing Simple and Complex Datatypes from LabVIEW
這篇大概解決了90%遇到複雜的structure、pointer的傳遞方式

官方範例程式:
Windows Message Queue Library
這篇應該是最經典範例程式,範例程式教使用者如何用C wrapper LabVIEW內的Message Queue,讓開發人員了解如何打通傳遞dll內的資料到LabVIEW裡面的Queue元件,而且範例程式傳遞的資料不別的正是LabVIEW程式天生缺少的message loop訊息

雖然網路資源如此豐富,但還是缺少了較完整的wrapper callback函數的教學,雖然LAVA有一篇文章我認為已經說明得非常清楚,但對於C/C++/Visual C++相對陌生的LabVIEW開發人員而言還是挺困難的,因此本篇文章會把重心移到如何編寫wrapper callback 函數的部分

第一篇文章會說明callback函數的原理
第二篇文章為實際範例,在dll內掛載全局的鍵盤滑鼠的鉤子,並註冊到user event
這個程式可以讓user event回傳鍵盤滑鼠的資料,不論LabVIEW程式是否為當前視窗都可以,也就是說即使LabVIEW程式被最小化或是隱藏在桌面右下角的圖示,程式還是可以收到鍵盤滑鼠的資料。再來是攔截usb裝置插入/拔出的事件並註冊到user event。不知道為什麼網路上都沒有相關的程式碼資料,難道大家都是用polling偵測usb裝置的有無嗎?用了這個程式後未來靠它就可以知道甚麼時候裝置被插上或拔除了

何謂callback函數呢?
詳細的說明可以參考這篇
實作可以參考這篇
基本上就是我們除了可以用callback讓程式不需要藉由polling的方式等待某些函數的處理,而是等到函數處理完畢後發觸發設定的callback函數然後讓主線程(通常是UI Thread)來處理
例如windows Message傳遞訊息的機制或是driver處理處理與硬體的通訊,都不希望占用到程式執行時需要polling這些"事件",程式需要就去向系統或被呼叫的程式去"註冊"這些事件,一旦發生就轉到註冊好的函數裡執行

在LabVIEW裡的event structure就有點類似這個架構,在LabVIEW裡處理按鈕狀態改變(on cgange),可以靠while loop去polling這個訊息,也可以向event structure去註冊這個訊息,一旦發生就跳到對應的"event程式碼"裡面去處理。按鈕的事件再event程式碼帶出OldVal/NewVal等等按鈕的資料,callback函數也可以帶出函數觸發時需要被處理的參數,因此vc下callback函數的宣告會類似 int (WINAPI *PFCALLBACK)(int Param1,int Param2) ; Param1和Param2就是附帶的相關參數

基於以上所述我認為LabVIEW中最適合wrapper callback函數(所以還有其他方式可以wrapper )接下來教學的內容因此以event structure來wrapper callback

附帶一提,LabVIEW內 Call Library Function Node 裡面的 Callbacks跟本篇文章所談的callback一點關西都沒有

針對這個callbacks的說明參考下面連結:

其中的敘述如下:

Configuring Callbacks

When you configure a Call Library Function Node to call a function, you can use the Callback tab to specify other functions within the same library to call at the following times:
  • Reserve time—When the top-level VI that causes the Call Library Function Node to execute begins executing. Specify a Reserve callback when you need to perform initialization tasks before the primary function executes.
  • Unreserve time—When the top-level VI that caused the Call Library Function Node to execute stops executing. Specify an Unreserve callback when you save or analyze information or carry out clean-up operations.
  • Abort—The specified function executes if the VI that called the primary function aborts.
與就是說如果你想為LabVIEW寫專門的dll,可以寫三個函數Reserve()、Unreserve()、Abort()然後再Callbacks這邊指定,這樣LabVIEW在執行最上層程式碼的時候會自動在開始執行時的初始化階段呼叫Reserve(),在LabVIEW在執行最上層程式碼結束時呼叫Unreserve(),在按下Abort按鈕時執行Abort()所以一般dll應該是沒有機會用上的



沒有留言:

張貼留言