Buffers Sample

This sample demonstrates how to pass strings as In/Out parameters to unmanaged functions that expect a string (LPSTR) as a function parameter. Further, it shows how to use a string returned from an unmanaged method in the special case where the caller is not supposed to free memory allocated for the string. The Microsoft .NET Framework SDK includes the complete Visual Basic .NET and C# versions of this sample in Samples\Technologies\Interop\Platform-Invoke.

The Buffers sample uses the following unmanaged functions, shown with their original function declarations:

  • GetSystemDirectory exported from Kernel32.dll.

    UINT GetSystemDirectory(LPTSTR lpBuffer, UINT uSize);
    
  • GetCommandLine exported from Kernel32.dll.

    LPTSTR GetCommandLine();
    

In this sample, the LibWrap class contains a managed prototype for each unmanaged function called by the App class. The CharSet field is set so that platform invoke can choose between ANSI and Unicode formats at run time, based on the target platform.

The GetSystemDirectory prototype method substitutes a System.Text.StringBuilder buffer for the unmanaged LPSTR type. The buffer size remains fixed. To accommodate the requirements of the original function, GetSystemDirectory passes the buffer size variable as the second argument. A StringBuilder buffer, rather than a string, replaces the LPTSTR type in the declaration. Unlike strings, which are immutable, StringBuilder buffers can be changed.

The original GetCommandLine function returns a pointer to a buffer allocated and owned by the operating system. When marshaling strings as return types, the interop marshaler assumes it must free the memory that the original LPTSTR type pointed to by the function. To prevent the marshaler from automatically reclaiming this memory, the managed GetCommandLine prototype returns an IntPtr type instead of a string. The Marshal.PtrToStringAuto method copies the unmanaged LPSTR type to a managed string object, widening the character format, if required.

Declaring Prototypes

Public Class LibWrap
   Declare Auto Sub GetSystemDirectory Lib "Kernel32.dll" _
      ( ByVal sysDirBuffer As StringBuilder, ByVal buffSize As Integer )
   Declare Auto Function GetCommandLine Lib "Kernel32.dll" () As IntPtr
End Class
[C#]
public class LibWrap
{
   [ DllImport( "Kernel32.dll", CharSet=CharSet.Auto )]
   public static extern int GetSystemDirectory( StringBuilder 
      sysDirBuffer, int size );
   [ DllImport( "Kernel32.dll", CharSet=CharSet.Auto )] 
   public static extern IntPtr GetCommandLine();   
}

Calling Functions

Public Class App
   Public Shared Sub Main()
      ' Call GetSystemDirectory.
      Dim sysDirBuffer As New StringBuilder( 256 )
      LibWrap.GetSystemDirectory( sysDirBuffer, sysDirBuffer.Capacity )
      ...
      ' Call GetCommandLine.
      Dim cmdLineStr As IntPtr = LibWrap.GetCommandLine()
      Dim commandLine As String = Marshal.PtrToStringAuto( cmdLineStr )
   End Sub
End Class
[C#]
public class App
{
   public static void Main()
   {
      // Call GetSystemDirectory.
      StringBuilder sysDirBuffer = new StringBuilder( 256 );
      LibWrap.GetSystemDirectory( sysDirBuffer, sysDirBuffer.Capacity );
      ...
      // Call GetCommandLine.
      IntPtr cmdLineStr = LibWrap.GetCommandLine();
      String commandLine = Marshal.PtrToStringAuto( cmdLineStr );
   }
}

See Also

Marshaling Strings | Platform Invoke Data Types | Default Marshaling for Strings | Creating Prototypes in Managed Code