从C到c#的封送结构
本文关键字:结构 | 更新日期: 2023-09-27 18:09:33
编辑:我过于简化了我的例子…在实际代码中,我在没有正确使用wcscpy_s的情况下将值分配给strMyStringx,所以我只是传递指针,而不是分配值,当值被封送到托管代码中时,指针超出了范围…
我正试图从C到c#编组一个具有三个字符串属性的结构体,但我无法在c#中获得结构体的定义。所有属性打印为垃圾。是我的编组错误还是我的属性类型错误?
我的自定义结构:
typedef struct _MY_STRUCT_STRING {
LPWSTR strMyString1;
LPWSTR strMyString2;
LPWSTR strMyString3;
}MY_STRUCT_STRING, *PMY_STRUCT_STRING;
我的C函数返回指向这个结构体的指针数组:
bool bEnumerateString(OUT LONG &i_arr_size, OUT PMY_STRUCT_STRING* &pArrStringStruct)
{
// [...] function simplified to demonstrate building a pointer to an array of struct*
long i_arr_size = 3
PMY_STRUCT_STRING *ptr_arr_string = (PMY_STRUCT_STRING *)malloc(sizeof(PMY_STRUCT_STRING)* i_arr_size);
for (int i = 0; i < i_arr_size; i++) {
ptr_arr_string[i] = (PMY_STRUCT_STRING)malloc(sizeof(MY_STRUCT_STRING));
ptr_arr_string[i]->strMyString1 = L"String 1"; // This would work. In the real code I was assigning values from another array and mistakenly passed the pointer rather than doing wcscpy_s
ptr_arr_string[i]->strMyString2 = L"String 2";
ptr_arr_string[i]->strMyString3 = L"String 3";
}
pArrStringStruct = ptr_arr_string;
return true;
}
c#: //Import the DLL with my function
[DllImport("My.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "bEnumerateString")]
internal static extern bool bEnumerateString(out long count, out IntPtr pArrStringStruct);
// Define the C# equivalent of the C struct
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct MY_STRUCT_STRING
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)]
public string strMyString1;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)]
public string strMyString1;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)]
public string strMyString1;
}
[...]
// Code to marshal (try... catch etc removed for succinctness)
IntPtr pArrStruct = IntPtr.Zero;
long lCount = 0;
bool bResult = false;
bResult = bEnumerateString(out lCount, out pArrStruct);
if (!bResult)
{
// Marshal to deref pointer
IntPtr[] pArrStructList = new IntPtr[lCount];
for (ulong i = 0; i < (ulong)lCount; i++)
{
pArrStructList[i] = Marshal.ReadIntPtr(pArrStruct, Marshal.SizeOf(typeof(IntPtr)) * (int)i);
}
// Marshal pointers to struct
var lstMyStringStrct = new List<MY_STRUCT_STRING>(pArrStructList.Length);
foreach (IntPtr ptr in pArrStructList)
{
lstMyStringStrct.Add((MY_STRUCT_STRING)Marshal.PtrToStructure(ptr, typeof(MY_STRUCT_STRING)));
}
// Enumerate struct
foreach (MY_STRUCT_STRING myStr in lstMyStringStrct)
{
// All of these outputs are garbage
Console.WriteLine("strMyString1: " + myStr.strMyString1);
Console.WriteLine("strMyString2: " + myStr.strMyString2);
Console.WriteLine("strMyString3: " + myStr.strMyString3);
}
}
我看到一个问题。你的c++结构使用LPWSTR(指针),而你的c#代码期望固定大小的字符数组。
从
更改字符串[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 8)]
public string strMyString1;
,当c++结构定义为
时使用:char strMyString1[8];
:
[MarshalAsAttribute(UnmanagedType.LPWStr)]
public string strMyString1;