Hi
I would like to ask if anyone has experience of interfacing with LabView.
The situation is as follows: I have a compiled .vi with a nice LabView GUI and I need to automatically set some parameters on it. I discovered the hard way that the controls you see aren't child windows you can communicate with by sending messages. They are simply drawn on a large client window and the application does all the necessary management to react as if it were a normal Windows binary, but it is not.
After a few tries, I decided on a more or less ugly way of doing it, like AutoIt, moving and clicking the mouse using win32 APIs and using SendInput to send characters to this main window.
Has anyone discovered or know of a better way?
Regards, Biterider
I have no clue about LabVIEW, but this is not helpful ? User Interface Manager for LabVIEW (https://www.ni.com/de/support/downloads/tools-network/download.user-interface-manager-for-labview.html#374499)
Otherwise, to ask the LabVIEW Community is maybe more helpful. Just found this: https://forums.ni.com/t5/LabVIEW/pass-parameters-to-main-VI/m-p/3994226 (https://forums.ni.com/t5/LabVIEW/pass-parameters-to-main-VI/m-p/3994226)
Thanks Greenhorn
The "User Interface Manager for LabVIEW" is a GUI design tool. It is not intended to interact with a running vi.
Before posting to the LabView forum, I wanted to ask here first :biggrin:
Biterider
Hi
There seems to be no decent way to interact with the LabView GUI without having the .vi sources and adding a server to interact with.
Just as a reference in case anyone faces the same challenge, the approach described in the first post works pretty well using the SendInput (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) API. The main issue here is that the input sequence should not be disturbed by hardware inputs that would lead to wrong mouse positions and keystrokes landing in the wrong windows.
The solution is to create all the required inputs together and send them with a single SendInput call.
You also need to call BlockInput (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-blockinput) to temporarily disable mouse and keyboard input. The disadvantage is that you need administrator rights if UAC is enabled.
You can fine-tune by restoring the foreground window/focus and mouse position after the action has been performed.
Reference code:
FillMousePosition macro Position:req
mov [xbx].INPUT.type_, INPUT_MOUSE
mov ecx, WRect.left
add ecx, &Position&_X
invoke MulDiv, ecx, 65535, ScreenSize.x
mov [xbx].INPUT.mi.dx_, eax
mov ecx, WRect.top
add ecx, &Position&_Y
invoke MulDiv, ecx, 65535, ScreenSize.y
mov [xbx].INPUT.mi.dy, eax
mov [xbx].INPUT.mi.mouseData, 0
mov [xbx].INPUT.mi.dwFlags, MOUSEEVENTF_MOVE or MOUSEEVENTF_ABSOLUTE
mov [xbx].INPUT.mi.time, 0
mov [xbx].INPUT.mi.dwExtraInfo, 0
inc dInputCounter
add xbx, sizeof(INPUT)
endm
FillMouseAction macro Action1:req, Action2:req
mov [xbx].INPUT.type_, INPUT_MOUSE
mov [xbx].INPUT.mi.dx_, 0
mov [xbx].INPUT.mi.dy, 0
mov [xbx].INPUT.mi.mouseData, 0
mov [xbx].INPUT.mi.dwFlags, Action1
mov [xbx].INPUT.mi.time, 0
mov [xbx].INPUT.mi.dwExtraInfo, 0
inc dInputCounter
add xbx, sizeof(INPUT)
mov [xbx].INPUT.type_, INPUT_MOUSE
mov [xbx].INPUT.mi.dx_, 0
mov [xbx].INPUT.mi.dy, 0
mov [xbx].INPUT.mi.mouseData, 0
mov [xbx].INPUT.mi.dwFlags, Action2
mov [xbx].INPUT.mi.time, 0
mov [xbx].INPUT.mi.dwExtraInfo, 0
inc dInputCounter
add xbx, sizeof(INPUT)
endm
FillMouseLeftClick textequ <FillMouseAction MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP>
FillKeyStroke macro Char:req
mov [xbx].INPUT.type_, INPUT_KEYBOARD
mov [xbx].INPUT.ki.wVk, Char
mov [xbx].INPUT.ki.wScan, 0
mov [xbx].INPUT.ki.dwFlags, 0
mov [xbx].INPUT.ki.time, 0
mov [xbx].INPUT.ki.dwExtraInfo, 0
inc dInputCounter
add xbx, sizeof(INPUT)
mov [xbx].INPUT.type_, INPUT_KEYBOARD
mov [xbx].INPUT.ki.wVk, Char
mov [xbx].INPUT.ki.wScan, 0
mov [xbx].INPUT.ki.dwFlags, KEYEVENTF_KEYUP
mov [xbx].INPUT.ki.time, 0
mov [xbx].INPUT.ki.dwExtraInfo, 0
inc dInputCounter
add xbx, sizeof(INPUT)
endm
.code
SetRoomTemp proc uses xbx xdi, dRoomID:DWORD, pRoomTempA:PSTRINGA
local hRTF:HWND, WRect:RECT, SMI[200]:INPUT, dInputCounter:DWORD
local hLastForeWnd:HWND, LastCursorPos:POINT, ScreenSize:POINT
invoke FindWindow, $OfsCStr("LVDChild"), $OfsCStr("RTF.vi")
.if xax != 0
mov hRTF, xax
DbgStrA pRoomTempA
invoke GetSystemMetrics, SM_CXSCREEN
mov ScreenSize.x, eax
invoke GetSystemMetrics, SM_CYSCREEN
mov ScreenSize.y, eax
invoke GetCursorPos, addr LastCursorPos
mov hLastForeWnd, $invoke(GetForegroundWindow)
invoke BlockInput, TRUE ;Lock input from physical Mouse & Keyboard
;Requires admin rights!
invoke SetForegroundWindow, hRTF
invoke GetWindowRect, hRTF, addr WRect
;Select Testroom
mov dInputCounter, 0 ;Reset structure offset counter
lea xbx, [SMI]
FillMousePosition ROOM_SELECTOR ;Move Mouse
FillMouseLeftClick ;Left-Click
FillKeyStroke VK_HOME ;HOME keystroke
mov edi, dRoomID ;n-1 VK_DOWN keystrokes
dec edi
.while !ZERO?
FillKeyStroke VK_DOWN ;DOWN keystroke
dec edi
.endw
FillKeyStroke VK_RETURN ;ENTER keystroke
;Select Rooms Tab
FillMousePosition ROOMS_TAB ;Move Mouse
FillMouseLeftClick ;Left-Click
;Select Selected Room Tab
FillMousePosition ROOM_SELECTED ;Move Mouse
FillMouseLeftClick ;Left-Click
;Set Room Temperature
FillMousePosition ROOM_TEMP ;Move Mouse
FillMouseLeftClick ;Left-Click
repeat 7 ;7 BACK-Keystrokes
FillKeyStroke VK_BACK ;BACK keystroke
endm
mov xdi, pRoomTempA
.while TRUE
movzx eax, BYTE ptr [xdi]
.break .if al == 0
.if al == "."
mov eax, VK_DECIMAL
.endif
FillKeyStroke ax ;Digit/point keystroke
inc xdi
.endw
;Send RETURN Keystroke
FillKeyStroke VK_RETURN ;ENTER keystroke
invoke SendInput, dInputCounter, addr SMI, sizeof(INPUT) ;Send all INPUTs at once
;Housekeeping
invoke SetForegroundWindow, hLastForeWnd
invoke SetCursorPos, LastCursorPos.x, LastCursorPos.y
invoke BlockInput, FALSE ;Restore input from Mouse & Keyboard
mov eax, TRUE
.else
DbgText "Window not Found"
.endif
ret
SetRoomTemp endp
Biterider
Nice. AutoIt in Assembly. :thumbsup: :cool: