问题
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.
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.
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);
}
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;
}
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" });
and what comes back out the other side is:
stringArray[0] =
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.
Edit: 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.
new code:
(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;
}
Now I end up with this output:
stringArray[0] = 8
stringArray[1] =
The C# code has remained the same. Is there something else I need to change that I am missing?
Edit2: 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.
Here is what I ended up with:
(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;
}
Edit4: 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;
}
回答1:
Couple of possible problems here:
- 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.
来源:https://stackoverflow.com/questions/16447506/pass-an-array-of-strings-from-c-sharp-to-a-c-dll-and-back-again