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 Microsoft .NET Framework SDK includes the complete Visual Basic .NET and C# versions of this sample in Samples\Technologies\Interop\Platform-Invoke.
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.
Declaring Prototypes
' Declares a managed structure for each unmanaged structure.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Unicode )> _
Public Structure MyStrStruct
Public buffer As String
Public size As Integer
End Structure 'MyStrStruct
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Structure MyStrStruct2
Public buffer As String
Public size As Integer
End Structure 'MyStrStruct2
Public Class LibWrap
' Declares managed prototypes for unmanaged functions.
Declare Function TestStringAsResult Lib "..\LIB\PinvokeLib.dll" () _
As String
Declare Sub TestStringInStruct Lib "..\LIB\PinvokeLib.dll" _
( ByRef mss As MyStrStruct )
Declare Sub TestStringInStructAnsi Lib "..\LIB\PinvokeLib.dll" _
( ByRef mss As MyStrStruct2 )
End Class 'LibWrap
[C#]// 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 );
}
Calling Functions
Public Class App
Public Shared Sub Main()
' String as result.
Dim strng As String = LibWrap.TestStringAsResult()
Console.WriteLine( ControlChars.CrLf + "String returned: {0}", _
strng )
' Initializes buffer and appends something to the end so the whole
' buffer is passed to the unmanaged side.
Dim buffer As New StringBuilder( "content", 100 )
buffer.Append( ChrW(0) )
buffer.Append( "*"c, buffer.Capacity - 8)
Dim mss As MyStrStruct
mss.buffer = buffer.ToString()
mss.size = mss.buffer.Length
LibWrap.TestStringInStruct( mss )
Console.WriteLine( ControlChars.CrLf + _
"Buffer after Unicode function call: {0}", mss.buffer )
Dim buffer2 As New StringBuilder( "content", 100 )
buffer2.Append( ChrW(0) )
buffer2.Append( "*"c, buffer2.Capacity - 8 )
Dim mss2 As MyStrStruct2
mss2.buffer = buffer2.ToString()
mss2.size = mss2.buffer.Length
LibWrap.TestStringInStructAnsi( mss2 )
Console.WriteLine( ControlChars.CrLf + _
"Buffer after Ansi function call: {0}", mss2.buffer )
End Sub 'Main
End Class 'App
[C#]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 );
}
}
See Also
Marshaling Strings | Platform Invoke Data Types | Default Marshaling for Strings | Creating Prototypes in Managed Code