如何将这个非托管结构转换为 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 并以不同的方式排列字段,但无济于事
您可以使用
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}");