Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/17/2011 in all areas

  1. In a single word, "encapsulation." That's not a very helpful answer though... There were a couple things with the string/variant messages that I found difficult. First, changing the name of a message can be difficult or impossible. Since the message name is the only information immediately available I changed it often during development to be appropriately descriptive. Second, in a string/variant message the message name and the message data are inherently different elements. The message sending code can match any message name with any data type. This opens the door to runtime errors that may or may not be found during testing. By creating your own custom messages that derive from Message.lvclass, you have much more control over the both the message name and the message data. The message object is responsible for ensuring the message name and data match up correctly instead of the message sender. I typically create a 'Create MyMessage.vi' for each of my custom messages that accepts the necessary data types and does not have an input for message name. This greatly reduces the risk of message name/message data mismatches. Since any code that sends the message uses the creator it also means I have more confidence if I change a message name to improve code clarity--the message name is (usually) only used in two place, the creator method and the receiving loop. It's important to understand that messages that expose a Message Name input on the creator or inherit from RenameableMessage have inherently 'weaker' type safety. (All messages in the NativeTypes library inherit from RenameableMessage. Message and ErrorMessage do not inherit from RenameableMessage.) You're giving the responsibility of making sure the name and data match up correctly back to message sending code. In that respect they're not much different from string/variant messages (though the creator conpane inputs still give you data type information so you don't have to look it up.) You can create similar protection for string/variant messages by building creator vis for the various message types, but I've never seen anybody actually *do* it. For that matter, I don't think I've ever seen anybody even suggest doing it. There's not enough payoff for the extra effort of making a creator vi that just bundles a cluster. LVOOP *requires* a method to bundle the name and data into a message. For me, building robust code is much more natural (and easier) with the Message Library than with a string/variant messaging system. Not yet, and to be honest I haven't really thought about it. All my message classes have been of the "protected cluster" kind. It's an interesting idea though. For example, with the command pattern you could have Command.lvclass inherit from Message... In general I favor composition over inheritance, but I'll have to think about it for a while. Thanks. To be honest, currently LapDog isn't much of anything except an idea... a hope... a dream. <queue orchestral music> LapDog is intended to be a set of components to assist LVOOP programmers. Originally I envisioned small-ish base class libraries for things like Collections and Data Structures. I've since realized a flexible and robust messaging system is absolutely critical for managing larger projects. I'll still work on the other libraries, but I think this is more generally useful than collections or data structures so it took priority. Also, I use the Message Library far more than I use data structures or collections, so it's easier for me see flaws and make improvements.
    1 point
  2. Well if you find a different way to determine the length of a null terminated C string you are definitely a lot smarter than all the C cracks who have worked on the various standard C runtime libraries when implementing strlen(). MoveBlock() operates on a byte array only. There is no way it can determine the length of the source buffer at all. While it could be a typical C string it does not know about that. It's simply a char[] buffer, but char in C does not mean null terminated string at all, it's just the name for a byte sized integer. If you know that you have a null terminated string buffer you could do something like this instead: LStrHandle target = NULL; int len = StrLen(buffer); MgErr err = NumericArrayResize(uB, 1, (UHandle)&target, len); MoveBlock(buffer, LStrBuf(*target), len); LStrLen(*target) = len; This is as fast as it gets and I'm sure the XNode adds some complications to it, since it works for different parameter types too. Another LabVIEW manager call that does this more or less in one call would be: LStrHandle target = DSNewHdlClr(4); LStrPrintf(target, "%s", buffer); Since this incures an extra call to the memory manager function DSSetHandleSize() inside LStrPrintf() it is likely slower than the previous solution.
    1 point
  3. As ned has already explained quite clear you have to use LabVIEW memory manager functions if you want to hand data back to LabVIEW directly. The GetValueByPointer XNode is just a way to deal with native pointers, when you have no way or don't want to modify the DLL itself to deal with LabVIEW handles directly. What it does is copying the data in the pointer into a LabVIEW handle. And if you don't clean up that pointer yourself afterwards it will be leaked. Nothing LabVIEW can do about, since the DLL interface is simply a function interface with no defined conventions about how to allocate and manage memory across that boundery. DLL x could use a standard malloc function for that while DLL Y comes with its own memory manager implementation and LabVIEW has no way of knowing about this at all. Why LabVIEW uses handles? Because traditionally that was required on older platforms to have efficient variable sized memory structures (strings and arrays) and changing that now is no option at all. Even if it would use pointers the fact that the caller never can know what the callee used to create a particular memory block and vice versa, would still prevent fiddling with pointers created in the other component.
    1 point
  4. A Model-View-Controller architecture? An old-school solution is the examples outlined in Conway and Watts 'A Software Engineering Approach to LabVIEW'. If you go the the InformIT page for the book, you can download the examples. The Wigetometer Test System is based on parallel loops where the execution of the test is decoupled from the UI. http://www.informit.com/store/product.aspx?isbn=0130093653 The addition of event structures, queues and OOP makes certain things much easier. Apply your knowledge of these features to this old example.
    1 point
  5. In those examples, the data returned is always a pointer-sized integer, which is then dereferenced by a mysterious XNode call GetValueByPointer. The example provides what I assume is equivalent LabVIEW code for dereferencing a pointer using MoveBlock. Dereferencing the pointer this way copies the data from space allocated by the DLL into space allocated by LabVIEW. I'm guessing that in your case you are trying to return the structure/array directly by reference, allowing the call library node to handle the dereferencing. As a result, you're handing LabVIEW a block of memory that it didn't allocate, so it doesn't know how to manage it nor free it on exit. I'm not sure what happens to the memory allocated by the DLL in the examples; I'd guess this would be a memory leak if called repeatedly, and that the operating system would clean it up on exit, but that's mostly a guess.
    1 point
  6. Thanks for the kind words Felix. I showed your post to my wife and she said, "I like this Felix guy." I thought maybe it was because of the nice compliment. Silly me. It's because you have Johnny Depp as an avatar.
    1 point
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.