将嵌套结构从 C# 编组到 C++
Marshaling nested structures from C# to C++
我在 C++ 中有以下类型:
typedef void* keychain_handle;
typedef struct {
const char* keyHolderName;
unsigned int numKeys;
key* keys;
} key_holder;
typedef struct {
const char* keyName;
unsigned int keySize;
} key;
我有以下方法:
int createKeyChain(
int id,
key_holder* keyHolders,
keychain_handle* handle);
我需要我的 C# 创建带密钥的密钥持有者,将其发送到 C++ 代码并接收句柄。
这是我的 C# 代码:
/* Structs */
[StructLayout(LayoutKind.Sequential)]
public struct Key
{
public string key;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyHolder
{
public string name;
public uint keys;
public IntPtr keys;
}
/* Sync API */
[DllImport("keys.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern uint createKeyChain(uint id, KeyHolder[] keyHolders, ref IntPtr handle);
Key[] myKeys = new Key[1];
myKeys[0] = new Key { key = "tst", size = 5 };
KeyHolder keyHolder = new DllWrapper.KeyHolder
{
name = "tst123",
items = 1,
keys = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (Key))*myKeys.Length)
};
IntPtr c = new IntPtr(keyHolder.keys.ToInt32());
for (int i = 0; i < myKeys.Length; i++)
{
Marshal.StructureToPtr(myKeys[i], c, false);
c = new IntPtr(c.ToInt32() + Marshal.SizeOf(typeof(Key)));
}
Marshal.StructureToPtr(c, keyHolder.keys, false);
IntPtr handle = IntPtr.Zero;
var ret = createKeyChain(111, new []{keyHolder}, ref handle);
除了 Key 对象中的内部字符串已损坏外,一切正常。我怀疑是 StructureToPtr 破坏了它。如何让字符串显示在 C++ 端?
谢谢。
您仍然需要告诉 .NET 将字符串编组为 PChars:
[StructLayout(LayoutKind.Sequential)]
public struct Key
{
[MarshalAs(UnmanagedType.LPStr)]
public string key;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyHolder
{
[MarshalAs(UnmanagedType.LPStr)]
public string name;
public uint keyCount;
public Key[] keys;
}
如果不对非托管代码进行更改,您别无选择,只能自行编组。看起来像这样:
[StructLayout(LayoutKind.Sequential)]
public struct _Key
{
public IntPtr keyName;
public uint keySize;
}
[StructLayout(LayoutKind.Sequential)]
public struct _KeyHolder
{
public string name;
public uint numKeys;
public IntPtr keys;
}
public struct Key
{
public string keyName;
public uint keySize;
}
public static _KeyHolder CreateKeyHolder(string name, Key[] keys)
{
_KeyHolder result;
result.name = name;
result.numKeys = (uint)keys.Length;
result.keys = Marshal.AllocHGlobal(keys.Length * Marshal.SizeOf(typeof(_Key)));
IntPtr ptr = result.keys;
for (int i = 0; i < result.numKeys; i++)
{
_Key key;
key.keyName = Marshal.StringToHGlobalAnsi(keys[i].keyName);
key.keySize = keys[i].keySize;
Marshal.StructureToPtr(key, ptr, false);
ptr += Marshal.SizeOf(typeof(_Key));
}
return result;
}
public static void DestroyKeyHolder(_KeyHolder keyHolder)
{
IntPtr ptr = keyHolder.keys;
for (int i = 0; i < keyHolder.numKeys; i++)
{
_Key key = (_Key)Marshal.PtrToStructure(ptr, typeof(_Key));
Marshal.FreeHGlobal(key.keyName);
ptr += Marshal.SizeOf(typeof(_Key));
}
Marshal.FreeHGlobal(keyHolder.keys);
}
我在 C++ 中有以下类型:
typedef void* keychain_handle;
typedef struct {
const char* keyHolderName;
unsigned int numKeys;
key* keys;
} key_holder;
typedef struct {
const char* keyName;
unsigned int keySize;
} key;
我有以下方法:
int createKeyChain(
int id,
key_holder* keyHolders,
keychain_handle* handle);
我需要我的 C# 创建带密钥的密钥持有者,将其发送到 C++ 代码并接收句柄。
这是我的 C# 代码:
/* Structs */
[StructLayout(LayoutKind.Sequential)]
public struct Key
{
public string key;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyHolder
{
public string name;
public uint keys;
public IntPtr keys;
}
/* Sync API */
[DllImport("keys.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern uint createKeyChain(uint id, KeyHolder[] keyHolders, ref IntPtr handle);
Key[] myKeys = new Key[1];
myKeys[0] = new Key { key = "tst", size = 5 };
KeyHolder keyHolder = new DllWrapper.KeyHolder
{
name = "tst123",
items = 1,
keys = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (Key))*myKeys.Length)
};
IntPtr c = new IntPtr(keyHolder.keys.ToInt32());
for (int i = 0; i < myKeys.Length; i++)
{
Marshal.StructureToPtr(myKeys[i], c, false);
c = new IntPtr(c.ToInt32() + Marshal.SizeOf(typeof(Key)));
}
Marshal.StructureToPtr(c, keyHolder.keys, false);
IntPtr handle = IntPtr.Zero;
var ret = createKeyChain(111, new []{keyHolder}, ref handle);
除了 Key 对象中的内部字符串已损坏外,一切正常。我怀疑是 StructureToPtr 破坏了它。如何让字符串显示在 C++ 端?
谢谢。
您仍然需要告诉 .NET 将字符串编组为 PChars:
[StructLayout(LayoutKind.Sequential)]
public struct Key
{
[MarshalAs(UnmanagedType.LPStr)]
public string key;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyHolder
{
[MarshalAs(UnmanagedType.LPStr)]
public string name;
public uint keyCount;
public Key[] keys;
}
如果不对非托管代码进行更改,您别无选择,只能自行编组。看起来像这样:
[StructLayout(LayoutKind.Sequential)]
public struct _Key
{
public IntPtr keyName;
public uint keySize;
}
[StructLayout(LayoutKind.Sequential)]
public struct _KeyHolder
{
public string name;
public uint numKeys;
public IntPtr keys;
}
public struct Key
{
public string keyName;
public uint keySize;
}
public static _KeyHolder CreateKeyHolder(string name, Key[] keys)
{
_KeyHolder result;
result.name = name;
result.numKeys = (uint)keys.Length;
result.keys = Marshal.AllocHGlobal(keys.Length * Marshal.SizeOf(typeof(_Key)));
IntPtr ptr = result.keys;
for (int i = 0; i < result.numKeys; i++)
{
_Key key;
key.keyName = Marshal.StringToHGlobalAnsi(keys[i].keyName);
key.keySize = keys[i].keySize;
Marshal.StructureToPtr(key, ptr, false);
ptr += Marshal.SizeOf(typeof(_Key));
}
return result;
}
public static void DestroyKeyHolder(_KeyHolder keyHolder)
{
IntPtr ptr = keyHolder.keys;
for (int i = 0; i < keyHolder.numKeys; i++)
{
_Key key = (_Key)Marshal.PtrToStructure(ptr, typeof(_Key));
Marshal.FreeHGlobal(key.keyName);
ptr += Marshal.SizeOf(typeof(_Key));
}
Marshal.FreeHGlobal(keyHolder.keys);
}