将字符串数组从C#传递到C ++ dll,然后再次返回
我环顾了googleverse和堆栈溢出,并看到了与此类似的几个问题,但是我发现的答案都没有为我解决.我是新成员,因此我不允许评论别人的问题以要求澄清,所以我不得不求助于我自己的问题.
I have looked around the googleverse and stack overflow and have seen several similar questions to this but none of the answers I have found have worked for me. I am a new member so I am not allowed to comment on answers in someone else's question to ask for clarification so I have had to resort to asking my own.
好,所以我试图将字符串数组从C#应用程序传递到C ++ dll,然后在另一个C#应用程序中获取该信息.我相信我可以正确地传递给C ++,但是我无法从dll中获取正确的字符串.
Ok so I am trying to pass a string array from a C# application to a C++ dll and then grab that information in another C# application. I believe I am passing to C++ properly but I can't get proper strings back from the dll.
我像这样传递给C ++:
I am passing to C++ like so:
[DllImport("KinectPlugins.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void SetGrammarData(string[] strArr, int size);
public void SetGrammar(string[] strArr)
{
SetGrammarData(strArr, strArr.Length);
}
我的C ++代码如下:
My C++ code looks like this:
#define EXPORT_API __declspec(dllexport)
#pragma data_seg(".SHARED")
char** grammarData;
int grammarDataLength = 0;
#pragma data_seg()
#pragma comment(linker, "/section:.SHARED,RWS")
EXPORT_API void SetGrammarData(char** strArr, int size)
{
grammarData = strArr;
grammarDataLength = size;
}
EXPORT_API int GetGrammarDataLength()
{
return grammarDataLength;
}
EXPORT_API char** GetGrammarData()
{
return grammarData;
}
我随后在其他C#应用程序中获取信息的代码如下:
My code for then grabbing the information in my other C# application looks like this:
[DllImport("KinectPlugins.dll")]
private static extern IntPtr GetGrammarData();
[DllImport("KinectPlugins.dll")]
private static extern int GetGrammarDataLength();
public string[] GetGrammar()
{
int size = GetGrammarDataLength();
List<string> list = new List<string>();
IntPtr ptr = GetGrammarData();
IntPtr strPtr;
for (int i = 0; i < size; i++)
{
Console.WriteLine("i = " + i);
strPtr = Marshal.ReadIntPtr(ptr);
list.Add(Marshal.PtrToStringAnsi(strPtr));
ptr += Marshal.SizeOf(typeof(IntPtr));
}
return list.ToArray();
}
理论上,这应该基于我的研究,因为我已经看到其他几个人使用几乎相同的代码.在实践中,发生的事情是我通过了:
In theory this should work based on my research as I have seen several other people use almost the same code. In practice, what happens is I pass in:
SetGrammar(new string[] { "b", "a" });
另一面又是:
stringArray[0] =
stringArray[1] = H-▬l☺
如果由于某些原因而无法查看它,或者另一个stringArray [1]等于H,-,粗线,l和笑脸符号.显然这不是我要输入的.
In case some can't view it for some reason or another stringArray[1] is equal to H, -, a thick line, l and a happy face symbol. This is obviously not what I put in.
有人知道我可能在哪里出错吗?我花了很长时间来解决这个问题,并且真的可以使用一些帮助,因为感觉好像我在这里错过了一些非常简单的事情.
Does anyone have an idea where I could be going wrong with this? I have been banging my head against this problem for quite a while and could really use some help as it feels like I am missing something really simple here.
修改:根据antijon的建议,我确实更改了SetGrammarData来复制字符串,但仍然遇到问题.
as per antijon's suggestion I did change my SetGrammarData to make a copy of the strings but I am still running into an issue.
新代码:
(inside the data_seg)
wchar_t* grammarData;
(end data_seg)
EXPORT_API void SetGrammarData(wchar_t* strArr, int size)
{
delete[] grammarData;
grammarData = new wchar_t[size];
std::memcpy(grammarData, strArr, sizeof(wchar_t) * size);
grammarDataLength = size;
}
EXPORT_API wchar_t* GetGrammarData()
{
return grammarData;
}
现在我得到以下输出:
stringArray[0] = 8
stringArray[1] =
C#代码保持不变.我还有其他需要改变的东西吗?
The C# code has remained the same. Is there something else I need to change that I am missing?
Edit2:刚刚意识到wchar_t就像一个字符,而不是一个字符串,不知道为什么我认为它的行为像一个字符串.回到绘图板上,需要弄清楚如何最好地复制wchar_t **.没有C ++的经验,但是我认为没有自己传递wchar_t *的长度是不可能的,但是我将不得不研究它.
Just realized that wchar_t is like a char, not a string, not sure why I thought it behaved like a string. Back to the drawing board, need to figure out how to best copy a wchar_t**. Not that experienced with C++ but I don't think it's possible to get the length of a wchar_t* without passing it in myself but I will have to look into it.
Edit3:终于让它正常工作了.
Finally got it working properly.
这就是我最后得到的:
(inside the data_seg)
std::wstring* grammarData;
(end data_seg)
EXPORT_API void SetGrammarData(wchar_t** strArr, int size)
{
delete[] grammarData;
grammarDataLength = size;
grammarData = new std::wstring[size];
for(int i = 0; i < size; i++)
{
grammarData[i] = std::wstring(strArr[i]);
}
}
EXPORT_API const wchar_t** GetGrammarData()
{
const wchar_t** wct = new const wchar_t*[grammarDataLength];
for(int i = 0;i<grammarDataLength;i++)
{
const wchar_t* t = grammarData[i].c_str();
wct[i] = t;
}
return wct;
}
以为我可以正常工作,这是不正确的.我正在测试一个传回自己的exe文件,但是当通过dll传递到另一个exe文件时,什么也不会通过.现在,我可以使用它了:
Thought I had it working properly, was incorrect. I was testing with an exe passing back to itself but when passing through the dll to another exe nothing would come through. I now have it working:
(inside the data_seg)
wchar_t grammarData[32][50] = {};
(end data_seg)
EXPORT_API void SetGrammarData(wchar_t** strArr, int size)
{
grammarDataLength = size;
for(int i = 0; i < size; i++)
{
wcscpy(grammarData[i], strArr[i]);
}
grammarDataChanged = 1;
}
EXPORT_API wchar_t** GetGrammarData()
{
wchar_t** wct = new wchar_t*[grammarDataLength];
for(int i = 0;i<grammarDataLength;i++)
{
wct[i] = grammarData[i];
}
grammarDataChanged = 0;
return wct;
}
这里可能存在的问题:
- 默认情况下,.NET将封送为
wchar_t
,而不是char
.您需要使用 MarshalAsAttribute 标记输入/输出字符串参数才能使用字符. - 如果要保留字符串,则需要在C函数中复制它们.在函数调用
SetGrammarData
中给您的指针不能保证持久存在.
- By default, .NET will marshal as
wchar_t
, notchar
. You will need to mark your input/output string parameters with MarshalAsAttribute to use char. - If you want to keep the strings, you will need to make copies of them within the C function. The pointers given to you in the function call to
SetGrammarData
are not guaranteed to persist.