Jump to content

Does anyone know how to convert a VI Server refnum to the underlying pointer?


Sparkette

Recommended Posts

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.)

Link to comment
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?

481687404_VirtualBox_Windows10_18_09_2020_14_56_01.png.4f810e1130ff3cd8662f0edb1e178379.png

Link to comment
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.

2020-09-19_2-30-51.jpg

Link to comment
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.

2020-09-19_2-30-51.jpg

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 :)

Link to comment

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.

Link to comment

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 by Rolf Kalbermatter
Link to comment
  • 2 weeks later...

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:

  1. 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.
  2. 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.
  3. 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 by dadreamer
tested this more extensively
  • Like 2
Link to comment
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?

Link to comment
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. :)

Link to comment
  • 3 months later...
  • 1 year later...
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?

Link to comment

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 by flarn2006
32-bit compatibility, error terminal fix
Link to comment
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 by flarn2006
Link to comment

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.

2022-02-01_16-26-12.jpg.cc4f10035f7b8a86a8a1cb61641655ea.jpg

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.

2022-02-01_16-34-54.jpg.3547a3655eeeb6de3625861085854b82.jpg

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.

Link to comment
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.

2022-02-01_16-26-12.jpg.cc4f10035f7b8a86a8a1cb61641655ea.jpg

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.

2022-02-01_16-34-54.jpg.3547a3655eeeb6de3625861085854b82.jpg

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.

 

Link to comment
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.

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

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