Reputation: 3
how can I translate this unmanaged structure into 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;
docs: https://learn.microsoft.com/ru-ru/windows/win32/api/evcoll/ns-evcoll-ec_variant i try this code:
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();
my struct:
[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;
}
I tried to use LayoutKind.Explicit and arrange the fields differently but to no avail
Upvotes: -1
Views: 91
Reputation: 139187
The equivalent C# structure would be this:
public partial struct EC_VARIANT
{
[StructLayout(LayoutKind.Explicit)]
public struct EC_VARIANT_UNION
{
[FieldOffset(0)]
public bool BooleanVal;
[FieldOffset(0)]
public uint UInt32Val;
[FieldOffset(0)]
public ulong DateTimeVal;
[FieldOffset(0)]
public IntPtr StringVal;
[FieldOffset(0)]
public IntPtr BinaryVal;
[FieldOffset(0)]
public IntPtr BooleanArr;
[FieldOffset(0)]
public IntPtr Int32Arr;
[FieldOffset(0)]
public IntPtr StringArr;
[FieldOffset(0)]
public IntPtr PropertyHandleVal;
}
public EC_VARIANT_UNION Anonymous;
public uint Count;
public uint Type;
}
Upvotes: 1
Reputation: 4696
You can use the CsWin32
source generator to get all the definitions for related functions/structs/enums/etc.
How to use:
install the CsWin32
nuget package: dotnet add package Microsoft.Windows.CsWin32
or Install-Package Microsoft.Windows.CsWin32
add the NativeMethods.txt
file in the root of the project (in the same folder as the .csproj
).
Place the following content in the NativeMethods.txt
:
EC_VARIANT
EcGetSubscriptionProperty
EcOpenSubscription
EC_*
EC_VARIANT_TYPE
This will tell the generator to generate definitions for the all listed entities.
use in your code as following (I rewrite your sample and slightly simplified it).
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}");
Note: I'm not sure that the parameters for the EcGetSubscriptionProperty
are correct. The most suspicious is the 128
as the buffer size. You may try to use the Marshal.SizeOf(some)
or something similar instead.
Upvotes: 0