Sparkette Posted September 18, 2020 Report Share Posted September 18, 2020 That is, to get the address that would be shown in the Heap Peek window. I doubt there's an official way to do it, but is anyone aware of a private method or named internal function to do it? I'm sure I could locate the reference table in memory and look it up there, but I'm not sure if there's any way to obtain the address for that in as much of a version-agnostic way as possible. (And yes, I know the internal structures at those addresses are subject to change regardless. But ideally I'd like some way to do it that won't break just because a minor unrelated patch happened to place something at a different memory address.) Quote Link to comment
dadreamer Posted September 18, 2020 Report Share Posted September 18, 2020 Do you need VI Data Space pointer? If yes, then you could use GetDSFromVIRef internal function - check my samples with ReadDCOTransferData / WriteDCOTransferData calls. That function is available in LabVIEW starting from 2009 version. Quote Link to comment
Sparkette Posted September 18, 2020 Author Report Share Posted September 18, 2020 14 minutes ago, dadreamer said: Do you need VI Data Space pointer? If yes, then you could use GetDSFromVIRef internal function - check my samples with ReadDCOTransferData / WriteDCOTransferData calls. That function is available in LabVIEW starting from 2009 version. That's very interesting, thanks! However, I tried it and it doesn't give me the pointer I needed. Unless I'm doing something wrong? Quote Link to comment
dadreamer Posted September 18, 2020 Report Share Posted September 18, 2020 2 hours ago, flarn2006 said: However, I tried it and it doesn't give me the pointer I needed. Unless I'm doing something wrong? This gives you a pointer to VI Data Space, not to the object's own space. Well, I see what you want to obtain, so I recheck later, whether it's possible to retrieve a pointer to the object itself. Quote Link to comment
Sparkette Posted September 19, 2020 Author Report Share Posted September 19, 2020 3 hours ago, dadreamer said: This gives you a pointer to VI Data Space, not to the object's own space. Well, I see what you want to obtain, so I recheck later, whether it's possible to retrieve a pointer to the object itself. Thanks! I'll be sure to post here if I find a way too. Might be able to do some cool stuff with the VI data space as well, once I read up on what that's about. Cool to see more people interested in exploring LabVIEW's attic Quote Link to comment
dadreamer Posted September 19, 2020 Report Share Posted September 19, 2020 I'm still investigating things, but now I start to think that it's kinda complicated task. I've found no easy-to-use function in LabVIEW internals to get that pointer. And there's another difficulty - the refnum should be matched with the object, it relates to. I see no any refnum info in Heap Peek's object (and its DCO) properties. There's UID in the very first string, so that potentially could be used to identify the object needed. In that case the list of all VI objects should be retrieved (from OH or DS Heap, I guess) and each object should be analyzed to know, if its UID matches our one. Somewhat straightforward approach, but it's the best I could come up with. Maybe someone knows a better solution... As to refnums, there's MCGetCookieInfo and its wrapper named BaseCookieJar::GetCookieInfo, but I don't know a reliable way to find out a Cookie Jar for concrete LabVIEW instance. And even having that I'm unsure whether that function returns the necessary data. Quote Link to comment
Rolf Kalbermatter Posted September 19, 2020 Report Share Posted September 19, 2020 (edited) Trying to get at the data pointer of control objects, while maybe possible wouldn't be very helpful since the actual layout, very much like for the VI dataspace pointer has and will change with LabVIEW versions very frequently. Nothing in LabVIEW is supposed to interface to these data spaces directly other than the actual LabVIEW runtime and therefore there never has been nor is nowadays any attempt to keep those data structures consistent across versions. If it suits the actual implementation, the structures can be simply reordered and all the code that interfaces to external entities including saving and loading those heaps translates automatically to and from standardized (that includes changing multibyte data elements to Big Endian format) data. The MagicCookieJars used to be simply global variables but got moved into the Application Context data space with LabVIEW 8.0. I'm not aware of any function to access those CookieJar pointers. They did not exist prior to LabVIEW 8 as any code referencing a specific CookieJar was accessing them directly by its global address and I suppose there isn't any public interface to access any of them since the only code supposedly accessing them sits inside the LabVIEW runtime. The only external functions accessing such refnums either use well known, undocumented manager APIs to access objects (IMAQ Vision control) or use UserData refnums based on the object manager (has nothing to do with LabVIEW classes but rather with refnums) that reference their cookie-jar indirectly through the object class name. MCGetCookieInfo() requires a cookie jar, the actual refnum and returns the associated data space for that refnum. What that data space means can be very different for different refnums. For some it's simply a pointer to a more complex data structure that is allocated and deallocated by whatever code implements the actual refnum related functionality. For others it is the data structure itself. What it means is defined when creating the cookie jar, as the actual function to do so takes a parameter that specifies how many bytes each refnum needs for its own data storage. For interfaces managing their own data structures it simply uses sizeof(MyDataStructPtr) or more generally sizeof(void*) for this parameter, for interfaces that use the MagicCookie store for their entire refnum related data structure, they rather use sizeof(MyDataStruct) here. These interfaces all assume that the code that creates the CookieJar and uses those refnums is all the same code and there is no general need to let other code peek into this, so there is no public way to access the CookieJar. In fact if you write your own library managing your own refnums, you would need to store that cookie jar somewhere in your own code. That is unless you use object manager refnums. In that case things get even more complicated. Edited September 19, 2020 by Rolf Kalbermatter Quote Link to comment
Sparkette Posted September 20, 2020 Author Report Share Posted September 20, 2020 Okay, well thank you very much regardless! I seriously appreciate the effort you both put in! Quote Link to comment
dadreamer Posted September 29, 2020 Report Share Posted September 29, 2020 (edited) It took a while to code it, but here it is finally. 😉 I have found a way to retrieve the object's pointer soon after the last post in this thread, but had to debug and test everything. Refnum_to_Pointer.rar How it works: As we don't have any public or private API to obtain Base Cookie Jar (BCJ) pointer (that is a LabVIEW global variable), the only way is to examine some function, which uses it, find the place with this global and save the pointer. Actually, this is how we're getting our BCJ. To clarify, it's for Object References only, not for any other references out there. After we've got BCJ, we call MCGetCookieInfo and get the information, associated with that refnum. As far as I understand, CookieInfo appears to be a C++ class with a few methods and properties (not just an ordinary struct). One of the methods is able to extract the object's pointer from VI DS. Further we call that unnamed method, using the hard-coded offset of 0xC (for 32 bit) / 0x18 (for 64 bit) and it returns the necessary pointer. The method should be called using __thiscall convention, that is why I'm using the technique described here. I decided not to write a wrapper library, so that everyone everywhere could easily browse the code and alter it, when needed. Currently tested on all LabVIEW versions from 2009 to 2020 (both 32- and 64-bit, both IDE and RTE). It won't work on anything earlier than LV 2009, because ExtFuncCBWrapper is absent there. Also no Linux or macOS at the moment, sorry. Oh, and it may become broken in the future LV releases. Or may not, nobody knows yet. 🙂 Edited October 30, 2020 by dadreamer tested this more extensively 2 Quote Link to comment
Sparkette Posted September 29, 2020 Author Report Share Posted September 29, 2020 Wow, awesome—I would never have thought anyone would go to so much effort for this! Thank you! I do have one question: what is it that's stopping it from working on Linux/Mac? Quote Link to comment
dadreamer Posted September 29, 2020 Report Share Posted September 29, 2020 6 minutes ago, flarn2006 said: I do have one question: what is it that's stopping it from working on Linux/Mac? A few WinAPI calls are used there. Besides of that I suppose that assembly blocks should be altered and the hard-coded offsets should be checked as well. It all needs a time to debug on those platforms. I have VMs for Linux/macOS on one machine only, so... Do you really need this on Linux or macOS? Quote Link to comment
Sparkette Posted September 30, 2020 Author Report Share Posted September 30, 2020 6 hours ago, dadreamer said: A few WinAPI calls are used there. Besides of that I suppose that assembly blocks should be altered and the hard-coded offsets should be checked as well. It all needs a time to debug on those platforms. I have VMs for Linux/macOS on one machine only, so... Do you really need this on Linux or macOS? It would be nice to have it cross-platform, but it's hard to bring myself to ask when you've done so much already! Don't feel like you have to worry about it. Quote Link to comment
dadreamer Posted January 5, 2021 Report Share Posted January 5, 2021 On 9/30/2020 at 5:17 AM, flarn2006 said: It would be nice to have it cross-platform Finally here it is. Refnum_to_Pointer-Linux.zip Refnum_to_Pointer-MacOS.zip Tested in LV 2020 on Ubuntu 20.10 and macOS Big Sur. It's assumed to work in 64-bit editions of LabVIEW only. 2 Quote Link to comment
Sparkette Posted January 30, 2022 Author Report Share Posted January 30, 2022 On 1/5/2021 at 9:17 AM, dadreamer said: Finally here it is. Refnum_to_Pointer-Linux.zip 41.9 kB · 1 download Refnum_to_Pointer-MacOS.zip 37.29 kB · 1 download Tested in LV 2020 on Ubuntu 20.10 and macOS Big Sur. It's assumed to work in 64-bit editions of LabVIEW only. Forgot about this! Just gave it a try, and I can confirm it works on LabVIEW 2021 on Arch Linux. At least as far as I can tell from my initial test. Would this work with Conditional Disable Structures so a single version can work in every OS? Quote Link to comment
dadreamer Posted January 30, 2022 Report Share Posted January 30, 2022 4 hours ago, flarn2006 said: Would this work with Conditional Disable Structures so a single version can work in every OS? Sure, why not? I was just too lazy to wrap those three VIs into one. 🙂 Quote Link to comment
Sparkette Posted January 30, 2022 Author Report Share Posted January 30, 2022 (edited) Here's a simple VI I made that does the opposite. This one should be cross-platform, though I've only tested it on Linux. I enabled maximum error checking on the MoveBlock CLFN, but I've found it can still crash LabVIEW if the pointer is invalid, so keep that in mind. Pointer to Refnum.vi Edited January 30, 2022 by flarn2006 32-bit compatibility, error terminal fix Quote Link to comment
dadreamer Posted January 30, 2022 Report Share Posted January 30, 2022 For 32-bit system you should add 8 bytes to the pointer instead of 16 to read out the UID. Check my test sample from here. Anyway it mostly matters for Windows, as both Linux and macOS are 64-bit nowadays. Quote Link to comment
Sparkette Posted January 30, 2022 Author Report Share Posted January 30, 2022 (edited) 1 hour ago, dadreamer said: For 32-bit system you should add 8 bytes to the pointer instead of 16 to read out the UID. Check my test sample from here. Anyway it mostly matters for Windows, as both Linux and macOS are 64-bit nowadays. Thanks; I'll update it when I get the chance. EDIT: Done. I also wired the error in/error out terminals, since I apparently forgot to do that before. Edited January 30, 2022 by flarn2006 Quote Link to comment
dadreamer Posted February 1, 2022 Report Share Posted February 1, 2022 Also to note for your VI. 1. Looks like UID to GObject Reference.vi is giving away a duplicate reference instead of the original one. Hence it should be closed explicitly with Close Reference after the work with it is done. 2. UID to GObject Reference.vi is not working in RTE. The Context Help for it has the related remark and even though the underlying UidToObjRef function is present in lvrt.dll, it does nothing. So, for RTE another way should be found. 3. Icon picture of Pointer to Refnum.vi doesn't reflect, that reference, not pointer, is outputted. BCJ is not used here as well. Maybe, something like " @ # " should fit more or less ok. Quote Link to comment
Sparkette Posted February 2, 2022 Author Report Share Posted February 2, 2022 12 hours ago, dadreamer said: Also to note for your VI. 1. Looks like UID to GObject Reference.vi is giving away a duplicate reference instead of the original one. Hence it should be closed explicitly with Close Reference after the work with it is done. 2. UID to GObject Reference.vi is not working in RTE. The Context Help for it has the related remark and even though the underlying UidToObjRef function is present in lvrt.dll, it does nothing. So, for RTE another way should be found. 3. Icon picture of Pointer to Refnum.vi doesn't reflect, that reference, not pointer, is outputted. BCJ is not used here as well. Maybe, something like " @ # " should fit more or less ok. 1. I thought references to GObjects didn't need to be closed. 2. I'm not concerned about RTE; my interest is for use alongside VI scripting, e.g. for doing low-level editing operations in a shortcut menu plugin. 3. Noted, thanks. I just copied your icon and didn't really consider what it meant.  Quote Link to comment
dadreamer Posted February 2, 2022 Report Share Posted February 2, 2022 5 hours ago, flarn2006 said: I thought references to GObjects didn't need to be closed. Well, this was discussed a lot here and on NI forums. The link there is invalid, the new one is Closing References in LabVIEW There's a paragraph about implicit references (current app, current VI, controls/indicators on the panel): Quote Although you should usually close references when you no longer need them, you can leave implicit references and references returned in the reference out terminal of unwired property and invoke nodes open, shown below, because a Close Reference function does not actually close these references or remove the target objects from memory. All the other references should be closed with Close Reference node as a good manner rule. Of course, you may leave everything opened and LabVIEW disposes/closes it on the VI/project unload or on the app exit. But it's gonna eat up some extra resources in the system and slightly slow down your program. Or you may always close everything and don't care about the ref types. 🙂 On 6/2/2015 at 7:47 PM, Rolf Kalbermatter said: This is documented and some people like to go to great lengths to make sure to always know exactly which references need to be closed and which not, in order to not use the Close Reference node unneccessarily but my personal opinion is that this is a pretty useless case of spending your time and energy and simply always using the Close Reference node anyways is the most quick and simple solution.  5 hours ago, flarn2006 said: I'm not concerned about RTE Just a note for another guys out there, who might use that VI. 1 Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.