-1

I'm actually learning C#/WPF and I wrote a library in C++. And I have a function that have an output parameter in LPSTR type, the test work well in C++ and I'm actually getting the right value I wanted with the right size. But in C# after importing the dll and set the format to unicode/ansi, either I have a empty value or bad value.

C++ project build in myfunction.dll win32.

C++ export

/*
* getting the right value in outString 
* c++ test
* 
*/

API_DLLEXPORT long GetSomeString (LPSTR outString ,long * outNbChar);
for (long iChar = 0; iChar < *outNbofchar; ++iChar)
{
    outsLibClass[iChar] = (char)finder.GetFileName()[iChar];
}
outsLibClass[*outNbofchar] = '\0';
break; 

C# import

[DllImport("myfunction.dll",  CharSet = CharSet.Unicode)]
public static extern Int32 GetSomeString (StringBuilder outString, ref Int32 outNbChar);

StringBuilder out = new StringBuilder(256) ;
Int32 nbchar = new Int32() ;

int result = GetSomeString (out, ref nbchar ) ;

Console.WriteLine(out.ToString());

// I get the right nbchar

But I'm not getting the right outstring result:

㠴0휐ࠦ휠ࠦ鏺瓑휬ࠦ찞瑻쳁촀

And of course I try also to set the CharSet to Ansi but the result was empty.

So if anyone could help me that would be a great pleasure.

GSerg
  • 76,472
  • 17
  • 159
  • 346
  • 2
    https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-for-strings ? – ProgrammingLlama Aug 05 '20 at 07:40
  • I'm pretty sure you are not getting correct results in C++ either. Please show `GetSomeString`. – GSerg Aug 05 '20 at 07:45
  • for (long iChar = 0; iChar < *outNbofchar; ++iChar) { outsLibClass[iChar] = (char)finder.GetFileName()[iChar]; } outsLibClass[*outNbofchar] = '\0'; break; – Hadramet Sylla Aug 05 '20 at 08:00
  • `long` is 64-bit on 64-bit platforms but you have mapped it to `Int32` on the managed side. Also, please show the full implementation of `GetSomeString` as @GSerg mentioned. The snippet in your comment is not enough (for example, what is `finder`?) – TainToTain Aug 05 '20 at 08:06
  • @TainToTain `long is 64-bit` - https://stackoverflow.com/q/384502/11683 – GSerg Aug 05 '20 at 08:14
  • @HadrametSylla That is a truly horrible way of copying the result of `GetFileName()` into the return buffer, but that put aside, you are passing a pointer to zero to `outNbChar` instead of a pointer to the buffer size. – GSerg Aug 05 '20 at 08:17
  • @GSerg Oh, you mean 32-bit. I see. – TainToTain Aug 05 '20 at 08:28
  • @GSerg yes way its kind a horrible but the problem is not in c++ because i'm actualy getting the value when i print it. the GetSomeString methode can also be a simple string input but in c# i'm getting some value but not in the right format. – Hadramet Sylla Aug 05 '20 at 08:42
  • @John thank you for link it works with the spec in the doc. – Hadramet Sylla Aug 05 '20 at 08:44
  • @TainToTain i'm actualy builing in x32 that why i use the int32. – Hadramet Sylla Aug 05 '20 at 08:50

1 Answers1

-1

Thx to @john link in the comments, i resolve it : i was making a copy and not actualy referencing the address of outString.


// Replace LPSTR by LPSTR 
API_DLLEXPORT long GetSomeString (LPSTR * outString ,long * outNbChar);

and in c#

[DllImport("myfunction.dll",  CharSet = CharSet.Unicode)]
public static extern Int32 GetSomeString ([MarshalAs(UnmanagedType.LPStr)] ref string outString,
                                          ref Int64 outNbChar);
  • This is wrong for many reasons. Given that the memory is (correctly) allocated at the calling side, you must use `LPSTR`, not `LPSTR*`. You shouldn't declare Unicode only to immediately override it to Ansi, and you shouldn't pass `Int64` for a 32-bit `long`. If this happens to currently work for you, this is a coincidence. – GSerg Aug 05 '20 at 09:03
  • @GSerg I'm agree its kind a weird, but i followed this [doc](https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-for-strings) and its work. – Hadramet Sylla Aug 05 '20 at 09:11
  • There is a difference between weird and wrong. You should have `API_DLLEXPORT long GetSomeString (LPSTR outString, long* outNbChar);`, `[DllImport("myfunction.dll", CharSet = CharSet.Ansi)] public static extern int GetSomeString (StringBuilder outString, ref int outNbChar);`, and you should pass the "current capacity of the string builder minus 1" for the second argument. There are also various problems with the C++ loop you are using for copying, but I'm not touching that at the moment (the "minus 1" is one of the manifestations of these problems). – GSerg Aug 05 '20 at 09:15