C# Receives String from C++ DLL

Asked 1 years ago, Updated 1 years ago, 81 views

I look forward to hearing from you.

Write a function that returns a string (mixed alphanumeric) with char in C++ and
I'm thinking of using that function from C# to receive a string.
I looked it up and found that there were steps like passing a string from C#, but
I'm at a loss because I can't find a way to return it from C++.
If anyone knows, could you please let me know?

c# c++

2022-09-30 21:21

3 Answers

In C/C++, the "function returns a string" action has two patterns:
1. A called function dynamically takes memory with malloc() and stores a string there (strdup)
). 2. The calling function takes a fixed-length buffer, and the called function stores a string there (snprintf)
Which one is this case?

You can use StringBuilder for the latter.This eliminates the need for unsafe and automatically encodes.

C++ side

extern "C"_declspec(dllexport)bool_stdcallGetText(char*buf,size_tbufsize){
    if(bufsize<4)return false
    buf[0] = 'a';
    buf[1] = '\x82'; // 82a0 = CP932 'Ah'
    buf[2] = '\xa0';
    buf[3] = '\0';
    return true;
}

C# side

 [DllImport("example.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
static external Boolean GetText (StringBuilder's, Int32bufsize);

// CharSet.Ansi specifies that OS standard local specific encoding should be automatically converted to UTF-16
// CP932 → UTF-16 for Japanese OS
System.Text.StringBuilder sb=new System.Text.StringBuilder(256);
GetText(sb, sb.Capacity);
Console.WriteLine(sb.ToString()); //a

In the former case malloc() series results are different depending on when and how free() is performed.
You have to look at the C/C++ specifications or implementations to get answers.


2022-09-30 21:21

:: If you use the memory saved by CoTaskMemAlloc, you can target GC on the .Net side, so
C++ to C# string passing is easier on the C# side by implementing the following link:
https://limbioliong.wordpress.com/2011/06/16/returning-strings-from-a-c-api/

C/C++

extern "C"_declspec(dllexport) char *__stdcall StringReturnAPI01()
{
    charszSampleString[] = "Hello World";
    ULONGulSize=strlen(szSampleString)+sizeof(char);
    char*pszReturn=NULL;

    pszReturn=(char*)::CoTaskMemAlloc(ulSize);
    // Copy the contents of szSampleString
    // to the memory pointed to by pszReturn.
    strcpy(pszReturn, szSampleString);
    // Return pszReturn.
    return pszReturn;
}

C#

 [DllImport("<path to DLL>", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
return: MarshallAs (UnmanagedType.LPStr)
public static external string StringReturnAPI01();

static void CallUsingStringAsReturnValue()
{
  string strReturn01 = StringReturnAPI01();
  Console.WriteLine("Returned string:"+strReturn01);
}


2022-09-30 21:21

Compile /unsafe with C# and use byte* (pointer) or
Instead of using /unsafe, you can pinned the area and pass the address.

https://stackoverflow.com/questions/1579446/how-can-i-pass-a-pointer-to-an-integer-in-c-sharp

To quote with a little improvement,

【Unsafe usage pattern <

unsafe static void TestMethod()
{
    fixed (byte*buffer=new byte [4096])
    {
        int maxSize = buffer.Length;
        GetBuffer(buffer, ref maxSize);
    }
}

【Unsafe not used pattern >

byte[] buf = new byte [kBufSize];
GCHANDLE HANDLE = GCHANDLE.Alloc (buf, GCHANDLEType.Pined); 
// An address is fixed by securing an area and pinning it.
IntPtrp=handle.AddrOfPinnatedObject();
int size = buf.Length;
intret=GetBuffer(p,ref size); // DLLImported C++ function
handle.Free();

You can convert the byte array you receive into characters to match the encoding of the string.


2022-09-30 21:21

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.