Export (0) Print
Expand All

Strings Sample

This sample demonstrates how to use a string returned from an unmanaged function, and how to pass a structure that contains a Unicode-formatted or ANSI-formatted string. It shows how to properly initialize these strings and how to retrieve returned values.

The String sample uses the following unmanaged functions, shown with their original function declaration:

  • TestStringAsResult exported from PinvokeLib.dll.

    char* TestStringAsResult();
    
  • TestStringInStruct exported from PinvokeLib.dll.

    void TestStringInStruct(MYSTRSTRUCT* pStruct);
    
  • TestStringInStructAnsi exported from PinvokeLib.dll.

    void TestStringInStructAnsi(MYSTRSTRUCT2* pStruct);
    

PinvokeLib.dll is a custom unmanaged library that contains implementations for the previously listed functions and two structures, MYSTRSTRUCT and MYSTRSTRUCT2. These structures contain the following elements:

typedef struct _MYSTRSTRUCT
{
   wchar_t* buffer;
   UINT size; 
} MYSTRSTRUCT;
typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size; 
} MYSTRSTRUCT2;

In this sample, the managed MyStrStruct and MyStrStruct2 structures contain managed strings instead of StringBuilder buffers because the StringBuilder type cannot be used inside a structure. The StructLayoutAttribute attribute is set to ensure that the members are arranged in memory sequentially, in the order in which they appear. The CharSet field is set to specify ANSI or Unicode formats.

The LibWrap class contains the managed prototype methods called by the App class. Although structures are normally passed by value, the arguments to the TestStringInStruct and TestStringInStructAnsi methods are marked with the ref (ByRef in Visual Basic) keyword, which passes structures by reference.

// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct MyStrStruct
{
    public string buffer;
    public int size;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct MyStrStruct2
{
    public string buffer;
    public int size;
}

public class LibWrap
{
    // Declares managed prototypes for unmanaged functions.
    [DllImport("..\\LIB\\PinvokeLib.dll")]
    public static extern string TestStringAsResult();

    [DllImport("..\\LIB\\PinvokeLib.dll")]
    public static extern void TestStringInStruct(ref MyStrStruct mss);

    [DllImport("..\\LIB\\PinvokeLib.dll")]
    public static extern void TestStringInStructAnsi(ref MyStrStruct2 mss);
}

public class App
{
    public static void Main()
    {
        // String as result. 
        string str = LibWrap.TestStringAsResult();
        Console.WriteLine("\nString returned: {0}", str);

        // Initializes buffer and appends something to the end so the whole 
        // buffer is passed to the unmanaged side.
        StringBuilder buffer = new StringBuilder("content", 100);
        buffer.Append((char)0);
        buffer.Append('*', buffer.Capacity - 8);

        MyStrStruct mss;
        mss.buffer = buffer.ToString();
        mss.size = mss.buffer.Length;

        LibWrap.TestStringInStruct(ref mss);
        Console.WriteLine( "\nBuffer after Unicode function call: {0}",
            mss.buffer );

        StringBuilder buffer2 = new StringBuilder("content", 100);
        buffer2.Append((char)0);
        buffer2.Append('*', buffer2.Capacity - 8);

        MyStrStruct2 mss2;
        mss2.buffer = buffer2.ToString();
        mss2.size = mss2.buffer.Length;

        LibWrap.TestStringInStructAnsi(ref mss2);
        Console.WriteLine("\nBuffer after Ansi function call: {0}",
            mss2.buffer);
    }
}
Show:
© 2014 Microsoft