如何从Native(C ++)代码返回文本

我正在使用Pinvoke在本机(C ++)代码和托pipe(C#)代码之间进行互操作。 我想实现的是从本地代码中获取一些文本到托pipe代码中。 为此,我尝试了很多东西,例如,使用[IN]和[OUT]传递string / stringbuilder,使用LPSTR封装,从函数等返回string,但在我的情况下没有任何作用。 任何帮助一些小代码将不胜感激。

我会用BSTR来做,因为这意味着你不必为每个string调用两次本地variables,一次获得长度,然后一次获得内容。

使用BSTR ,编组人员将负责使用正确的内存pipe理器来释放BSTR ,以便将其从C ++代码中安全地传递出去。

C ++

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

C#

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

BSTR有一个小缺点,就是它携带一个UTF-16有效载荷,但是你的源数据很可能是char*

为了克服这个问题,你可以像下面这样将char*转换为BSTR

 BSTR ANSItoBSTR(const char* input) { BSTR result = NULL; int lenA = lstrlenA(input); int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0); if (lenW > 0) { result = ::SysAllocStringLen(0, lenW); ::MultiByteToWideChar(CP_ACP, 0, input, lenA, result, lenW); } return result; } 

这是最难的一个,现在很容易添加其他包装从LPWSTRstd::stringstd::wstring等转换为BSTR

以下是通过C#执行此操作的示例。 我通过pInvoking通过C#调用Native函数GetWindowTextGetWindowText返回其handle传递给它的窗口的标题。

  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetWindowTextLength(IntPtr hWnd); public static string GetText(IntPtr hWnd) { // Allocate correct string length first int length = GetWindowTextLength(hWnd); StringBuilder sb = new StringBuilder(length + 1); GetWindowText(hWnd, sb, sb.Capacity); return sb.ToString(); } private void button1_Click(object sender, EventArgs e) { string str = GetText(this.Handle); } 

这里有一个话题是string编组已经讨论过了。

需要用属性标记参数

 [MarshalAs(UnmanagedType.LPSTR)] 

如果你返回一个char * ,并且不想修改C / C ++代码来为你的返回值分配内存(或者你不能修改那个代码),那么你可以改变你的C#的extern函数,原型来返回一个IntPtr ,并做自己的编组。

例如,下面是我为Pocketsphinx写的interop的一个片段:

 [DllImport("sphinxbase.dll", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr /* char const * */ jsgf_grammar_name(IntPtr /* jsgf_t * */ jsgf); 

这里是C# JsgfGrammar类的获取访问器。 m_pU是一个指向原始jsgf_t对象的IntPtr

 public string Name { get { IntPtr pU = jsgf_grammar_name(m_pU); if (pU == IntPtr.Zero) strName = null; else strName = Marshal.PtrToStringAnsi(pU); return strName; } } 

为其他string格式(例如Unicode)修改这个例子应该是微不足道的。