NetQueryDisplayInformation (netapi32)
Last changed: -219.137.199.12

.
Summary
The NetQueryDisplayInformation function returns user account, computer, or group account information. Call this function to quickly enumerate account information for display in user interfaces.

C# Signature:

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

VB Signature:

    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

VB.Net Signature:

    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

User-Defined Types:

Notes:

None.

Tips & Tricks:

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.

Sample Code:

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

Sample Code:

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

}

Alternative Managed API:

Do you know one? Please contribute it!

Documentation