- Popular Post
Rob Calhoun
-
Posts
33 -
Joined
-
Last visited
-
Days Won
3
Content Type
Profiles
Forums
Downloads
Gallery
Posts posted by Rob Calhoun
-
-
I am extremely disappointed with it. The suspend-when-called bug introduced in the initial LV 2009 release is still not fixed in SP1. This bug was noted on LavaG many months ago (see this post) and submitted to NI before the SP1 beta started. I reported it again during the SP1 beta. Months pass, the release is out, and suspend-when-called is still completely broken. You still cannot change control values and it still corrupts the control data when the VI is executed, which means that you cannot run a suspended VI more than once without corrupting your data. It's a ghastly bug.
I am dumbfounded that a data loss issue like this was not considered a blocker for SP1's release.
Here is an example of the suspend-when-called bug corrupting data.
-
I know this is an ancient thread, but for posterity I wanted to note that in LV 8.2 and later, you can use the regular LabView "variant to data" function to convert ActiveX timestamps to LabView timestamps.
-
I am unsure how to set the Local IP there doesn't seem to be a way to do this, only a way to read it. This is going to be a problem...
You generally do not need to set an IP address when you create a server, just a port. The address input is there only so that you can force a machine with multiple IP addresses to listen on only a specific IP. The default is "listen on all IP addresses".
As others have said, there are good examples of how to use the TCP primitives. Basically you create a listener, wait on the listener for a connection, then service the connection. The one thing that is not very clear is that you do not need to create a listener more than once; one listener can handle an unlimited number of connected clients. Typically you pass a cluster with the TCP refnum and other data (e.g. "New Cnx") to a new re-entrant process that runs top-level so that the listener thread can go back to the wait-on-listener state.
The code below is simpler than that; rather than spawn off a server process, it just dumps a datetime message to whomever connected on port 27000 (via e.g. "telnet localhost 27000" and then hangs up the TCP connection. With this type of design you can only have one client connected at a time. Once done with the current client, it will go back to waiting on listener. To exit the program cleanly we use the close TCP function to close the listener, causing Wait On Listener to error out.
-Rob
-
Whoops, I had disabled asynchronous downloads while testing. With Async set to TRUE again, Timeout does work with WaitForResponse(). I'm using an I32.
-
"Timeout" seems to be ignored by WaitForResponse(), at least with all of the data types I can think of stuffing in there.
-
I encountered this bizarre and performance-destroying behavior yesterday so I thought I should write up some notes on it.
In our application we call various Microsoft components (Active Data Objects, WinHTTP, MSXML) to do tasks that aren't build-in to LabView (database connectivity, http and xpath queries, respectively.) We use the Automation (ActiveX) functions for this. When we expect to call these routines in parallel, their wrappers are set for re-entrant execution.
I was running a process that does a lot of downloading via WinHTTP in one thread while doing a lot of opening and closing of databases in another. I was getting extremely poor performance. A little debugging isolated the problem to a block on the Automation Open function (on an ADO object!) while WinHTTP was doing a synchronous download. Adding more parallel downloads makes the problem worse; I have no trouble firing off 5 WinHTTP downloads in parallel, but doing so almost completely lobotomizes LabView. Click the run button with five WinHTTP clones chomping away at big files and even the simplest routines (see two-plus-two.png) get completely stuck.
The solution is simple: enable asynchronous downloads. From the WinHttpRequest documentation.
"The main advantage to using WinHTTP asynchronously in script is that the Send method returns immediately. The request is prepared and sent by a worker thread. This enables your application to do other things while it is waiting for the response. "
We had set it to synchronous because a) it was the default and b) we were running it in a clone anyway and didn't really want the clone to do anything other than wait for the download to complete. What I did not realize is that when Microsoft says "[t]his enables your application to do other things while it is waiting for the response", they are not kidding! The WinHttpRequest.Send method apparently has deep ties into the depths of the Windows execution system and you REALLY cannot do other things while it is running.
The strangest part of the whole business is that while you can set up an ActiveX event to catch the completion notice, if you don't mind you VI (as opposed to your entire application) to get blocked, the easy way to do a download is to fire off the request with WinHttpRequest.Send (async) and then wait (synchronously) for it to complete or timeout using WinHttpRequest.WaitForResponse. WinHttpRequest.WaitForResponse blocks your VI but it doesn't destroy your world.
So in the end this had an easy solution. (And I was really sweating this last night!) This kind of issue, however, is why Jim and I would like to see a nice SSL-capable http client built in to LabView. (see Setting up SSL Web Services).
Here is the synchronous (blocking) code. DON'T DO THIS!
Here is the non-blocking) code. You can use an ActiveX event if you want to show a progress bar or something, but this will get the job done.
-Rob Calhoun
blocked!
blocking:
non-blocking:
-
I agree with the other posters on general good style for calling DLLs from LabView with non-simple types: allocate the memory in LabView, pass a pointer to the LV-allocated buffer to the DLL as an argument (usually along with a length) and allow the DLL to modify the buffer that was passed in. So a C function that converted a lower-case string to upper case might have prototype:
int ConvertToUpperCase (char *string, int length)
where the return value is used for error handling.
Some DLLs return a pointer to data in the return value. It's not ideal but sometimes you have to work with what your are given. There is no way to access this directly using the Call Library Function, but there is a workaround that is described in this post
http://forums.lavag.org/How-to-get-data-fr...aded#entry38166
which links to this example
http://zone.ni.com/devzone/cda/epd/p/id/3672
The "secret trick" (thanks, Rolf!) that you do not need to write your own DLL to do this; the LabView dev env and runtime export a "MoveBlock" function that you can use to copy data from an area of memory that is private to the DLL to an area of memory allocated by LabView. (Since the DLL is loaded by LabView, it isn't an access violation to READ the data, but chaos will result if LabView tries to MODIFY the data.) You return a pointer from your function and then use MoveBlock to copy that into an area of LV-allocated memory, which LabView can then copy/move/delete as it wishes. In the function above, you'd have to call MoveBlock multiple times, once for each pointer dereference required. (Yuck!!!) As others have pointed out, plenty can go wrong if the internal data changes while you are doing this (for example, it is device driver). In the example below, I throw a mutex around the calls to prevent me from inadvertently calling the library with the same instance in a different VI.
Something that isn't clear is what data type to return pointers. Lately I have been using the Call Library Function's "unsigned pointer-sized integer" to handle pointers and size_t integers. On my platform this always returns a UInt64. In fact the function I am calling works with size_t ints set to either "pointer sized" or Uint32s. This would not be the case if LabView were actually passing U32s or U64s at my request---any parameters following the first goof would be corrupted. LabView's documentation is pretty sparse on this, but my guess is that since wires size needs to be defined at compile time, the compiler always allocates 64 bits of storage for "pointer sized integers" on the diagram, but inside the call library function it passes either 32 or 64 bits as appropriate. I don't think this "pointer-sized integer" is foolproof because it requires LabView and the DLL to agree on what that is, but it seems safer than blindly assuming a U32.
If you have source code for the DLL, you can wrap it with your own code and define fixed-size types.
Running System Exec vi as Administrator in Win7
in Calling External Code
Posted
The UAC in Vista and later is designed to prevent even administrator accounts from doing "dangerous" things without user confirmation. Running as Administrator alone is not sufficient to avoid the prompt as Microsoft has tried very hard to ensure that the prompts cannot be worked around. (This is so that virus authors can't go that route.)
The "right" way to handle this is to ship a manifest that tells Windows that an application needs elevation. It will ask for it on launch. If there is no manifest, Windows tries to figure out which applications require elevation (for example, an installer named "setup.exe") and request elevation from the user on launch. It is very frequently wrong and this results in cascade of errors later on.
I agree with you that disabling UAC entirely on a machine is the wrong approach. I'm no fan of UAC, but it is the world Microsoft wants us to live in. None of them really get rid of the UAC prompt, they just get the user's permission at some more convenient point in the launch process. (I realize not all of these apply to your situation:)
While we are talking Windows 7, keep in mind that the Program Files directory is now called Program Files (x86) when 32-bit LV is running on a 64-bit versions of windows. So make sure to clean out those hard-coded paths!
-Rob