ADVANCED: How To Call The Mac OS Directly From LabVIEW Part VII: Putting It All Together
See Part I of this series for the obligatory warning about using the Call Library Function Node.
Now let's take a look at some advanced techniques for handling some very complicated structures in calls. Take a look at vi.lib/Platform/FileManager.llb/PBGetCatInfo.vi. Discussing how PBGetCatInfoSync (Apple's Documentation) is far beyond the scope of this post. Let's just say that it is a kitchen-sink-included type function. We'll just look at some of the techniques used to make this call more manageable.
First off, because of the complexity of the structure (a union that contains two structs and each contain structs, arrays pointers, etc.) I decided to just treat the whole block as an array of bytes. We create the aray of bytes of the correct size with the Initialize Array primitive (Programming -> Array). There are a few parameters that need to be set up first: ioName (PStrPtr to a 32 character buffer), ioFDirIndex (I16), ioVRefNum (I16) and ioDirID/ioDrDirID (I32). Since these are inputs, we need to set those spots in the struct to the input data. So we convert them to byte arrays (U8[]) and then replace the Replace Array Subset (Programming -> Array) to set them. This is where finding the offsets of each element of a struct come in handy. Notice that for ioName, we call NewPtr and BlockMove to create a buffer and fill it in with whatever input they gave us. Then we convert that pointer into an array of bytes and put it into the buffer.
We then make the call to PBGetCatInfoSync. We do the traditional error handling with the return value. We take the array returned and pull out the pointer so we can call DisposePtr.
Now comes the fun part, getting all the data out. Since this structure has so many values to get out, I found it easier to group them by the data type and loop over an array of indexes (here again its helpful to pre-calculate the offset of each struct member) and do the conversion to that type. So you can see that we have OSType, 8-bit, 16-bit and 32-bit values we pull out. We also pull the string out of the PStr we allocated (before we disposed of it) and create an FSSpec from the parameters and the string.
Since it is a union, the data at certain offsets can be interpreted in different ways. So we return two different clusters, one for File and one for Directory (and a boolean saying which to look at). We grab the values for each and populate the output.
While at first glance this seems like a very complicated VI, it is actually not all that bad, there is just a lot of data to look at.
Well, that's it. With all of this, you can call the OS (specifically Carbon) and do all sorts of wonderful things.
Now let's take a look at some advanced techniques for handling some very complicated structures in calls. Take a look at vi.lib/Platform/FileManager.llb/PBGetCatInfo.vi. Discussing how PBGetCatInfoSync (Apple's Documentation) is far beyond the scope of this post. Let's just say that it is a kitchen-sink-included type function. We'll just look at some of the techniques used to make this call more manageable.
First off, because of the complexity of the structure (a union that contains two structs and each contain structs, arrays pointers, etc.) I decided to just treat the whole block as an array of bytes. We create the aray of bytes of the correct size with the Initialize Array primitive (Programming -> Array). There are a few parameters that need to be set up first: ioName (PStrPtr to a 32 character buffer), ioFDirIndex (I16), ioVRefNum (I16) and ioDirID/ioDrDirID (I32). Since these are inputs, we need to set those spots in the struct to the input data. So we convert them to byte arrays (U8[]) and then replace the Replace Array Subset (Programming -> Array) to set them. This is where finding the offsets of each element of a struct come in handy. Notice that for ioName, we call NewPtr and BlockMove to create a buffer and fill it in with whatever input they gave us. Then we convert that pointer into an array of bytes and put it into the buffer.
We then make the call to PBGetCatInfoSync. We do the traditional error handling with the return value. We take the array returned and pull out the pointer so we can call DisposePtr.
Now comes the fun part, getting all the data out. Since this structure has so many values to get out, I found it easier to group them by the data type and loop over an array of indexes (here again its helpful to pre-calculate the offset of each struct member) and do the conversion to that type. So you can see that we have OSType, 8-bit, 16-bit and 32-bit values we pull out. We also pull the string out of the PStr we allocated (before we disposed of it) and create an FSSpec from the parameters and the string.
Since it is a union, the data at certain offsets can be interpreted in different ways. So we return two different clusters, one for File and one for Directory (and a boolean saying which to look at). We grab the values for each and populate the output.
While at first glance this seems like a very complicated VI, it is actually not all that bad, there is just a lot of data to look at.
Well, that's it. With all of this, you can call the OS (specifically Carbon) and do all sorts of wonderful things.
6 Comments:
Hi Marc, I'm french LabVIEW developper and I read carrefully your blog.
One question : there is a way to use cocoa framework in LabVIEW like .NET on windows ?
Thank you for the interesting informations delivered here :) and sorry for my poor english :(
That is a very good question. If you would like to take advantage of some routines in Cocoa, you can write a Cocoa Framework and export C functions from it that call the Cocoa classes. You can then call the framework from a Call Library Function Node primitive (Functions Palette -> Connectivity -> Libraries & Executables). Double click on it and select your framework, and then type in your function name. Then set up the parameters and you can now call your code.
If you want to call LabVIEW code from a Cocoa application, and your have LabVIEW Pro, you can build a Shared Library (framework) out of a set of VIs. You can then call that framework from a Cocoa application. I have heard reports of some strange interactions between Cocoa and the LabVIEW Runtime engine, so this method may not be ideal.
We do not have a clean method of intermixing Cocoa and LabVIEW code at this point. If you have any suggestions on some directions for us to investigate, we would love to hear them.
By the way, your English is much better than my French.
I'll try your solution as soon as possible and I wait impatiently other interesting post on your blog.
>By the way, your English is much better than my French.
:)
Hi Marc, i'm a friend and colleague of odjau (and i'm about to switch :D). I'll have a suggestion about your posts. Could you put some pictures of diagram when you explain your techniques ? It's difficult for me to see what you mean sometimes.
By the way, I learn lot of thing with your blog. It's very exciting to learn how to merge the 2 worlds (MacOSX & LabVIEW).
Thank you adnan, and welcome to the Mac World.
I understand that without accompanying images it makes it difficult to follow the topics. I am changing my posting dates to once a month, so I can spend time developing images and finding the best way to get the point across.
Thank you for the feedback.
Thnak you marc! Much much better!
Post a Comment
<< Home