C ++ dll returned string is damaged in C # calling why?

I have a C # application that calls a C ++ DLL.

In C #, I have the code as follows:

[DllImport(@"111.dll", CharSet = CharSet.Unicode)] public extern static String Func1(String arg); ...... String arg = "test text"; String retstring = Func1(arg); 

In CPP, I have a function defined as follows:

 extern "C" { __declspec(dllexport) LPWSTR Func1(LPWSTR arg) { .... LPWSTR ret1 = L"1?2?3?4?5"; LPWSTR ret2 = SomeActualFunction(arg); retturn ret1; // return ret2; } } 

If I return ret1 in C ++ Func1 (), everything works fine. And in the VS2008 memory window, I can see the correct Unicode binaries. In C ++, binaries ret1 -

"31 00 3f 00 32 00 3f 00 33 00 3f 00 34 00 3f 00 35 00"

and in C # retstring binaries

"28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00 31 00 3f 00 32 00 3f 00 33 00 3f 00 34 00 3f 00 35 00"

. I think C # binaries

"28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00"

is a header of type System.String.

What else, if I add the following line immediately before returning in the CPP code, I can also get the correct line in C #:

 ret2 = L"1?2?3?4?5"; 

But when I return ret2 in the C ++ DLL, the returned string of ret in C # seems to be corrupted. The binaries in the C ++ DLL are Unicode correct when I inspect. But the retstring binaries in C # code make up

"28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00 dd dd dd dd dd dd dd dd dd dd dd dd ....".

I can only notice that ret2 is longer than ret1 - ret2 has several hundred WCHARs.

Any ideas? thanks in advance.

+6
source share
7 answers

I would always use BSTR for this because it transparently allocates memory allocation / deallocation.

C ++

 #include <comutil.h> BSTR GetSomeText() { return ::SysAllocString(L"Greetings from the native world!"); } 

FROM#

 [DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.BStr)] private static extern string GetSomeText(); 

You do not say how your lines are allocated, but as soon as you use a dynamically allocated line, you need to solve this problem. The great thing about BSTR is that it uses a common COM allocator, which allows the C # marker to free a line with the same allocator as the C ++ code that allocated it.

+8
source
 [DllImport(@"111.dll", CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.LPStr)] public extern static String Func1(String arg); 

or

 [DllImport(@"111.dll", CharSet = CharSet.Unicode)] public extern static IntPtr Func1(String arg); // In your calling code string result = Marshal.PtrToStringUni(Func1("somestring")); 
+5
source

Is your call func __cdecl or __stdcall? IIRC, the default value for C # is __stdcall , but the default for C ++ is __cdecl . Try adding CallingConvention=CallingConvention.Cdecl .


Another possibility: since you are saying that it returns a static string, is the pointer returned by SomeActualFunction returned? If he pointed to a local buffer in this function, it will not act after returning from the function.

+1
source

So, if you return the pointer to the line string L "1? 2? 3? 4? 5", everything will be fine. But if you return SomeActualFunction, the answer is incorrect. Maybe the C ++ code is wrong? How does SomeActualFunction work? For example, it can return LPWSTR from some object pushed onto the stack, which is destroyed at this time. Try to test this first with a C ++ client.

0
source

I downloaded the sample code on SkyDrive (http://cid-48a119f5ed65483e.office.live.com/self.aspx/.Public/MarshalString.zip). It demonstrates how to pass a managed string to unmanaged code and how to manipulate it.

0
source

I think I got this working: calling C # in a C ++ DLL, returns a string in C #. I will tell you what I think is what makes it work:

In c #

 using System.Runtime.InteropServices; [DllImport( @"C:\Users\Ron\Documents\Visual Studio 2013\ etc. ...(The whole path)... my.dll, CallingConvention = CallingConvention.Cdecl )] [return: MarshalAs(UnmanagedType.BStr)] public static extern string cpp_brand_files(string home_dir, string xml_lic); 

And a call later in C #:

  string a_str = cpp_brand_files(home_dir, xml_license); 

In the C ++ DLL:

  #using <mscorlib.dll> using namespace System; extern "C" __declspec(dllexport) wchar_t* cpp_brand_files(char* home_dir, char* xml_lic); 

And further in C ++:

  wchar_t* cpp_brand_files(char* home_dir, char* xml_lic) { BSTR samp = ::SysAllocString( L"This is the long, long string." ); return samp; } 

ALSO, compile the C ++ DLL with / cli (Common Language Runtime Support) in the configuration properties. Right-click the C ++ project, then Properties → Configuration Properties → General → Common Language Runtime Support.

So, I think these are the bare bones of what makes it work (returning a string).

I am using Visual Studio 2013 RC. Experts, please comment on what is optional or missing.

0
source

Here is the link for your reference if you need to marshal other data types. UPDATE COMMUNICATION FOR .NET 4.0 https://msdn.microsoft.com/en-us/library/sak564ww(v=vs.100).aspx

0
source

Source: https://habr.com/ru/post/890580/


All Articles