storojs72
storojs72

Reputation: 185

Marshalling `byte[]` from .NET to `const u8*` in C

I have this C function:

void ECRYPT_keysetup(ECRYPT_ctx* ctx, const u8* key, u32 keysize, u32 ivsize);

that loads some key bytes to cipher context for example:

{0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0}

I want to pass byte[] from my .NET application to ECRYPT_keysetup. The problem is to marshall const u8*. Any suggestions?

ECRYPT_ctx is a structure:

u32 lfsr[1036];
u32 nfsr[1036];
u32 * nptr;
u32 * lptr;
u32 count;
const u8 * key;
u32 keysize;
u32 ivsize;

I have it's .NET representation:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1036)]
public UInt32[] lfsr;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1036)]
public UInt32[] nfsr;

public UIntPtr nptr;
public UIntPtr lptr;

public UInt32 count;

public byte[] key;

public UInt32 keysize;
public UInt32 ivsize;

May be my mistake is in structure declaration?

Upvotes: 2

Views: 574

Answers (2)

György Kőszeg
György Kőszeg

Reputation: 18013

Solution 1

Map your types and use MarshalAs attribute:

[DllImport("Mylib.dll")]
private static extern void ECRYPT_keysetup(
    [In][MarshalAs(UnmanagedType.LPStruct)] ref ECRYPT_ctx ctx,
    [In][MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]byte[] key,
    uint keysize,
    uint ivsize);

// define whatever you have here (you can use Sequential layout without offsets, too)
[StructLayout(LayoutKind.Explicit)]
private struct ECRYPT_ctx
{
    [FieldOffset(0)]
    internal int someInt32;

    [FieldOffset(4)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    internal byte[] someBytes;
}

Solution 2

Use pointers and marshal everything manually:

[DllImport("Mylib.dll")]
private static extern void ECRYPT_keysetup(IntPtr ctx, IntPtr key, uint keysize, uint ivsize);

In this case you should manage the allocations and disposal manually:

byte[] key = new byte[128]; // use the size you need, of course
IntPtr keyPtr = Marshal.AllocHGlobal(key.Length);
Marshal.Copy(key, 0, keyPtr, key.Length);

ECRYPT_ctx ctx = new ECRYPT_ctx();
IntPtr ctxPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ECRYPT_ctx)));
Marshal.StructureToPtr(ctx, ctxPtr, false);

ECRYPT_keysetup(ctxPtr, keyPtr, (uint)key.Length, ivsize);

Marshal.FreeHGlobal(keyPtr);
Marshal.DestroyStructure(ctxPtr, typeof(ECRYPT_ctx));
Marshal.FreeHGlobal(ctxPtr);

Remark: I considered all parameters as input ones. If you get something back in the buffers, define them as [In, Out], and in Solution 2 use the Marshal.PtrToStructure method to convert the pointer to a managed structure.

Upvotes: 1

i486
i486

Reputation: 6564

Maybe [MarshalAs(UnmanagedType.LPArray)] Byte[] key.

Upvotes: 0

Related Questions