我从C#调用一个C dll,找不到正确的方法来编组返回的结构。
在执行编组的ConvertConfigStructToDico中,我正确地读取了第一个size_t字段,但在使用我的ConvertStringArray读取char **时崩溃了。然而我在'char **方法()'上测试后者并且它有效,所以我想知道我是否没有错误地将我的指针推进到行上的错误位置 IntPtr p = args + Marshal.SizeOf( typeof运算(ULONG));
如果有人可以就此事提供帮助,我将不胜感激......
C方法(外部方法,我不能改变它):
// By design, the returned length is always 1.
configStruct *Config_enumerate(size_t *length);
typedef struct
{
size_t size;
char **keys;
char **vals;
} configStruct;
我的C#代码:
public static List<Dictionary<string, string>> GetConfig(string args = "")
{
// By design, the returned length will always be 1.
ulong length = 0;
IntPtr configStructArray = Config_enumerate(ref length);
var list = new List<Dictionary<string, string>>((int)length);
// Correct because length is always 1.
var dico = ConvertConfigStructToDico(configStructArray);
list.Add(dico);
return list;
}
[DllImport("external", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr Config_enumerate(ref ulong length);
static Dictionary<string, string> ConvertConfigStructToDico(IntPtr args)
{
//typedef struct
//{
// size_t size;
// char** keys;
// char** vals;
//}
//configStruct;
// Works fine, I get the right size.
ulong size = (ulong)Marshal.ReadInt64(args); //size_t is ulong in Win64 and uint in x86
// Advance pointer to next field
IntPtr p = args + Marshal.SizeOf(typeof(ulong));
// BUG: ConvertStringArray will incorrectly read the first string then crash (access violation). Is my point "args" pointer incorrect?
string[] keys = ConvertStringArray(p, (uint)size); // This frees unmanaged memory.
p += (int)size * IntPtr.Size;
string[] values = ConvertStringArray(p, (uint)size); // This frees unmanaged memory.
Marshal.FreeCoTaskMem(args);
Dictionary<string, string> dico = new Dictionary<string, string>((int)size);
for (int i = (int)size - 1; i >= 0; i--)
dico[keys[i]] = values[i];
return dico;
}
/// <summary>
/// Converts an unmanaged string array specified by its pointer, into an array of managed <see cref="String"/>, and cleans up unmanaged memory afterwards.
/// </summary>
/// <param name="args">The pointer to the unmanaged string array</param>
/// <param name="length">The number of items in the unmanaged string array</param>
/// <returns></returns>
static string[] ConvertStringArray(IntPtr args, uint length)
{
string[] array = new string[length];
IntPtr p = args;
for (int i = 0; i < length; i++)
{
var strPtr = (IntPtr)Marshal.PtrToStructure(p, typeof(IntPtr));
array[i] = Marshal.PtrToStringAnsi(strPtr);
Marshal.FreeCoTaskMem(strPtr);
p += IntPtr.Size;
}
Marshal.FreeCoTaskMem(args);
return array;
}