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

问题描述 投票:1回答:2

我正在尝试将某些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);
c# pinvoke
2个回答
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);

未经测试,应该合理接近。


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;
}
© www.soinside.com 2019 - 2024. All rights reserved.