I have two VIs. The first VI (AsynchronousCall.vi) performs an "asynchronous call." (see in the following picture)
The following VI (Test.vi) is started by the asynchronous call. (see in the following picture)
The first VI only iterates over an array and starts the Test.vi. An element from the array is passed. This element should then be used in Test.vi. However, the first entry from the array is not passed correctly after the first call.
It follows that my asynchronous program does not receive the correct input data.
Important: In order to recreate the Senario, the front panel of Test.vi can be opened first after the asynchronous call. Because when it's open, it works as intended!
The target/actual comparison is in the following list:
Target value
Asynchronous program should have "Test_0" as input parameter.
Asynchronous program should have "Test_1" as input parameter.
Asynchronous program should have "Test_2" as input parameter.
Asynchronous program should have "Test_3" as input parameter.
Actual value
Asynchronous program is "" (empty string) as input parameter.
Asynchronous program is "Test_1" as input parameter.
Asynchronous program is "Test_2" as input parameter.
Asynchronous program is "Test_3" as input parameter.
How can it be avoided that the string is empty the first time it is called?
The 32-bit version of LabView 2015 is used, but this Senerio also occurs with newer versions (32-Bit LabVIEW 2019)
When you call a VI asynchronously with the Front Panel closed, LabVIEW does not appear to update the values displayed in the controls - this makes sense from a resource perspective as why paint an update to a control that no one can see?
If you were to perform an operation on the passed value in your test VI - such as writing it to a file or some shared queue you should be able to verify that the correct value is indeed passed, just not displayed in control on the front panel. The one button dialog can also be used for debugging this but it might block the open VI reference call in the launcher VI and thus cause your launcher loop to stall. See this discussion on LAVA forums about the root loop and the built-in dialog windows.
Related
I'm writing a VBS program where there is a while loop, but it's not easily breakable because it's not seen in the task manager easily (Not enough time to find it in the background processes because of the program). So, my solution was to make a simple input box that is always open which allows you to break the loop by typing Q. But, I can't find a way to allow the code in front of the input box code to run without having an input in the input box (Yes, No, Cancel). Any help? I'm new to VBS.
I have a problem with a task in LabView that I thought would be simple and pretty standard, but I am failing to acomplish it nonetheless.
The task: I have a measurement VI that aquires data in a loop. This may take a while, so I want to show the incomplete dataset to the user "as it grows". This should be done in an extra window so I want (need?) to use a SubVI. I want this SubVI's front panel to open at the beginning of the measurement and close at the end.
I put it in the measurement loop, so it gets called after each new datapoint is taken and can display the updated dataset. I set it to "show front panel when called", so it opens at the beginning of the measurement (first iteration of the loop), just as I want it to. But it doesn't close. If I check "Close afterwards if originally closed" it closes after each iteration of the loop, which is very annoying.
Also I tried calling FP.Open, FP.Run and FP.Close with an Invoke node but then I have no idea how to actually call the SubVI in the measurement loop and feed data to it.
Is there a general misconception in my approach? Or is there an obvious solution I failed to spot?
It sounds as if you have the SubVI displaying the data you want and it's just closing the front panel at the right time that you're stuck on. In that case the simplest way to do it is to keep the VI in the measurement loop, with the Show Front Panel When Called setting checked, and just use the FP.Close method to close the front panel when the loop is finished:
This implies that you're passing all of your acquired data to the subVI every time round the loop; that's not a problem if the size of the data is small, but a more scalable approach would be a producer/consumer pattern using a queue as Joe suggests. To do this:
Create the queue in your top level VI and pass the reference in to your measurement loop
Also pass the queue reference to your subVI, which sits outside your measurement loop
Your subVI contains the consumer loop which waits for data on the queue and updates the subVI's display with it
Don't set the subVI to show its front panel when called; use the FP.Open and FP.Close methods on it in your top level VI to open and close its front panel when needed.
You'll need to give the subVI some way of knowing when to exit when your top level VI is finished; a convenient way of doing this is to force-destroy the queue in the top level VI which will cause the Dequeue Element in the subVI to exit with an error.
Another option would be to keep your subVI in the measurement loop, pass it only the new data each time round the loop, but give it a 'memory' using an uninitialized shift register in which it accumulates the acquired data for display. Search the LabVIEW help for functional global variable for more detail on this approach. Again, use the open/close methods from your top level VI to show or hide the front panel.
Both approaches are workable, good for small project, not ideal for a larger/complicated setup where more precise control over what displayed data is required.
With the first approach you would have to find a reference to the open VI somehow, to manipulate with its front panel state by reference. Say, global variable of VI reference type will work.
With the second approach, what you are missing to call the vi with all the parameters is Call by reference node
For a more controllable approach, I would start the subVI on the start of the program (FP closed) and then communicate panel open/close and data update by firing custom user events to the subVI events structure.
If you use the Producer/Consumer pattern, you can use a queue to send the data as it arrives to another VI.
I have a windows forms application consisting of a single form which parses a large body of text upon clicking a few buttons.
There is a huge chunk of code which parses through every node of an XML file, typically around 5000 nodes containing 20-ish child nodes, and those have even more children, and so on and so forth, just to create an image of the file's size.
While iterating through the code, as in when the data is being parsed, if I press the minimize button, it won't minimize but goes into the "not responding" state. My guess is that the minimize function can't be processed while the data is being parsed.
Is there a way to set an interrupt to the minimize/maximize/close buttons, or set priority to them, or any other solution to enable smooth minimisation of the form?
Thanks in advance
Sorry to add almost the same answer as Stephan, but waited 10 hours for him to remove the DoEvents thing.
Data gathering or parsing should be handled in another Thread. The simpliest way is to use a BackgroundWorker, and implementing at least two event handlers :
BGWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
' Move your parsing code here
' use local variables whenever possible
' do the appropriate changes
' and
BGWorker_RunWorkerCompleted( _
ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
' tells your Main thread that it can use the resuls
Note :
You must be careful not to manipulate any user-interface objects
in your DoWork event handler. Instead, communicate to the user
interface through the ProgressChanged and RunWorkerCompleted
events.
And I would add :
Everything your BGW needs in its DoWork should remain untouched (*) by any other code. The DoWork() can access anything in your main thread (ex : manipulating a class instance of FileContent, calling a Function, reading a static variable...) You shouldn't take that lightly ! This could produce unexpected behaviours due to interference like multiple Workers, states changes or User inputs.
User inputs interfering with the parsing process should be handled : use the .RunWorkerCompleted(..) to capture when your main thread can safely (let user) access and manipulate datas, change states, etc.
(*) Best move is to make everything required by your BGW as a copy of the actual values at the beginning of the work. If you have a very long task to do, and states changes could occur in the meantime (ex : filesystem hierachy + file deletion - date changing while running a code that orders results by time...) you should :
either think again, whether all the required tools are available in your code to properly complete the task (best case)
either carefully handle the .Error Property of the RunWorkerCompletedEventArgs parameter (then fix the error, and try again..)
either validate your data integrity prior to use them (worst scenario)
EDIT : BGW is not the only way. Have a look at Threads and Threading while following Managed Threading Best Practices advices.
Since you are parsing your XML in your main thread, the GUI can't update until the parsing is finish. The best option is to use the BackgroundWorker. It will start an other thread that permit you to execute the parsing of your file while leaving the GUI responsive to the user input.
I am looking for a way to click on a button 'open file'.
I wrote a excel-VBA macro that connects with SAP module. What it should do is to add a file as an attachment in SAP. As a result I get pop-up window, just a standard windows open file window to get the file name and open file button.
My question is how to automatically insert a file name (always known) and click on that open file button?
I tried sendkeys from within excel-VBA, but it turns out that the once the open file window pops up the whole Sub routine stops.
I know I need Winapi to do this.
You probably need to do a DoEvents to allow the keys to be processed by SAP.
Quoting from VBA help:
DoEvents Function
Yields execution so that the operating system can process other
events.
Syntax
DoEvents( )
Remarks
The DoEvents function returns an Integer representing the number of
open forms in stand-alone versions of Visual Basic, such as Visual
Basic, Professional Edition. DoEvents returns zero in all other
applications.
DoEvents passes control to the operating system. Control is returned
after the operating system has finished processing the events in its
queue and all keys in the SendKeys queue have been sent.
DoEvents is most useful for simple things like allowing a user to
cancel a process after it has started, for example a search for a
file. For long-running processes, yielding the processor is better
accomplished by using a Timer or delegating the task to an ActiveX EXE
component.. In the latter case, the task can continue completely
independent of your application, and the operating system takes case
of multitasking and time slicing.
Caution Any time you temporarily yield the processor within an event
procedure, make sure the procedure is not executed again from a
different part of your code before the first call returns; this could
cause unpredictable results. In addition, do not use DoEvents if other
applications could possibly interact with your procedure in unforeseen
ways during the time you have yielded control.
I wrote a VB.NET Windows Forms app that requests a string from an out-of-process COM object every time the activate event fires. My form has two tabs, so I need to programmatically flip to the correct tab every time my window gains focus. Works fine, until...
By chance, someone ran a vbscript (yes, script, not exe) that contains:
Set shell = CreateObject("WScript.Shell")
shell.AppActivate("Window Title That Matches My App")
This script consistently crashes my app. Usually so badly that the Exception dialog usually can't paint itself. I have to kill it from task manager. Sometimes the Exception is readable. (I also confirmed the exception by attaching to the running exe with Visual Studio). It's: "System.Runtime.InteropServices.COMException (0x8001010D): An outgoing call cannot be made since the application is dispatching an input-synchronous call."
What's really messing with my mind is that my app has multiple instance detection using a mutex, and if an existing instance is running, my own code (compiled) uses VB.NET's own AppActivate keyword, and this does NOT crash my app. It activates the running instance and exits the redundant instance as expected.
The problem seems solely to be triggered by cscript/wscript's AppActivate. I wrote a 3-liner .vbs to confirm this. It's repeatable.
Is there a way to trap or avoid this in my compiled app?
It's not clear to me WHY this approach actually fixes the problem, but it DOES work:
Add a timer to the form.
Move all the _Activated code to the timer's _Tick event.
Make the _Activated event start the timer.
Make the _Tick event stop the timer then perform the COM stuff.