开发者

C# p/invoke Secur32.dll problems

I'm trying to wrap the Secur32.dll's EnumerateSecurityPackages function which is declared below:

SECURITY_STATUS SEC_Entry EnumerateSecurityPackages(
  __in  PULONG pcPackages,
  __in  PSecPkgInfo *ppPackageInfo
);
开发者_运维问答

I have the following C# code, but I get an AccessViolationException when I try to run it. In the debugger the pcPackages variable does get set correctly, but I think I'm doing something wrong with the array of 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);

Any ideas what I'm doing wrong?


Try this code, its converted from VB.Net (my native language) but runs fine for me in C#. Just call Call_EnumerateSecurityPackages() and it will return a list for you.

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

And for future use, here's the VB version:

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


Your definition of SecPkgInfo is incorrect, C's ULONG != C#'s ulong. You also need to very clearly specify how to marshal Name and Comment via MarshalAs

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜