如何在PowerShell中创建含普通数组的非托管结构体并正确赋值?
PowerShell处理C风格结构体数组字段及序列化方案
问题根源
- 数组未初始化:.NET结构体中的引用类型(如数组)默认初始化为
null,直接索引赋值会抛出"Cannot index into a null array"错误。 - 类型不匹配:原代码中
Int16/Int32与C结构体的uint16_t类型不对应,会导致内存布局偏差,必须改用UInt16匹配无符号16位整数。
修复数组初始化问题
先为thresholds数组分配指定大小的实例,再进行元素赋值:
$typeCode = @' using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential, Pack = 1)] [Serializable] public struct MyConfig { public UInt16 level; // 匹配C的uint16_t [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public UInt16[] thresholds; // 匹配C的uint16_t[16] } '@ Add-Type -TypeDefinition $typeCode $config = New-Object MyConfig $config.level = 1 # 先初始化数组 $config.thresholds = New-Object UInt16[] 16 # 逐个赋值 $config.thresholds[0] = 1 $config.thresholds[1] = 2 # ... 其他元素按需赋值
将结构体序列化为二进制Blob并写入文件
使用System.Runtime.InteropServices.Marshal类完成结构体到字节数组的转换,再写入文件:
# 计算结构体大小 $structSize = [System.Runtime.InteropServices.Marshal]::SizeOf($config) # 分配非托管内存 $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($structSize) try { # 将结构体拷贝到非托管内存 [System.Runtime.InteropServices.Marshal]::StructureToPtr($config, $ptr, $false) # 从非托管内存读取字节数组 $byteArray = New-Object byte[] $structSize [System.Runtime.InteropServices.Marshal]::Copy($ptr, $byteArray, 0, $structSize) # 写入文件 [System.IO.File]::WriteAllBytes("MyConfig.bin", $byteArray) } finally { # 释放非托管内存,避免泄漏 [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }
完整示例代码
$typeCode = @' using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential, Pack = 1)] [Serializable] public struct MyConfig { public UInt16 level; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public UInt16[] thresholds; } '@ Add-Type -TypeDefinition $typeCode # 初始化结构体 $config = New-Object MyConfig $config.level = 1 $config.thresholds = New-Object UInt16[] 16 # 填充数组数据 for ($i = 0; $i -lt 16; $i++) { $config.thresholds[$i] = [UInt16]($i + 1) } # 序列化并写入文件 $structSize = [System.Runtime.InteropServices.Marshal]::SizeOf($config) $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($structSize) try { [System.Runtime.InteropServices.Marshal]::StructureToPtr($config, $ptr, $false) $byteArray = New-Object byte[] $structSize [System.Runtime.InteropServices.Marshal]::Copy($ptr, $byteArray, 0, $structSize) [System.IO.File]::WriteAllBytes("MyConfig.bin", $byteArray) Write-Host "结构体已成功写入MyConfig.bin" } finally { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) }
内容的提问来源于stack exchange,提问作者Richard W
相关产品推荐
相关产品推荐

