简体   繁体   中英

how to display in messagebox a C function from C# with a WCHAR*

I'm building a C# application that loads a C++ library. I call functions from that C++ DLL. I use below function to display input string.

c++ dll:

wchar_t* Test_EchoString( wchar_t *InputStr )
{
String HWStr = String( InputStr );  

return HWStr.c_str();
}

c# code:

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]

public static extern int  _Test_EchoString([MarshalAs(UnmanagedType.LPWStr)] string s);

private void echo_string_Click(object sender, RoutedEventArgs e)
{
    string upn = "aaaaa";
    _Test_EchoString(upn);

    MessageBox.Show(_Test_EchoString(upn).ToString());    
}

I get in messagebox number 18666252 but i want to get a string from _Test_EchoString() .

You have a pair of problems in your code:

in your C# you defined _Test_EchoString as public static extern int _Test_EchoString , so when you execute it, the returned value will be the address of the first character of the string HWStr.c_str() . And here it shows another problem, as anderas said, you are returning an invalid pointer, because HWStr.c_str() returns the pointer to the current value of the std::wstring object, so it is valid as long that the wstring is valid, so when the method Test_EchoString ends its execution it is no more valid(because HWStr is destroyed).

There are different ways to fix this problems, I'm going to show you two of these:

1) The first is to allocate the memory you want to return in the Heap and free it later with another call:

static wchar_t *Test_EchoStringResult;
extern "C" __declspec(dllexport) const wchar_t * Test_EchoStringNew(const wchar_t *InputStr)
{
    std::wstring HWStr(InputStr);
    HWStr += L" something";
    Test_EchoStringResult = new wchar_t[HWStr.length() + sizeof(wchar_t)];
    HWStr.copy(Test_EchoStringResult, HWStr.length());
    Test_EchoStringResult[HWStr.length()] = L'\0';
    return Test_EchoStringResult;
}

extern "C" __declspec(dllexport) void Test_EchoStringDelete()
{
    delete[] Test_EchoStringResult;
}

And this is the usage in C#:

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern IntPtr Test_EchoStringNew(string foo);

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void Test_EchoStringDelete();

public void foo()
{
    string result = Marshal.PtrToStringAuto(Test_EchoStringNew("test"));
    MessageBox.Show(result.ToString());
    Test_EchoStringDelete();
}

To me, this looks pretty ugly, so I'd prefer to use another pattern

2) Passing a callback to the C method and pass to this method HWStr.c_str() when HWStr is still valid:

extern "C" __declspec(dllexport) void Test_EchoString(const wchar_t *InputStr, void (*callback)(const wchar_t*))
{
    std::wstring HWStr(InputStr);
    HWStr += L" something";
    callback(HWStr.c_str());
}

And here is the C# usage:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public delegate void myCallback(string toShow);

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void Test_EchoString(string foo, myCallback callback);

public void foo()
{
    Test_EchoString("test", callback);
}

void callback(string toShow)
{
    MessageBox.Show(toShow);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM