我正在尝试将一些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);
答案 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;
}