Click to See Complete Forum and Search --> : send string from C++ dll to C#


shingpui
July 13th, 2010, 09:28 AM
Hi,

I have a C++ dll that needs to send a string to C#. I know that C++ uses ASCII for storing characters and C# uses UNICODE instead. I like to know what would be the best approach to receive the string on the c# end and how should it be implemented. This is what i have now but i'm getting garbage on the c# end because of the different charcter coding.


I'm getting "Dąesult = 1.234" from the C# end while i send "My Result = 1.234" from c++ dll.


Thanks

////////////////////////////////////////
//c++
////////////////////////////////////////
//Test.h
extern "C" __declspec( dllexport ) const char* TestStringReturn();

#include "Test.h"
extern "C" __declspec( dllexport ) const char* TestStringReturn()
{
std::stringstream ReturnServiceResult;

ReturnServiceResult << "My Result = 1.234";

return ReturnServiceResult.str().c_str();
}

////////////////////////////////////////
//c#
////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;


namespace Test
{
static class Program
{
[DllImport(@"D:\TestStringReturn.dll")]

static extern string TestStringReturn();

[StructLayout(LayoutKind.Sequential)]
struct Args
{
public string ip;
public string argparams;
}

static void Main()
{
string ReturnString;

ReturnString = TestStringReturn();

}
}
}

Igor Vartanov
July 13th, 2010, 01:08 PM
I like to know what would be the best approach to receive the string on the c# end and how should it be implemented.BSTR (http://msdn.microsoft.com/en-us/library/ms221069.aspx)is system wide known string type.

Arjay
July 14th, 2010, 08:26 PM
Returning a pointer to a string in this manner is problematic - that's why no Win32 api's do it this way. Your C code shouldn't either.

To fix your problem. See how windows prototypes the method call for passing a string back to the client. A good example of these api's are GetModuleFileName or GetComputerName. Each take a pointer to a string buffer and size of the buffer as parameters. Clients create a buffer, pass in the size and the api copies the data to the buffer. Notice the clients are responsible for allocating the buffer and cleaning it up (if necessary). The server (the api in the dll in this case) is not responsible for string allocation or cleanup - the reason is that the api has know idea when the client is finished with the string.

At any rate, use the two aforementioned api's as patterns, and change your api to look just like them.

Now for the C# side. After you've changed the C api, go to www.pinvoke.com and search for the correct pinvoke signature for GetModuleFileName or GetComputerName to see how to make the pinvoke call to your api.

It's pretty easy once you've done it, but you have to start out with the proper C function prototype.

Arjay
July 14th, 2010, 08:27 PM
BSTR (http://msdn.microsoft.com/en-us/library/ms221069.aspx)is system wide known string type.BSTR implies COM is being used. So I wouldn't use it unless your api is exposed as a COM server.

Arjay
July 14th, 2010, 08:33 PM
Btw, most Win32 api's have an A and W version (e.g. GetComputerNameA and GetComputerNameW).

The pinvoke signature has the ability to specify a charset. Normally with an api with an A and W version, pinvoke handles this by default.

Since your api only exposes an ANSI version, you'll want to use CharSet.Ansi.