返回从PInvoke的字符串? [英] Returning a string from PInvoke?

查看:128
本文介绍了返回从PInvoke的字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能重复:结果
  元帅“ char *之”的在C#

我使用的PInvoke为本地code(C ++)和托管code(C#)之间的互操作性。
我只是写一个简单的函数从C ++ code得到的字符串。我的code样子
C#code:

I am using PInvoke for interoperability between Native Code (C++) and Managed Code (C#). I just write a simple function which gets a string from c++ code. My code looks like C# Code:

        [DllImport("MyDll.dll")]
        private static extern string GetSomeText();
        public static string GetAllValidProjects()
        {
            string s = GetSomeText();
            return s;
        }

C ++ code

C++ Code

char* GetSomeText()    
{
std::string stri= "Some Text Here";
char * pchr = (char *)stri.c_str();
return pchr;
} 

在所有的C ++结束正​​常工作,即在巴勒斯坦人权中心,则为有些文字在这里,但在C#中的字符串s它包含值得注意。我不知道我做错了。任何帮助将是AP preciated

All works fine at c++ end, i.e the pchr contians "Some Text Here" but at C# the string s contains noting in it. I don't know what I am doing wrong. Any help would be appreciated

推荐答案

首先,正如其他人指出的那样,你的C ++甚至试图互操作之前打破。您正在返回一个指针 STRI 的缓冲区。但由于 STRI 是尽快函数返回,返回值是无效的破坏。

First of all, as others have pointed out, your C++ is broken even before trying interop. You are returning a pointer to stri's buffer. But because stri is destroyed as soon as the function returns, the return value is not valid.

更重要的是,即使你解决了这个问题,你需要做的更多。它不会工作在C ++ code,你将需要C#code,以释放内存分配。

What's more, even if you fixed this, you need to do more. It won't work allocating memory in your C++ code which you would need the C# code to deallocate.

有几个选项做是正确的。

There are a few options to do it right.

您C#code可以问C ++ code字符串有多长。然后一个C#StringBuilder的创建并分配到适当的大小。接下来StringBuilder对象传递给C ++ code和其默认编组是作为LPWSTR。在这种方法中,C#code分配的字符串和您的C ++ code接收一个C字符串,它必须复制的缓冲区。

Your C# code can ask the C++ code how long the string is. Then a C# StringBuilder is created and allocated to the appropriate size. Next the StringBuilder object is passed to the C++ code and its default marshalling is as a LPWSTR. In this approach the C# code allocates the string and your C++ code receives a C string to which it must copy the buffer.

另外,您可以从C ++允许在本地C ++ code和释放在C#code分配返回BSTR。

Alternatively you can return a BSTR from the C++ which allows allocation in the native C++ code and deallocation in the C# code.

BSTR的方法可能是我会怎么做。它看起来是这样的:

The BSTR approach is probably how I would do it. It looks like this:

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();

更新

汉斯帕桑特增加了几个有用的意见,在意见。首先,大多数的P / Invoke的互操作是对现有的接口,它不能改变做,你没有选择pferred接口互操作的方法$ P $的奢侈品。这样看来,是不是这里的情况,所以这做法应该选择?

Hans Passant added a couple of useful observations in the comments. First of all, most P/Invoke interop is done against an existing interface which cannot be changed and you do not have the luxury of picking your preferred interop interfacing approach. It would appear that is not the case here, so which approach should be chosen?

选项1是分配在托管code中的缓冲区,有第一,问道本土code需要多少空间。也许是足够使用一个固定大小的缓冲区双方同意。

Option 1 is to allocate the buffer in the managed code, after having first asked the native code how much space is needed. Perhaps it is enough to use a fixed size buffer that both parties agree on.

如果选择1跌倒是组装的字符串是昂贵的,当你不想(为内容例如一次返回它的长度,并再次)做两次。这是选项2, BSTR 用武之地。

Where option 1 falls down is when assembling the string is expensive and you don't want to do it twice (e.g. once to return its length, and once again for the contents). This is where option 2, the BSTR comes into play.

汉斯指出的一个缺点的 BSTR ,即它带有UTF-16有效载荷,但源数据可能会好的char * ,这是一个麻烦的一点。

Hans pointed out one drawback of the BSTR, namely that it carries a UTF-16 payload but your source data may well char*, which is a "bit of a hassle".

要克服你可以用从的char *转换的麻烦 BSTR 是这样的:

To overcome the hassle you can wrap up the conversion from char* to BSTR like this:

BSTR ANSItoBSTR(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;
}

这是最难的一出的方式,现在可以很容易地从 LPWSTR BSTR C>,的std ::字符串的std :: wrstring 等。

That's the hardest one out of the way, and now it's easy to add other wrappers to convert to BSTR from LPWSTR, std::string, std::wrstring etc.

这篇关于返回从PInvoke的字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆