Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ DLL LPCTSTR to C# string

Tags:

c++

c#

dll

I am trying to get string from C++ DLL to C#. It outputs incorrect symbols - {栠搂珯獲긋ݳݳ贈琹玴ɡݳ⻜}

Here is my code: C++ DLL

_declspec(dllexport) int __stdcall myClass(LPCTSTR& z)
{
    z = _T("Test String");
    return 0;
}

My C# code reading C++ DLL:

[DllImport("ecrClassDll.dll", CharSet = CharSet.Unicode)]
static extern void myClass(StringBuilder z);

static void Main(string[] args)
{
    StringBuilder z = new StringBuilder();
    myClass(z);
}
like image 904
Kristaps C Avatar asked Jan 25 '26 01:01

Kristaps C


1 Answers

First, make sure you defined the UNICODE macro in C++, so that _T outputs wchar_t data, and LPCTSTR means const wchar_t*. That's what CharSet.Unicode expects. By the way, if you don't intend to support an ANSI version too, I wouldn't bother with all this _T stuff and just use Unicode everywhere, the code will be simpler.

Also, your C++ function returns an int, but your C# function expects a void. You have a mismatch there (unless you intended to set PreserveSig to false).

On the C# side, when you provide a StringBuilder, it means you provide a buffer to the C++ side, and you expect it to fill that buffer. The correct usage would be something like this:

_declspec(dllexport) int __stdcall myClass(LPCTSTR z, int zSize)
{
    _tcscpy_s(z, zSize, _T("Test String"));
    return 0;
}
[DllImport("ecrClassDll.dll", CharSet = CharSet.Unicode)]
static extern int myClass(StringBuilder z, int zSize);

static void Main(string[] args)
{
    StringBuilder z = new StringBuilder(256);
    myClass(z, z.Capacity);
}

But your code returns a pointer to a static string, which the marshaller doesn't expect here.

If you'd like to keep your C++ code as-is, you could try this instead:

[DllImport("ecrClassDll.dll", CharSet = CharSet.Unicode)]
static extern int myClass(out string z);

static void Main(string[] args)
{
    string z;
    myClass(out z);
}

I admit I didn't test it, but it should work as this C# signature matches the C++ signature.

If everything fails, you could try to marshal the data by yourself:

[DllImport("ecrClassDll.dll")]
static extern unsafe int myClass(void** z);

static unsafe void Main(string[] args)
{
    void* z;
    myClass(&z);
    var str = Marshal.PtrToStringUni(new IntPtr(z));
}
like image 153
Lucas Trzesniewski Avatar answered Jan 27 '26 15:01

Lucas Trzesniewski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!