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
精彩评论