Reputation:
The dll is written in c++ and sends text as utf8 through a const char*
callback.
First, is this the correct way to declare the callback?
[UnmanagedFunctionPointer( CallingConvention.StdCall )]
public delegate void TextCallback( string sText );
[DllImport(
"cppLib.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl )]
public static extern void GetText(
[MarshalAs( UnmanagedType.FunctionPtr )] TextCallback textCallback );
private TextCallback m_TextCallback;
Native callback:
typedef void ( __stdcall * TextCallback )( const char* szText );
If so, how do I handle the utf8 text once it arrives?
I'm sending it to a RichTextBox and the utf8 chars come out as garbage (the ones that happen to be ascii print fine).
Thank you all.
ANSWER
In the comments below, TheUndeadFish provided a link with an answer that works. It is also explained to a degree. Those interested should take a look. I'm just replicating the answer here as it applies to the code I posted.
Only this modification is needed:
[UnmanagedFunctionPointer( CallingConvention.StdCall )]
public delegate void TextCallback( IntPtr ipText );
The delegate reinterprets the int pointer (pointing to a utf8 string from the c++ dll) as follows:
m_TextCallback = ( ipText ) =>
{
var data = new System.Collections.Generic.List<byte>();
var off = 0;
while( true )
{
var ch = Marshal.ReadByte( ipText, off++ );
if( ch == 0 )
{
break;
}
data.Add( ch );
}
string sptr = Encoding.UTF8.GetString( data.ToArray() );
};
Upvotes: 10
Views: 3788
Reputation: 581
You should use CharSet.Unicode (if the string is a wchar*, 2 bytes per char) or CharSet.Ansi (if the string is 1 byte per char).
Since your string is in UTF8, you should convert by hand. None of the default conversion fit your problem.
Upvotes: 2