2

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?

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

1 Comment

works like a charm however requires .ToInt64() on x64 build in the IntPtr ArrayPtr = new IntPtr(SourcePoint.ToInt32());
1

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

2 Comments

I switched ulong to int which seems to still work okay. I also added the following to Name and Comment: [MarshalAs(UnmanagedType.LPStr)] and I still get an AccessViolationException "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
You need to check the semantics of EnumerateSecurityPackages - does it expect that Name and Comment already point to an existing buffer? Who will allocate the memory? Also, you want to marshal as LPWStr.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.