[DllImport("Netapi32.dll")]
extern static uint NetQueryDisplayInformation([MarshalAs(UnmanagedType.LPWStr)]
string serverName,
uint Level,
uint ResumeHandle,
uint EntriesRequested,
uint prefMaxLength,
out uint entriesRead,
out IntPtr Buffer);
Declare Function NetQueryDisplayInformation Lib "Netapi32.dll"
(serverName As Byte, _
ByVal level As Long, _
ByVal ResumeHandle As Long, _
ByVal EntriesRequested As Long, _
ByVal prefMaxLen As Long, _
entriesRead As Long, _
Buffer As Long) As Long
Declare Function NetQueryDisplayInformation Lib "Netapi32.dll" _
(serverName As IntPtr, _
ByVal level As Integer, _
ByVal ResumeHandle As Integer, _
ByVal EntriesRequested As Integer, _
ByVal prefMaxLen As Integer, _
ByRef entriesRead As Integer, _
ByRef Buffer As Long) As Integer
None.
I hugely increased the speed of this API by doing the following:
Add 'private const uint MAX_PREFERRED_LENGTH = 4294967294;' to the defines and request 100 records at a time thus:
lret = NetQueryDisplayInformation(strDomain, 3, lindex, 100, MAX_PREFERRED_LENGTH, out lread , out x);
The following C# function returns user information just as fast as the C++ equivalent.
public struct UserInfo
{
public string Username;
public string FullName;
}
public List<UserInfo> GetUserList(string DomainController)
{
System.IntPtr UsrBuf = System.IntPtr.Zero;
System.IntPtr item = System.IntPtr.Zero;
uint lindex = 0;
uint lread = 0;
uint lret = ERROR_MORE_DATA;
uint reqRecs = 100; // Number of records to get (Win2K+ only allows 100 at a time)
List<UserInfo> UserData = new List<UserInfo>();
NET_DISPLAY_USER usr = new NET_DISPLAY_USER();
int StructSize = Marshal.SizeOf(typeof(NET_DISPLAY_USER));
// Get user information
lret = ERROR_MORE_DATA;
while ((lret == ERROR_MORE_DATA))
{
// Get batches of 100 users
lret = NetQueryDisplayInformation(DomainController, 1, lindex, reqRecs, MAX_PREFERRED_LENGTH, out lread, out UsrBuf);
if (lread > 0)
{
// Get users from buffer
item = UsrBuf;
// lread contains the number of records returned.
for( ; lread > 0; lread--)
{
if (item != System.IntPtr.Zero)
{
UserInfo nUser = new UserInfo();
// Convert strings and load UserInfo structure
usr = (NET_DISPLAY_USER)Marshal.PtrToStructure(item, typeof(NET_DISPLAY_USER));
nUser.Username = Marshal.PtrToStringUni(usr.usri1_name);
nUser.FullName = Marshal.PtrToStringUni(usr.usri1_full_name);
UserData.Add(nUser);
}
// Update index (used in GetInfo call to set offset for next batch)
lindex = usr.usri1_next_index;
// Increment UserInfo pointer
item = (IntPtr)(item.ToInt64() + StructSize);
}
// Free buffer (allocated by system)
if (UsrBuf != System.IntPtr.Zero)
{
NetApiBufferFree(UsrBuf);
}
}
}
return UserData;
}
[ StructLayout( LayoutKind.Sequential)]
public struct NET_DISPLAY_USER
{
public System.IntPtr usri1_name;
public System.IntPtr usri1_comment;
public uint usri1_flags;
public System.IntPtr usri1_full_name;
public uint usri1_user_id;
public uint usri1_next_index;
}
[StructLayout( LayoutKind.Sequential )]
public struct NET_DISPLAY_GROUP
{
public System.IntPtr grp_name;
public System.IntPtr grp_comment;
public int grp_group_id;
public int grp_attributes;
public int grp_next_index;
}
[StructLayout( LayoutKind.Sequential )]
public struct NET_DISPLAY_MACHINE
{
public System.IntPtr usri2_name;
public System.IntPtr usri2_comment;
public int usri2_flags;
public int usri2_user_id;
public int usri2_next_index;
}
#region constants
private const int READ_CONTROL = 0x20000;
private const int TOKEN_QUERY = 0x8;
private const int ERROR_MORE_DATA = 234;
private const int NERR_TRUE = 1;
private const int RPC_S_SERVER_UNAVAILABLE = 1722;
private const int ERROR_ACCESS_DENIED = 5;
private const int ERROR_INVALID_LEVEL = 124;
private const int NERR_Success = 0;
#endregion
#region external dll declares
[DllImport( "advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[DllImport("Netapi32.dll")] static extern int NetQueryDisplayInformation([MarshalAs(UnmanagedType.LPWStr)] string serverName,
int Level, int ResumeHandle, int EntriesRequested, int prefMaxLength, out int entriesRead, out System.IntPtr Buffer);
[DllImport("netapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern int NetApiBufferFree (System.IntPtr pBuffer);
#endregion
public static test(string strDomain)
{
System.IntPtr x = System.IntPtr.Zero;
uint lindex = 0;
uint lread = 0;
uint lret = ERROR_MORE_DATA;
ArrayList a = new ArrayList();
NET_DISPLAY_GROUP grp = new NET_DISPLAY_GROUP ();
NET_DISPLAY_USER usr = new NET_DISPLAY_USER();
while ((lret == ERROR_MORE_DATA))
{
//get each group
lret = NetQueryDisplayInformation(strDomain, 3, lindex, 1, 1024, out lread , out x);
if (lread > 0)
{
//get group
if (x != System.IntPtr.Zero)
{
grp = (NET_DISPLAY_GROUP)Marshal.PtrToStructure (x, typeof(NET_DISPLAY_GROUP));
a.Add(Marshal.PtrToStringUni(grp.grp_name));
}
//get next index
lindex = grp.grp_next_index;
//free buffer
if (x != System.IntPtr.Zero)
{
NetApiBufferFree(x);
}
}
}
lret = ERROR_MORE_DATA;
//now get users
while ((lret == ERROR_MORE_DATA))
{
//get each user
lret = NetQueryDisplayInformation(strDomain, 1, lindex, 1, 1024, out lread , out x);
if (lread > 0)
{
//get group
if (x != System.IntPtr.Zero)
{
usr = (NET_DISPLAY_USER)Marshal.PtrToStructure(x, typeof(NET_DISPLAY_USER));
a.Add(Marshal.PtrToStringUni(usr.usri1_name));
}
//get next index
lindex = usr.usri1_next_index;
//free buffer
if (x != System.IntPtr.Zero)
{
NetApiBufferFree (x);
}
}
}
lret = ERROR_MORE_DATA;
NET_DISPLAY_MACHINE mac = new NET_DISPLAY_MACHINE ();
//now get users
while ((lret == ERROR_MORE_DATA))
{
//get each group
lret = NetQueryDisplayInformation(strDomain, 2, lindex, 1, 1024, out lread , out x);
if (lread > 0)
{
//get group
if (x != System.IntPtr.Zero)
{
mac = (NET_DISPLAY_MACHINE) Marshal.PtrToStructure(x,typeof(NET_DISPLAY_MACHINE));
a.Add(Marshal.PtrToStringUni(mac.usri2_name));
}
//get next index
lindex = mac.usri2_next_index;
//free buffer
if (x != System.IntPtr.Zero)
{
NetApiBufferFree (x);
}
}
}
}
Do you know one? Please contribute it!