Buffers Sample

This sample shows 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.

This sample platform invokes two native Win32 functions exported from Kernel32.dll:

  • GetSystemDirectory

    Retrieves the path of the system directory.

  • GetCommandLine

    Retrieves the command-line string for the current process.

The LibWrap class contains a managed prototypes for the unmanaged functions, which are called from Main in the console application. The CharSet field is set so that platform invoke can choose between ANSI and Unicode formats at run time, based on the target platform. For more information about this field, see Specifying a Character Set.

The GetSystemDirectory prototype method substitutes a 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 native 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 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
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();
}
public ref class LibWrap
{
public:
    [DllImport("Kernel32.dll", CharSet=CharSet::Auto)]
    static int GetSystemDirectory(StringBuilder^
        sysDirBuffer, int size);

    [DllImport("Kernel32.dll", CharSet=CharSet::Auto)]
    static 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
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);
    }
}
public ref class App
{
public:
    static void Main()
    {
        // Call GetSystemDirectory.
        StringBuilder^ sysDirBuffer = gcnew StringBuilder(256);
        LibWrap::GetSystemDirectory(sysDirBuffer, sysDirBuffer->Capacity);
        // ...
        // Call GetCommandLine.
        IntPtr cmdLineStr = LibWrap::GetCommandLine();
        String^ commandLine = Marshal::PtrToStringAuto(cmdLineStr);
    }
};

See Also

Concepts

Marshaling Strings

Platform Invoke Data Types

Default Marshaling for Strings

Other Resources

Creating Prototypes in Managed Code