如何将CRYPT_CONTEXTS结构转换为C#PInvoke

时间:2014-08-05 13:39:12

标签: c# pinvoke

我正在尝试将一些WinAPI转换为C#。我不是很擅长这些特殊功能并不在pinvoke.net上(这可能是我不应该这样做的另一个标志,但无论如何我都是。)

我想要实现的结构是:http://technet.microsoft.com/en-ca/aa376218(v=vs.80)

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

你可以在bcrypt.h中找到它。我想在最终使用Schannel / SSPI API时使用这个(和其他)结构。我认为需要使用本机API的原因是SSL流的托管C#不允许我灵活地选择我自己的密码套件等。

编辑:添加我用于BCryptEnumContexts的签名(这可能是错误的):

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

2 个答案:

答案 0 :(得分:2)

它是一个可变大小的结构,总是很难。处理它的最好方法是不要声明它,api愿意分配内存本身。因此,将BCryptEnumContexts的第三个参数声明为ref IntPtr。然后使用类似的代码读取结果:

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);

未经测试,应该相当接近。

答案 1 :(得分:0)

这是工作版本

[System.Runtime.InteropServices.DllImport("Bcrypt.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern uint BCryptEnumContexts(uint dwTable, ref int pcbBuffer, ref IntPtr ppBuffer);


[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct CRYPT_CONTEXTS
{
    public uint cContexts;
    public IntPtr rgpszContexts;
}


const uint CRYPT_LOCAL = 0x00000001;
const uint NCRYPT_SCHANNEL_INTERFACE = 0x00010002;
const uint CRYPT_PRIORITY_TOP = 0x00000000;
const uint CRYPT_PRIORITY_BOTTOM = 0xFFFFFFFF;

private System.Collections.Generic.List<string> GetContexts(){
  var list = new List<string>();
  int size = 0;
  IntPtr ptr = IntPtr.Zero;
  var err = BCryptEnumContexts(CRYPT_LOCAL, ref size, ref ptr);
  if (err == 0) {
    var contexts = 
        (CRYPT_CONTEXTS)System.Runtime.InteropServices.Marshal
          .PtrToStructure(ptr, typeof(CRYPT_CONTEXTS));
    IntPtr pStr = contexts.rgpszContexts;

    for (int i = 0; i < contexts.cContexts; i++){
        list.Add(
          System.Runtime.InteropServices.Marshal.PtrToStringUni(
            System.Runtime.InteropServices.Marshal.ReadIntPtr(pStr)));
        pStr += IntPtr.Size;
    }
  }
  BCryptFreeBuffer(ptr);
  return list;
}