Jump to content

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


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 post
Share on other sites
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 post
Share on other sites
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 post
Share on other sites
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 post
Share on other sites

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 post
Share on other sites

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 post
Share on other sites
  • 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 1
Link to post
Share on other sites

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?

Link to post
Share on other sites
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 post
Share on other sites
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 post
Share on other sites

Join the conversation

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

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