Click here to Skip to main content
15,891,375 members
Articles / Programming Languages / Visual Basic

Marshal variable length array of structs from C to VB.NET

Rate me:
Please Sign up or sign in to vote.
4.67/5 (4 votes)
24 Jul 2011CPOL4 min read 32.7K   15   4
How to pass a variable length array of structs from C to VB.NET.

Introduction

This article presents an example of how to create a VB.NET program that retrieves data in the form of a variable length array of structs from a DLL file written in C. The challenge here is how to pass data between the safe world of managed code executed by the Common Language Runtime (CLR) and unmanaged code.

Background

Code which is developed using the .NET Framework is known as managed code. This code is directly executed by CLR with the help of managed code execution. Any code that is written in .NET Framework is managed code. Managed code uses CLR which in turns looks after your applications by managing memory, handling security, allowing cross-language debugging, and so on. Code which is developed outside the .NET Framework is known as unmanaged code. Applications that do not run under the control of the CLR are said to be unmanaged, and therefore don’t have the benefits of the CLR. I won’t get any deeper into the definitions of managed and unmanaged code since that is out of the scope for this article and there are plenty of sources for that on the internet. Just Google it :)

Marshalling

The solution for passing data between managed and unmanaged code is of course marshalling. What made the assignment a bit tricky was that some of the unmanaged functions returned an array of structs whose size I didn’t know when I was calling the function.

The Code

I will begin with the unmanaged DLL. Here is the struct declaration in C:

C++
typedef struct { 
    Char id1[10]; 
    Char id2[20];               
}unmanagedStruct;

Here is the declaration of the function:

C++
extern "C" __declspec(dllexport) unmanagedStruct* unmanagedFunction(int &size) 
{ 
    unmanagedStruct *outStruct = new
    unmanagedStruct[myStructSize]; 
 
    size = myStructSize; 
    //Do whatever your function is supposed to do
    return outStruct; 
}

As you can see, the function returns a pointer since what I need on the managed side is a pointer to the unmanaged memory I have allocated. The next thing to note is that I am taking the integer size as a reference call. This variable enables me to get the size of the array on the managed side. How the elements of the array are retrieved will be explained in detail when I present the managed code. Now I will just show the relevant parts of the unmanaged function. Of course, the function should do a lot more such as fill the array with values and so on, but that is out of the scope for this article. So as you can see, I am declaring my array of structs and allocating memory for it. Then I set the size variable to the size of the array so that the managed code will be able to know the size. Finally, I return the pointer to the caller of the function.

Now on the managed side, in Visual Studio, I start by declaring the struct I intent to use. Notice that I am using the MarshalAs attribute class to specify the length of my fields in the structure. These lengths have to be the same as the lengths declared in the unmanaged DLL.

VB
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ 
Public Structure managedStruct 
 
   <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=10)> _ 
   Public id1 As String  
 
   <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=20)> _ 
   Public id2 As String  
End Structure

I continue by declaring a DllImport to my unmanaged DLL and the function which I intend to use.

VB
<DllImport("myUnmanagedDll.dll")> _  
Public Shared Function unmanagedFunction(ByRef size As Integer) As IntPtr 
End Function

And finally, here comes the part where I call the unmanaged function from my managed code, retrieve the pointer to the unmanaged array of structs, and retrieve the values.

VB
Dim p1 As IntPtr  'My struct pointer
'pointer to be used to cleanup the unmanaged memory 
Dim cleanUpPtr as IntPtr
Dim numberOfResults As Integer 'Size of array from dll
Dim resultArray() As managedStruct
'The array where i will store the retrieved values
 
'Call the unmanaged function and get intpointer
p1 = unmanagedFunction(numberOfResults) 
'Set the pointer to be used for cleanup to point on the same memory block
cleanUpPtr = p1
 
ReDim resultArray(numberOfResults - 1) 'Resize my array  
 
Dim size As Integer = Marshal.SizeOf(GetType(managedStruct))
Dim start As Integer = (CType(p1, Integer) + _
(Marshal.SizeOf(GetType(managedStruct)) - size)) 
p1 = New IntPtr(start) 'Set the pointer at the first element of array 
Dim i As Integer = 0 
 
Do While (i < numberOfResults) 
    resultArray(i) = CType(Marshal.PtrToStructure(p1, _
                           GetType(managedStruct)), managedStruct)
 
    If (i < (count - 1)) The
        p1 = New IntPtr((CType(p1, Integer) + size)) 
    End If  
 
    i = (i + 1)
Loop

After the call to the unmanaged function, I have the number of posts I have retrieved in the array. In the variable called size, I store the size of every array element so I know how many bytes I have to increment to retrieve the next post. Then I proceed to set the pointer p1 to the first array element, and finally use Marshal.PtrToStructure to retrieve the values. Once I have retrieved an array element, I continue to set the pointer to the next element. This step is repeated until I have retrieved all the elements and now I have the entire unmanaged array in the managed memory.

Now as a last thing, remember to clean up the unmanaged memory. That’s why I created an extra pointer called cleanupPtr since I will loop over the array with the original pointer. cleanUpPtr is still pointing to the beginning of the unmanaged memory. The cleanup operation can be performed directly from managed memory by using the CoTaskMemFree() attribute or by using the delete[] operator in the unmanaged code.

Final Words

As a final word, I would like to answer the question I guess many of you would ask: Why do it in VB.NET, and the answer to that question is that was part of the requirement when I got the task. If it was up to me, I would have done it in C#. I am a C# guy.

History

  • 24 July, 2011: Fixed some copy-paste error in the code part of the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Sweden Sweden
have 5+ years of experience working as a software developer. My main area is the .NET platform and C# is my main language.
I am an experienced consultant and has worked both as an on-site consultant aswell as an in-house developer. Apart from developing software I have also been involved with training of end users, writing documentation, test and 3rd line support.

I have working with projects in several different industries such as Oil/Gas, Nuclear Power ,Telecoms, Defense and Life Science. Working in serveal different fields have given me broad technical experience
and understanding of the demands within the different fields. My work experience ranges from developing industrial automation systems ,realtime systems, traceability systems to web based SMS payment portals.

Most of my experience is on the .NET platform but I have also worked with C++ and Java. With databases I have worked mostly with Microsoft Sql server and Oracle but I also have good knowledge of open source databases such as MySql and MariaDB
Within Web development have worked mostly with the ASP.NET MVC architecture. I have worked mainly with backend development in C# but have also been working with frontend using Jquery, HTML5 and CSS. I have also been doing a project developing an Android app for a homeautomation system using Android Studio.

I have a great interest in learning new technologies and I am a fast learner. Javascript is a area of focus right now and technologies such as asynchronous serverside JavaScript(Nodejs), realtime web applications with websockets(socket.io) and peer2peer based videostreaming wirh webrtc are currently taking a lot of my sparetime.
Other areas of interest are php based cms systems such as Wordpress and being a Google fan software development on the Android platform is a must. Currently i am exploring the Android Wear SDK. Love that Android Studio finally came.

Comments and Discussions

 
Generalinteresting Pin
BillW3314-Jun-11 4:15
professionalBillW3314-Jun-11 4:15 
GeneralJust few comments Pin
Selvin17-May-11 21:05
Selvin17-May-11 21:05 
GeneralRe: Just few comments Pin
alanjmcf22-May-11 23:38
alanjmcf22-May-11 23:38 
GeneralRe: Just few comments [modified] Pin
Robert Josefson23-May-11 7:43
Robert Josefson23-May-11 7:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.