Cipher
Cipher

Reputation: 6082

Return C++ char to C#

I have a C++ project in which I have to return some variables from C++ to C#.

These char variables are in the main program:

char test1[MAX_Q_LEN], test2[MAX_Q_LEN], test3[MAX_Q_LEN];

After I finish doing something with these variables in my C program, I have to return the values of these variables in a C# program.

ReturnChar.h

extern "C" RETURNCHAR_API TCHAR* __cdecl testString();

ReturnChar.cpp

extern "C" RETURNCHAR_API TCHAR* testString()
{
return ;
}

TestImport C#

static class TestImport
{
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr testString(); 
}


public partial class MainWindow : Window
{
public MainWindow()
{
try
{
InitializeComponent();
textBox1.Text = ReturnSomething()
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private static string ReturnSomething()
{
IntPtr t = TestImport.testString();
String result = Marshal.PtrToStringAuto(t);
}

I tried with the above approach but I am not able to find out how to return the above char values. Also, this should not be an independent function because the values shoud be fetched only after executing the main which will give the right values in these variables.

Any suggestions?

Upvotes: 1

Views: 2551

Answers (2)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361312

I will suggest a solution which would require you to change function signature to this:

extern "C" int __cdecl testString(char *output, int outputSize);

That is, pass an allocated buffer as the first argument to the function which will hold the output, and pass the size of the buffer as the second argument.

Note that I mention the return type of the function as int. It is because you could return the output actual size from the function, and the caller can interpret this value to confirm that outputSize value was large enough to hold the output string. For example, you could implement testString() as:

 int testString(char *output, int outputSize)
 {
    std::string const & s = getString();
    if ( s.size() <= outputSize )
    {
        std::strncpy(output, s.c_str(), s.size());
        return s.size(); //return the actual size of output
    }
    else //means s.size() > outputSize, i.e outputSize is smaller than required!
    {
        std::strncpy(output, s.c_str(), outputSize);
        return s.size(); //return what is required (the actual size of output)!
    }
 }

Then in C# code, do this:

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int testString(out StringBuilder output, int outputSize); 

And call it as:

private static string ReturnSomething()
{
   int bufferSize = 100;
   StringBuilder buffer= new StringBuilder(bufferSize);
   int outputSize = TestImport.testString(buffer, bufferSize);
   if ( outputSize < bufferSize )  //output bufferSize was sufficient
   {
        return buffer.ToString();
   }
   else //output bufferSize was insufficient 
   {
        //retry!
        bufferSize = outputSize;
        buffer = new StringBuilder(bufferSize); //reallocate!
        outputSize = TestImport.testString(buffer, bufferSize); 
        if ( outputSize <= bufferSize )
             return buffer.ToString();
        else
        {
            throw new Exception("PANIC");
        }
   }
}

Upvotes: 2

DanNsk
DanNsk

Reputation: 900

I'm not quite big c++ spec, but maybe to use bstrs in c++

_bstr_t text("saasas");
return text.Detach();

and for c# parameter

[MarshalAs(UnmanagedType.BStr)] 

or to pass StringBuilder to your c++ func with some preallocated capacity

Upvotes: 2

Related Questions