Search code examples
c#pinvoke

How to Convert CRYPT_CONTEXTS structure to C# PInvoke


I am trying to convert some WinAPI stuff to C#. I'm not very good at it, and these particular functions are not on pinvoke.net (which is probably another sign that I shouldn't be doing this, but I am anyway.)

The structure that I am trying to implement is here: http://technet.microsoft.com/en-ca/aa376218(v=vs.80)

typedef struct _CRYPT_CONTEXTS {
  ULONG cContexts;
  PWSTR rgpszContexts;
} CRYPT_CONTEXTS, *PCRYPT_CONTEXTS;

You can find this in bcrypt.h. I'm wanting to use this (and other) structures in my pursuit of ultimately using the Schannel/SSPI API. The reason I feel the need to use the native API for this is that the managed C# for SSL streams don't give me the flexibility to choose my own cipher suites, etc.

Edit: Adding the signature that I'm using for BCryptEnumContexts (which is probably wrong):

[DllImport("Bcrypt.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern NTSTATUS BCryptEnumContexts([In] ulong dwTable, ref int pcbBuffer, ref IntPtr ppBuffer);

Solution

  • It is a variable-sized struct, always difficult. The best way to deal with it is to not declare it at all, the api is willing the allocate the memory itself. So declare the 3rd argument of BCryptEnumContexts as ref IntPtr. Then read the result with code similar like this:

    var result = new List<string>();
    int size = 0;
    IntPtr ptr = IntPtr.Zero;
    int err = BCryptEnumContexts(table, ref size, ref ptr);
    if (err != 0) throw new Win32Exception(err);
    int cnt = Marshal.ReadInt32(ptr);
    int offs = IntPtr.Size;           // Note alignment requirement
    for (int ix = 0; ix < cnt; ++ix) {
        var ctxptr = new IntPtr(ptr.ToInt64() + offs + ix * IntPtr.Size);
        result.Add(Marshal.PtrToStringUni(ctxptr));
    }
    BCryptFreeBuffer(ptr);
    

    Untested, ought to be reasonably close.