Andrew Pollack's Blog

Technology, Family, Entertainment, Politics, and Random Noise

Marshaling data in and out of managed vs.net code -- may have some value for Domino API work as well

By Andrew Pollack on 03/14/2006 at 12:19 PM EDT

Part of the work I've been doing requires that I make use of an external library in the form of a DLL. This article describes about 2/3 of the techniques needed for the process. If you like it, I'll write another one that deals with the other side of the coin --- "callbacks". That's a tricky bit of work in vs.Net.

vs.Net applications are like Java in that they run in their own runtime engine. In Java, its the JVM. In vs.Net its called the "CLR" (Common Language Runtime). One big disadvantage to the CLR is that you can't just easily pass data in and out of it. Its actually pretty complicated -- and in doing so you remove the benefits of the runtime environment. Normally, you don't worry about memory allocation at all. The CLR does that for you. When you're working with Unmanaged Memory, you have to allocate it to your variables and if you don't remember to free it when you're done, it creates a "memory leak". If all your memory leaks away the computer will forget how to work until you reboot.

The code that follows is a snippet which I find well illustrates about 2/3 of the issues surrounding these calls. There are three parts to look at. First, is the actual declaration that defines the function call and what data gets sent to and returned from the DLL itself. In this case, its a bit complicated. You pass in five pointers (memory locations) with room to store numeric values. The function will fill those locations with useful information, and will return to your function another integer value just indicating if it succeed or failed.

So, in the first part, we're telling the CLR that we want call a function called "iaxc_audio_devices_get" which is located in "iaxclient.dll". We want to pass it five numbers, and get back a number. We don't really tell the CLR what the numbers are for, just that they're numbers. In this case, each number is a POINTER to a memory slot -- like a cubbyhole -- which has enough room to hold pretty big number. What we know, because we read the documentation for the library, is that these numbers we get back when we go back and read the data at those locations will represent the following:

1. Another pointer, which is a memory location where we can find an array of records, each of which is an audio device description.
2. The total number of records held in the memory location described in number 1 above
3. Of the records pointed to by the value in number 1, which device is currently set to accept input
4. Of the records pointed to by the value in number 1, which device is currently set to accept output
5. Of the records pointed to by the value in number 1, which device is currently set to be used for RINGING noises

The second bit of code defines the structure of an audio device definition. Remember, we're going to get back a pointer to a group of these and a number telling us how many in the group. Notice that one part of the structure is itself a pointer to yet another place in memory where a text value is stored with the name of the device. That's because text strings vary in size, so you can't stack them neatly.

Finally, the third bit of code is the subroutine that allocates the 5 memory locations (cubbyholes), calls the library, and reads the data that got placed in the cubbyholes. Then it copies that information to variables we don't have to worry about and tells the system that it doesn't need the cubbyholes any more. Finally, it looks at the data and reads the text descriptions from the locations given for each, and prints the result.

' this is the function declaration for the call to the unmanaged dll itself
' note that the use of "_" allows me to wrap the lines so it isn't just
' just one long line of text.
Friend Declare Function iaxc_audio_devices_get Lib "iaxclient.dll" Alias _
"iaxc_audio_devices_get" (ByVal devlistptrInt As Integer, _
ByVal ndevsptrInt As Integer, ByVal InputptrInt As Integer, _
ByVal OutputptrInt As Integer, ByVal ringptrInt As Integer) As Integer

Structure iaxc_audio_device
' this is the structure definition - we will read an array of these
' from unmanaged memory by their address in memory
Public devnameptrint As Integer
Public caps As UInt32
Public devid As Integer
End Structure

Friend Sub getDevices()
' allocate pointer space in unmanaged memor
Dim devListPtr As IntPtr = Marshal.AllocHGlobal(4)
Dim devNoPtr As IntPtr = Marshal.AllocHGlobal(4)
Dim inputPtr As IntPtr = Marshal.AllocHGlobal(4)
Dim outputPtr As IntPtr = Marshal.AllocHGlobal(4)
Dim ringPtr As IntPtr = Marshal.AllocHGlobal(4)
' create managed memory value holders
Dim devlistPointer As IntPtr, devno As Integer, output As Integer, _
input As Integer, ring As Integer, result As Integer
' ********************************************************************
' Here is the actual API call to iaxclient.dll
' ********************************************************************
' fill the unmanaged locations with values
result = iaxc_audio_devices_get(devListPtr.ToInt32, devNoPtr.ToInt32, _
inputPtr.ToInt32, outputPtr.ToInt32, ringPtr.ToInt32)
' ********************************************************************
' ********************************************************************
' copy the unmanaged values to managed variables
devlistPointer = Marshal.ReadIntPtr(devListPtr, 0)
devno = Marshal.ReadInt32(devNoPtr, 0)
input = Marshal.ReadInt32(inputPtr, 0)
output = Marshal.ReadInt32(outputPtr, 0)
ring = Marshal.ReadInt32(ringPtr, 0)
' free the unmanaged memory to prevent leaks
Marshal.FreeHGlobal(devListPtr)
Marshal.FreeHGlobal(devNoPtr)
Marshal.FreeHGlobal(inputPtr)
Marshal.FreeHGlobal(outputPtr)
Marshal.FreeHGlobal(ringPtr)
' now try to read the array
Dim devices(devno - 1) As iaxc_audio_device
Dim devicenames(devno - 1) As String
Dim x As Integer
For x = 0 To devno - 1
' read raw bytes from unmanaged memory and convert them into a managed structure
devices(x) = CType(Marshal.PtrToStructure(devlistPointer, GetType(iaxc_audio_device)), iaxc_audio_device)
' One of the structure members is itself a pointer to a memory location with
' a character string, containing the text value we actually want.
' read that string from a memory location we get from the pointer
devicenames(x) = Marshal.PtrToStringAnsi(New IntPtr(devices(x).devnameptrint))
' now advance the memory location pointer forward by the size of one record
devlistPointer = IntPtr.op_Explicit(devlistPointer.ToInt32 + Marshal.SizeOf(devices(x)))
Next
' lets see what we ended up with
Debug.WriteLine("Audio in: " + devicenames(input))
Debug.WriteLine("Audio Out: " + devicenames(output))
Debug.WriteLine("Ring Sound: " + devicenames(ring))
End Sub


There are  - loading -  comments....

Bring it on!By Julian Robichaux on 03/14/2006 at 10:25 PM EDT
I'd like to see the rest of the technique, even if I'm not going to use it
right away. It's always good to see that kind of stuff and keep it in the back
of your mind.

Even more interesting to me would be examples of calling a .NET DLL from
LotusScript. I haven't had to venture down that road yet, but I know I will
someday.
I doubt you'll ever do quite that...By Andrew Pollack on 03/15/2006 at 12:41 AM EDT
..the idea of a ".net dll" isn't really something you'd ever call from outside
so far as I know. .NET applications compile to byte code that runs in the CLR
-- just like java classes compile to byte code that runs in the JVM. It would
be very unusual, I think, to call into a CLR unless I'm missing something.


Other Recent Stories...

  1. 03/26/2019Undestanding how OAUTH scopes will bring the concept of APPS to your Domino serverWhile a full description of OATH is way beyond what I can do in this quick blog entry, I wanted to talk a bit about how "SCOPES" interact with the already rich authorization model used by Domino. Thanks to the fantastic work by John Curtis and his team, the node.js integration with Domino is going to be getting a rich security model. What we know is that a user's authorizations will be respected through the node.js application to the Domino server -- including reader names, ACLs, Roles, and so on. The way ...... 
  2. 02/05/2019Toro Yard Equipment - Not really a premium brand as far as I am concernedDear Toro Customer Service, I arm writing about the following machine: Toro Power Max 1120 OXEModel:38654S/N:31000#### Specifically, bearing part #:63-3450 This is the part ($15 online / $25 at the local dealer) that caused me to raise my objections on-line. This piece of garbage is supposed to be a bearing. It carries the shaft which drives both stages of the auger. The shaft passes through the bearing (which is what bearings do) after the auger drive pulley as the shaft goes through the back (engine ...... 
  3. 10/08/2018Will you be at the NYC Launch Event for HCL Domino v10 -- Find me!Come find me in NYC on Wednesday at the Launch Event if you're there. I really do want to talk to ...... 
  4. 09/04/2018With two big projects on hold, I suddenly find myself very available for new short and long term projects.  
  5. 07/13/2018Who is HCL and why is it a good thing that they are now the ones behind Notes and Domino? 
  6. 03/21/2018Domino Apps on IOS is a Game Changer. Quit holding back. 
  7. 02/15/2018Andrew’s Proposed Gun Laws 
  8. 05/05/2016Is the growing social-sourced economy the modern back door into socialism? 
  9. 04/20/2016Want to be whitelisted? Here are some sensible rules for web site advertising 
  10. 12/30/2015Fantastic new series on Syfy called “The Expanse” – for people who love traditional science fiction 
Click here for more articles.....


pen icon Comment Entry
Subject
Your Name
Homepage
*Your Email
* Your email address is required, but not displayed.
 
Your thoughts....
 
Remember Me  

Please wait while your document is saved.