C# p/invoke Secur32.dll 问题

标签 c# pinvoke sspi

我正在尝试包装 Secur32.dll 的 EnumerateSecurityPackages函数声明如下:

SECURITY_STATUS SEC_Entry EnumerateSecurityPackages(
  __in  PULONG pcPackages,
  __in  PSecPkgInfo *ppPackageInfo
);

我有以下 C# 代码,但当我尝试运行它时,出现 AccessViolationException。在调试器中,pcPackages 变量确实设置正确,但我认为我对 SecPkgInfos 数组做错了。

[StructLayout(LayoutKind.Sequential)]
public struct SecPkgInfo
{
    public ulong fCapabilities;
    public ushort wVersion;
    public ushort wRPCID;
    public ulong cbMaxToken;
    public string Name;
    public string Comment;
}

[DllImport("Secur32.dll")]
public extern static int EnumerateSecurityPackages(
    ref ulong pcPackages,
    ref SecPkgInfo[] ppPackageInfo
);

///Calling code
ulong count = 0;
SecPkgInfo[] buffer = new SecPkgInfo[256];
EnumerateSecurityPackages(ref count, ref buffer);

知道我做错了什么吗?

最佳答案

尝试一下这段代码,它是从 VB.Net(我的母语)转换而来的,但在 C# 中运行得很好。只需调用 Call_EnumerateSecurityPackages(),它就会为您返回一个列表。

    public static List<SecPkgInfo> Call_EnumerateSecurityPackages()
    {
        //Will hold the number of security packages found
        UInt32 count = 0;

        //Will hold a pointer to our array
        IntPtr SourcePoint = IntPtr.Zero;

        //Call function
        int MSG = EnumerateSecurityPackages(ref count, ref SourcePoint);
        //See if there was an error
        if (MSG == 0)
        {
            //Create a copy of our pointer so that we can clear it later
            IntPtr ArrayPtr = new IntPtr(SourcePoint.ToInt32());
            //The type of our structure
            Type T = typeof(SecPkgInfo);
            //The size of our structure
            int ObjSize = Marshal.SizeOf(T);
            //We'll store our information in a standard list object
            List<SecPkgInfo> SecPackages = new List<SecPkgInfo>();

            //Create a loop and increment our pointer by the size of the SecPkgInfo structure, effectively walking the array
            for (ulong I = 0; I <= (count - 1); I++)
            {
                //This converts the current bytes at the pointer to the given structure
                SecPackages.Add((SecPkgInfo)Marshal.PtrToStructure(ArrayPtr, T));

                //Increment our pointer by the size of the structure
                ArrayPtr = IntPtr.Add(ArrayPtr, ObjSize);
            }

            //Cleanup our pointer
            MSG = FreeContextBuffer(ref SourcePoint);

            //Make sure cleanup worked
            if (MSG == 0)
            {
                //Return our values
                return SecPackages;
            }
            else
            {
                //Do something better with the error code here
                throw new ApplicationException("Error cleaning up pointer");
            }
        }
        else
        {
            //Do something better with the error code here
            throw new ApplicationException("Error calling native function");
        }

    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SecPkgInfo
    {
        //ulong is 32 bit so we need to use a 32 bit int
        public UInt32 fCapabilities;
        //ushort is 16 bit 
        public UInt16 wVersion;
        public UInt16 wRPCID;
        public UInt32 cbMaxToken;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
        public string Name;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
        public string Comment;
    }

    [DllImport("Secur32.dll")]
    public static extern int EnumerateSecurityPackages(ref UInt32 pcPackages, ref IntPtr ppPackageInfo);

    [DllImport("Secur32.dll")]
    public static extern int FreeContextBuffer(ref IntPtr pvContextBuffer);

为了将来使用,这里是 VB 版本:

Public Shared Function Call_EnumerateSecurityPackages() As List(Of SecPkgInfo)
    ''//Will hold the number of security packages found
    Dim count As UInt32 = 0

    ''//Will hold a pointer to our array
    Dim SourcePoint As IntPtr

    ''//Call function
    Dim MSG = EnumerateSecurityPackages(count, SourcePoint)
    ''//See if there was an error
    If MSG = 0 Then
        ''//Create a copy of our pointer so that we can clear it later
        Dim ArrayPtr As New IntPtr(SourcePoint.ToInt32())
        ''//The type of our structure
        Dim T = GetType(SecPkgInfo)
        ''//The size of our structure
        Dim ObjSize = Marshal.SizeOf(T)
        ''//We will store our information in a standard list object
        Dim SecPackages As New List(Of SecPkgInfo)

        ''//Create a loop and increment our pointer by the size of the SecPkgInfo structure, effectively walking the array
        For I = 0 To (count - 1)
            ''//This converts the current bytes at the pointer to the given structure
            SecPackages.Add(CType(Marshal.PtrToStructure(ArrayPtr, T), SecPkgInfo))
            ''//Increment our pointer by the size of the structure
            ArrayPtr = IntPtr.Add(ArrayPtr, ObjSize)
        Next

        ''//Cleanup our pointer
        MSG = FreeContextBuffer(SourcePoint)

        ''//Make sure cleanup worked
        If MSG = 0 Then
            ''//Return our values
            Return SecPackages
        Else
            ''//Do something better with the error code here
            Throw New ApplicationException("Error cleaning up pointer")
        End If
    Else
        ''//Do something better with the error code here
        Throw New ApplicationException("Error calling native function")
    End If

End Function

<StructLayout(LayoutKind.Sequential)>
Public Structure SecPkgInfo
    Public fCapabilities As UInt32 ''//ulong is 32 bit so we need to use a 32 bit int
    Public wVersion As UInt16 ''//ushort is 16 bit 
    Public wRPCID As UInt16
    Public cbMaxToken As UInt32
    <MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)> Public Name As String
    <MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)> Public Comment As String
End Structure

<DllImport("Secur32.dll")>
Public Shared Function EnumerateSecurityPackages(ByRef pcPackages As UInt32, ByRef ppPackageInfo As IntPtr) As Integer
End Function

<DllImport("Secur32.dll")>
Public Shared Function FreeContextBuffer(ByRef pvContextBuffer As IntPtr) As Integer
End Function

关于C# p/invoke Secur32.dll 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5940386/

相关文章:

multithreading - 每个线程在 Win32 中模拟吗?

c# - 从 C# 中的标准帐户以管理员身份运行批处理文件

c# - GetLogicalProcessorInformation 函数的 PInvoke

c# - 从 C# 调用 C++ 函数时出现访问冲突异常

c# - 从 Delphi DLL 发送二进制数据做一个 C# 应用程序

c# - 正则表达式不允许连续 3 个字符

c# - 如何将非通用 IList 转换为 IList<T>?

c# - 这两种类型的方法称为什么?

c# - 如何使用提供的凭据调用 SSPI 的 'AcquireCredentialsHandle'?