Get the User Names and Group Name from NT

I wish to fill my User table with the User Name and Group Names from the NT security. I tried to use the 'NetGroupGetUsers' API call but for some reason I was unable to make it work. Can anyone give me a example or another way to work around it.
Who is Participating?
JohnLucasConnect With a Mentor Commented:
This will get you the user name under NT/98 or 95

Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
   (ByVal lpBuffer As String, nSize As Long) As long

    Dim lpBuff As String * 25
    Dim ret As Long, UserName As String

    ret = GetUserName(lpBuff, 25)
    GetUser = Left(lpBuff, InStr(lpBuff, Chr(0)) - 1)

This is not needed...

Left(lpBuff, InStr(lpBuff, Chr(0)) - 1)
It is needed if you dont want a null character after the name followed by lots of blank spaces.

Nice answer JohnLucas. Only one suggestion, why not extend the length of lpBuff to 255 characters since you are going to trim it anyways? Just allows for future expansion of name lengths (beyond 25 chars) without recoding :)

Never miss a deadline with

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

umeshkhojeAuthor Commented:
I wish to fill all the users. Not the user who is logged in.
Function EnumerateUsers(ByVal SName As String, ByVal GName As String) As Long
    Dim Result As Long, BufPtr As Long, EntriesRead As Long
    Dim TotalEntries As Long, ResumeHandle As Long, BufLen As Long
    Dim SNArray() As Byte, GNArray() As Byte, UNArray(99) As Byte
    Dim UName As String, I As Integer, UNPtr As Long, TempPtr As MungeLong
    Dim TempStr As MungeInt, Found As Boolean
    Dim RS As ADODB.Recordset

    On Error Resume Next
    Set RS = frmMain.Adodc1.Recordset.Clone
    SNArray = SName & vbNullChar       ' Move to byte array
    GNArray = GName & vbNullChar       ' Move to Byte array
    BufLen = 255                       ' Buffer size
    ResumeHandle = 0                   ' Start with the first entry
        If Len(GName) = 0 Then
            Result = NetUserEnum0(SNArray(0), 0, FILTER_NORMAL_ACCOUNT, BufPtr, BufLen, EntriesRead, TotalEntries, ResumeHandle)
            Result = NetGroupEnumUsers0(SNArray(0), GNArray(0), 0, BufPtr, BufLen, EntriesRead, TotalEntries, ResumeHandle)
        End If
        EnumerateUsers = Result
        If Result <> 0 And Result <> 234 Then    ' 234 means multiple reads
                                                ' required
            If Result = 2220 Then GoTo exitFun
        End If
        For I = 1 To EntriesRead
            ' Get pointer to string from beginning of buffer
            ' Copy 4-byte block of memory in 2 steps
            Result = PtrToInt(TempStr.XLo, BufPtr + (I - 1) * 4, 2)
            Result = PtrToInt(TempStr.XHi, BufPtr + (I - 1) * 4 + 2, 2)
            LSet TempPtr = TempStr ' munge 2 integers into a Long
            ' Copy string to array
            Result = PtrToStr(UNArray(0), TempPtr.X)
            UName = Left(UNArray, StrLen(TempPtr.X))
            RS.Find "username='" & UName & "'"
            If RS.EOF Then
                frmUser.CbUserName.AddItem UName
            End If
        Next I
    Loop Until EntriesRead = TotalEntries
    ' The above condition is only valid for reading accounts on Windows NT,
    ' but is not OK for OS/2 or LanMan

    Result = NetAPIBufferFree(BufPtr)         ' Don't leak memory
End Function
Public Function GetPrimaryDCName(ByVal MName As String, ByVal DName As String) As String
    Dim Result As Long, DCNPtr As Long
    Dim DNArray() As Byte, MNArray() As Byte, DCNArray(100) As Byte
    GetPrimaryDCName = ""
    MNArray = MName & vbNullChar
    DNArray = DName & vbNullChar
    Result = NetGetDCName(MNArray(0), DNArray(0), DCNPtr)
    If Result <> 0 Then Exit Function
    Result = PtrToStr(DCNArray(0), DCNPtr)
    Result = NetAPIBufferFree(DCNPtr)
    GetPrimaryDCName = DCNArray()
End Function

EnumerateUsers GetPrimaryDCName("", ""), ""

No, it is not needed...

    Dim lpBuff As String * 25

Creates as string called lpBuff which has a fixed length of 25 characters.

    ret = GetUserName(lpBuff, 25)

Gets the username and puts it into lpBuff, which is fixed at 25 character length. IT also returns a null character to signify the end of the returned string.

IE :

lpBuff="ViktornetĀ§                "
Noting that I have used Ā§ to represent a null character.

That is why you must have the line:
GetUser = Left(lpBuff, InStr(lpBuff, Chr(0)) - 1)

which will give the value:


Which is in a much more usable format.

If you put a break point in JohnLucas' code on the last line <GetUser = Left(lpBuff, InStr(lpBuff, Chr(0)) - 1)> and type ?"*" & lpbuff & "*" into the debug window, you will see what I mean.

Try it, and if you still think you're right, justify your comment with an explanation as to why you are right. Don't just repeat your previous answer.

As I said before JohnLucas is right, the line is needed.


oh come on... stop arguing.... as i'm telling you that ISNT needed..

try this..

    Dim str As String * 100
    str = "Viktor" & Chr(0) & "net"
    Text1.Text = str

Now Text1.Text = "Viktor" not "Viktor#0"... VB knows what to do with the NULL char and doesn't include it in the string... it just let's it know where the string is ending...


Your code works perfectly. You are right that the textbox control knows how to handle a null char.

However, if you return the value from a function (or use it in the same function), and do not place it into a control, you do need the line in your code to trim out the crap, as my code (in my last comment) demonstrates.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.