c# - 如何编码指向结构数组指针的指针?

标签 c# .net interop pinvoke marshalling

我的C声明如下:

int myData(uint myHandle, tchar *dataName, long *Time, uint *maxData, DATASTRUCT **data);

typedef struct {
  byte Rel;
  __int64 Time;
  char Validated;
  unsigned char Data[1];
} DATASTRUCT;

我的 C# 声明如下:

[DllImport("myData.dll", EntryPoint = "myData")]
public static extern int myData(uint myHandle, [MarshalAs(UnmanagedType.LPTStr)] string dataName, out long Time, out uint maxData, ref DATASTRUCT[] data);

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DATASTRUCT
{
    public sbyte Rel;
    public long Time;
    public byte Validated;
    public double Data;
}

然后我按如下方式调用托管函数:

string dataToShow = "description";
long Time;
uint maxData; // How many structs will be returned, i.e., how much data is available?
uint myHandle = 1;

DATASTRUCT[] dataInformation = new DATASTRUCT[3]; // Doesn't it matter what I specify as the array size?

myData(myHandle, dataToShow, out Time, out maxData, ref dataInformation);

执行上述函数后,即使有 3 个要返回,也只会成功返回一个结构。为什么会这样?

附加信息;我尝试通过以下方式将指针传递给结构数组的指针:

  • ref DATASTRUCT[] data;//它有效,但它只返回一个结构
  • [Out, MarshalAs(UnmanagedType.LPArray)] DATASTRUCT[] data;//返回带垃圾的已定义结构的数量

据我所知,我可能需要使用 IntPtr 进行一些手动编码,但是我不知道如何实现它,所以任何建议将不胜感激。

最佳答案

好吧,看起来好像是您的 native 库进行了分配,所以实际上您需要做的就是提供一个指针,您可以通过该指针访问分配的数据。

将您的 API 定义更改为(注意,我将 maxData 参数更改为 uint,long 在 .NET 中为 64 位,在 native 中为 32 位。

[DllImportAttribute("myData.dll", EntryPoint = "myData")]
public static extern int myData(uint myHandle, [MarshalAs(UnmanagedType.LPTStr)] string dataName, out uint Time, out uint maxData, out IntPtr pData);

我不太记得最后一个参数是否需要 out 关键字,但我认为是这样。

然后,调用 myData:

uint nAllocs = 0, time = 0;
IntPtr pAllocs = IntPtr.Zero;
myData(1, "description", out time, out nAllocs, out pAllocs);

现在,pAllocs 应该指向非托管内存,将它们编码到托管内存中并不难:

[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct DATASTRUCT
{
    public byte Rel;
    public long Time;
    public byte Validated;
    public IntPtr Data; //pointer to unmanaged string.
}


int szStruct = Marshal.SizeOf(typeof(DATASTRUCT));
DATASTRUCT[] localStructs = new DATASTRUCT[nAllocs];
for(uint i = 0; i < nallocs; i++)
    localStructs[i] = (DATASTRUCT)Marshal.PtrToStructure(new IntPtr(pAllocs.ToInt32() + (szStruct * i)), typeof(DATASTRUCT));

现在你应该有一个局部结构数组。

注意事项 您可能需要将项目设置为编译为 x86,以将 IntPtr 的大小标准化为 4 字节 (DWORD) 而不是 AnyCPU 的默认值 8。

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

相关文章:

使用自定义数据而不是 FormCollection 的 C# UpdateModel

c# - 具有 OR 子句和空值的 lambda 表达式的 LINQ where 子句返回不完整的结果

c# - 如何为从源文件编译的应用程序分配自定义图标?

.net - 以编程方式运行可执行文件 .NET

c# - C# 单元测试套件的单线程

c# - 托管原型(prototype)中的 bool 与 BOOLEAN

c# - Microsoft.Office.Interop.Excel 具有 "bad value"作为默认参数

c# - Linq Where 语句性能缓慢

c# - 为什么 Multiple await 需要像 Task.WhenAll() 一样的时间

c# - 在 C# 中将字符串存储为 UTF8