将非托管结构编组为 C#

问题描述 投票:0回答:1

如何将这个非托管结构转换为 C#。

typedef struct _EC_VARIANT {
  union {
    BOOL                            BooleanVal;
    UINT32                          UInt32Val;
    ULONGLONG                       DateTimeVal;
    LPCWSTR                         StringVal;
    PBYTE                           BinaryVal;
    BOOL                            *BooleanArr;
    INT32                           *Int32Arr;
    LPWSTR                          *StringArr;
    EC_OBJECT_ARRAY_PROPERTY_HANDLE PropertyHandleVal;
  };
  DWORD Count;
  DWORD Type;
} EC_VARIANT, *PEC_VARIANT;

文档:https://learn.microsoft.com/ru-ru/windows/win32/api/evcoll/ns-evcoll-ec_variant 我尝试这个代码:

uint get = Internals.EcOpenSubscription("adfs", (uint)WecAcessTypes.EC_READ_ACCESS, (uint)WecFlags.EC_OPEN_EXISTING);
Console.WriteLine($"addr :{get}");
byte[] some = new byte[16];
uint a = 0;
bool success = Internals.EcGetSubscriptionProperty(get, (uint)EC_SUBSCRIPTION_PROPERTY_ID.EcSubscriptionEventSources, 0, 128, some, out a);
if (!success)
{
    Console.WriteLine("err EcSubscriptionEventSources");
    Console.ReadKey();
    return;
}
foreach (byte b in some)
{
    Console.Write(b);
}
GCHandle gCHandle = GCHandle.Alloc(some, GCHandleType.Pinned);
EC_VARIANT eC = (EC_VARIANT)Marshal.PtrToStructure(gCHandle.AddrOfPinnedObject(), typeof(EC_VARIANT));
Console.WriteLine($"\n{eC.Type} {eC.EC_OBJECT_ARRAY_PROPERTY_HANDLE}");
Console.WriteLine($"length {a}");
Console.ReadKey();

我的结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct EC_VARIANT
{
    public uint BooleanVal;
    public uint UInt32Val;
    public ulong DateTimeVal;
    public IntPtr StringVal;
    public IntPtr BinaryVal;
    public IntPtr BoolArr;
    public IntPtr Int32Arr;
    public IntPtr StringArr;
    public int EC_OBJECT_ARRAY_PROPERTY_HANDLE;
    public int Type;
    public int Count;
}

我尝试使用 LayoutKind.Explicit 并以不同的方式排列字段,但无济于事

c# windows winapi marshalling unmanaged
1个回答
0
投票

您可以使用

CsWin32
源生成器来获取相关函数/结构/枚举/等的所有定义。

使用方法:

  • 安装

    CsWin32
    nuget 包:
    dotnet add package Microsoft.Windows.CsWin32
    Install-Package Microsoft.Windows.CsWin32

  • NativeMethods.txt
    文件添加到项目的根目录中(与
    .csproj
    位于同一文件夹中)。

  • 将以下内容放入

    NativeMethods.txt

    EC_VARIANT
    EcGetSubscriptionProperty
    EcOpenSubscription
    EC_*
    EC_VARIANT_TYPE
    

    这将告诉生成器为所有列出的实体生成定义。

  • 在您的代码中使用如下(我重写了您的示例并稍微简化了它)。

      using Windows.Win32.System.EventCollector;
      using static Windows.Win32.PInvoke;
    
      var get = EcOpenSubscription("adfs", EC_READ_ACCESS, EC_OPEN_EXISTING);
      Console.WriteLine($"addr :{get}");
      var some = new EC_VARIANT();
      var success = EcGetSubscriptionProperty(get,
          EC_SUBSCRIPTION_PROPERTY_ID.EcSubscriptionEventSources, 0, 128,
          ref some, out var used);
    
      if (!success)
      {
          Console.WriteLine("Failed to get subscription property");
          return;
      }
    
      Console.WriteLine($"Type: {some.Type}");
      var union = some.Anonymous;
      var strVal = (EC_VARIANT_TYPE)some.Type switch
      {
          EC_VARIANT_TYPE.EcVarTypeNull => "null",
          EC_VARIANT_TYPE.EcVarTypeBoolean => union.BooleanVal.ToString(),
          EC_VARIANT_TYPE.EcVarTypeUInt32 => union.UInt32Val.ToString(),
          EC_VARIANT_TYPE.EcVarTypeDateTime => union.DateTimeVal.ToString(),
          EC_VARIANT_TYPE.EcVarTypeString => union.StringVal.ToString(),
          EC_VARIANT_TYPE.EcVarObjectArrayPropertyHandle => union.PropertyHandleVal.ToString(),
          _ => throw new ArgumentOutOfRangeException()
      };
      Console.WriteLine($"Value: {strVal}");
    
© www.soinside.com 2019 - 2024. All rights reserved.