gpt4 book ai didi

c# - 编码结构字段,它是指向结构数组的指针

转载 作者:太空宇宙 更新时间:2023-11-03 13:12:32 24 4
gpt4 key购买 nike

我花了一些时间思考这个问题,我需要你的帮助。我的问题看起来与 Stack Overflow 上的许多问题有些相似,我查看了其中的许多问题,但仍然没有找到答案。

我需要编码一个结构字段,它是一个指向结构数组的指针。问题是我需要从用 C 编写的遗留外部库接收这个结构。我发现了很多关于通过使用 Marshal.AllocHGlobalMarshal.StructureToPtr 锁定正确大小的内存来传递结构作为指针的提示。我还找到了如何接收作为指针返回的结构的指南:您可以使用 [MarshalAs] 修饰符。不幸的是,这无济于事,因为大多数 [MarshalAs] 修饰符似乎不适用于结构字段。

在下面的示例中,我可以分两步接收所需的数据:

  1. 接收MiddleStruct数据和其中的指针
  2. 使用PtrToStructure读取指向的数据

问题是我想确保垃圾收集器不会修改接收到的指针引用的内存。有什么方法可以一步读取 InnerStructure 中的数据吗?

C 结构

typedef struct OuterStruct {
MiddleStruct mStruct;
} OuterStruct;

typedef struct MiddleStruct {
int count;
InnerStruct FAR *innerData;
} MiddleStruct;

typedef struct InnerStruct {
int number;
char data[64];
} InnerStruct;

C# 结构

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public class OuterStruct
{
public MiddleStruct mStruct;
};

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct MiddleStruct
{
public int count;
public IntPtr pIStruct; //pointer to array of InnerStruct
}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct InnerStruct
{
int number;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public bytes[] data;
};

函数

[DllImport("legacy.dll", CharSet = CharSet.Ansi)]
public static extern short getData([In, Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(myCustomMarshaler))] OuterStruct sStruct);

例子

OuterStruct oStruct;
getData(out oStruct);
int count = oStruct.mStruct.count;
IntPtr pIStruct = oStruct.mStruct.pIStruct;
InnerStruct[] iStructArray = new InnerStruct[count];
int infoSize = Marshal.SizeOf(new iStructArray());
for (int i = 0; i < count; i++)
{
IntPtr targetPtr = new IntPtr(pIStruct.ToInt32() + infoSize * i);
iStructArray[i] = (InnerStruct)Marshal.PtrToStructure(targetPtr, typeof(InnerStruct));
}
WriteLine(iStructArray);

更新:

我已经创建了自定义编码器,但我想不出返回值的方法。知道数组是引用类型,有什么方法可以将 intPtr 转换为数组吗?我尝试使用 object 而不是 intPtr 并相应地转换它,但没有用。

public class myCustomMarshaler : ICustomMarshaler
{
[ThreadStatic]
private OuterStruct marshaledObj;

private static myCustomMarshaler marshaler = null;
public static ICustomMarshaler GetInstance(string cookie)
{
if (marshaler == null)
{
marshaler = new myCustomMarshaler();
}
return marshaler;
}

#region ICustomMarshaler Members
public int GetNativeDataSize()
{
return Marshal.SizeOf(typeof(OuterStruct));
}

public object MarshalNativeToManaged(System.IntPtr pNativeData)
{
Marshal.PtrToStructure(pNativeData, this.marshaledObj);
int count = this.marshaledObj.mStruct.count;
IntPtr pIStruct = this.marshaledObj.mStruct.pIStruct;
InnerStruct[] iStructArray = new InnerStruct[count];
int dataSize = Marshal.SizeOf(new InnerStruct());
for (int i = 0; i < count; i++)
{
iStructArray[i] = (InnerStruct)Marshal.PtrToStructure(new IntPtr(pIStruct.ToInt32() + dataSize * i), typeof(InnerStruct));
}

//*** how do I include iStructArray in return?

return this.marshaledObj;
}

public System.IntPtr MarshalManagedToNative(object managedObj)
{
if (!(managedObj is OuterStruct))
{
throw new ArgumentException("Specified object is not a OuterStruct object.", "managedObj");
}
else
{
this.marshaledObj = (OuterStruct)managedObj;
}
IntPtr ptr = Marshal.AllocHGlobal(this.GetNativeDataSize());
if (ptr == IntPtr.Zero)
{
throw new Exception("Unable to allocate memory to.");
}
Marshal.StructureToPtr(this.marshaledObj, ptr, false);

return ptr;
}

public void CleanUpManagedData(object managedObj)
{
}

public void CleanUpNativeData(System.IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}

#endregion
}

最佳答案

我解决了我的问题,方法是使用另一个类将它包装在 oStruct 周围并添加一个字典字段以返回额外的数据。虽然它对我有用,但使用起来非常不方便,而且扩展性不好。无论如何,也许这对某人有用:

包装类

public class WrapperClass
{
public OuterStruct oStruct;
public Dictionary<string, object> auxData;

public WrapperClass()
{
this.oStruct = new OuterStruct();
this.auxData = new Dictionary<string, object>();
}
}

自定义编码器

public class myCustomMarshaler : ICustomMarshaler
{
[ThreadStatic]
private WrapperClass marshaledObj;

private static myCustomMarshaler marshaler = null;
public static ICustomMarshaler GetInstance(string cookie)
{
if (marshaler == null)
{
marshaler = new myCustomMarshaler();
}
return marshaler;
}

public int GetNativeDataSize()
{
return Marshal.SizeOf(typeof(OuterStruct));
}

public object MarshalNativeToManaged(System.IntPtr pNativeData)
{
Marshal.PtrToStructure(pNativeData, this.marshaledObj);
int count = this.marshaledObj.mStruct.count;
IntPtr pIStruct = this.marshaledObj.mStruct.pIStruct;

InnerStruct[] iStructArray = new InnerStruct[count];
int dataSize = Marshal.SizeOf(new InnerStruct());
for (int i = 0; i < count; i++)
{
iStructArray[i] = (InnerStruct)Marshal.PtrToStructure(new IntPtr(pIStruct.ToInt32() + dataSize * i), typeof(InnerStruct));
}
// Add additional data to wrapper
this.marshaledObj.auxData.Add("iStructArray", iStructArray);
return this.marshaledObj;
}

public System.IntPtr MarshalManagedToNative(object managedObj)
{
if (!(managedObj is WrapperClass))
{
throw new ArgumentException("Specified object is not a WrapperClass object.", "managedObj");
}
else
{
this.marshaledObj = (WrapperClass)managedObj;
}
IntPtr ptr = Marshal.AllocHGlobal(this.GetNativeDataSize());
if (ptr == IntPtr.Zero)
{
throw new Exception("Unable to allocate memory to.");
}
Marshal.StructureToPtr(this.marshaledObj.oStruct, ptr, false);

return ptr;
}

public void CleanUpManagedData(object managedObj)
{
}

public void CleanUpNativeData(System.IntPtr pNativeData)
{
Marshal.FreeHGlobal(pNativeData);
}
}

用法

[DllImport("legacy.dll", CharSet = CharSet.Ansi)]
public static extern short getData([In, Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(myCustomMarshaler))] OuterStruct wrapper);

关于c# - 编码结构字段,它是指向结构数组的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27860098/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com