将C++字符返回到C#

Return C++ char to C#

本文关键字:返回 字符 C++      更新时间:2023-10-16

我有一个C++项目,其中我必须将一些变量从C++返回到C#。

这些字符变量在主程序中:

char test1[MAX_Q_LEN],test2[MAX_Q.LEN],test3[MAX_Q-LEN];

在我的C程序中完成对这些变量的处理之后,我必须在C#程序中返回这些变量的值。

ReturnChar.h

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

ReturnChar.cpp

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

测试导入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);
}

我尝试了上面的方法,但我找不到如何返回上面的char值。此外,这不应该是一个独立的函数,因为只有在执行main之后才能获取值,main将在这些变量中给出正确的值。

有什么建议吗?

我将建议一个需要将函数签名更改为以下内容的解决方案:

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

也就是说,将分配的缓冲区作为第一个参数传递给将保存输出的函数,并将缓冲区的大小作为第二个参数传递。

注意,我提到函数的返回类型为int。这是因为您可以从函数返回输出实际大小,并且调用者可以解释该值以确认outputSize值足够大,可以容纳输出字符串。例如,您可以将testString()实现为:

 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)!
    }
 }

然后在C#代码中,这样做:

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

并称之为:

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");
        }
   }
}

我不是很喜欢c++规范,但可能在c++中使用bstr

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

对于c#参数

[MarshalAs(UnmanagedType.BStr)] 

或者将StringBuilder传递给具有一些预分配容量的c++函数