Visual Basic Network Services
Retrieving Selection of Users and Groups via OpenUserBrowser
Posted:   Sunday April 14, 2002
Updated:   Monday November 28, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   Windows NT3.1, Windows NT4, Windows 2000, Windows XP
Author:   Tom Clement, VBnet - Randy Birch


InitializeSecurityContext: Authenticate User via the NT Challenge Process
IsUserAnAdmin: Determine if the Current User is an Administrator
LookupAccountName: Verify a User's Account
LookupAccountSid: Determine if the Current Process is Running Under Admin Account
This demo will work on the operating systems listed under OS Restrictions above. However, since this API is provided with Windows beginning with Win95, it's possible this may also function on all versions. If you have success or failure on a particular version, I would appreciate knowing via the Comments button on the navbar.

Netui2.dll exposes a 'common' dialog invoked through the OpenUserBrowser API. Used in tandem with EnumUserBrowserSelection it is possible for VB devs to display what is best described as the standard "select NT user/group/domain" dialog and to  return the selections made by the user.  Undocumented in the MSDN and the C++ libraries, it is was documented (in C) at OK Thinking Software and, thanks to Tom Clement's post in the microsoft.public.vb.winapi newsgroup, now documented for VB as well. This demo takes Tom's code as a basis in showing how to call OpenUserBrowser and how to to return the various network group and user information thorough EnumUserBrowserSelection. Being undocumented, the explanation of the APIs is formed in part from the C demo's comments and from the names of the various members of the calls.

Following populating the desired parameters into a OPENUSERBROWSER structure, OpenUserBrowser initializes and displays the Windows' dialog and provides the means for users to select various network domains, groups and users. Once the dialog has closed EnumUserBrowserSelection is passed the handle to the OpenUserBrowser session. If the session was not cancelled the call fills an ENUMUSERBROWSER struct with information about each selected item.

OpenUserBrowser itself takes only one parameter - the completed OPENUSERBROWSER structure. EnumUserBrowserSelection takes three parameters ... the handle to the browser session, an ENUMUSERBROWSER structure, and a Long representing the size of the structure passed. Once the user's selections have been retrieved, CloseUserBrowser is called to free the browser handle.

OpenUserBrowser requires the OPENUSERBROWSER sets, as a minimum, the .cbSize, .szDomainName and .dwFlags members. By specifying the form's hwnd as hWndParent the dialog is assured to remain above the calling form, otherwise the dialog becomes a child of the desktop. The dialog can display a custom string, or by specifying vbNullString, the default caption based on the available user actions (i.e. Add, Add Users, Add Groups, Add Users or Groups).   

You will also notice that in decoding the members of the OPENUSERBROWSER structure one parameter's purpose remains unknown, as is defined as such. The C++ demo sets this member to 1, while Tom's demo set it to 0. Both work, and I have no additional information as to the purpose of this member.

If the user selects and edits any values in the Add Names section, and that name is not in the Names list, the dialog displays an error to the user indicating the account for the edited item is not in the list.

The various flags available for the .flags property of OPENUSERBROWSER instruct the dialog on which elements of the network to display. As usual, multiple options are Or'd together to create the final flag. Based on the available documentation and constants, the following flags are available:

OPENUSERBROWSER_INCLUDE_ALIASES ...... On my system, adds Groups to the available names, and with INCLUDE_USER_BUTTONS, displays the Show Users button..
OPENUSERBROWSER_INCLUDE_GROUPS ...... On my system, initially shows nothing, and with INCLUDE_USER_BUTTONS displays the Show Users, Members and Search buttons. When Show users is pressed the users fill the names list.
OPENUSERBROWSER_INCLUDE_USER_BUTTONS ...... If OPENUSERBROWSER_INCLUDE_USERS is not included, shows the Show Users, Members and Search buttons. If OPENUSERBROWSER_INCLUDE_USERS is included, shows the Members and Search buttons.
OPENUSERBROWSER_INCLUDE_USERS ...... Adds all user names to the Names list. When combined with INCLUDE_USER_BUTTONS, shows the Members and Search buttons.
OPENUSERBROWSER_INCLUDE_NETWORK ...... Adds NETWORK to the available names.
OPENUSERBROWSER_INCLUDE_EVERYONE ...... Adds Everyone to the available names.
OPENUSERBROWSER_INCLUDE_SYSTEM ...... Adds SYSTEM to the available names.
OPENUSERBROWSER_SINGLE_SELECTION   Prevents multiple selection of names. Useful for eliciting a single valid item from the user.
OPENUSERBROWSER_NO_LOCAL_DOMAIN   Prevents display of the local domain in the List Names From combo. (On my non-domain single-workgroup system, enabling this flag prevented the display of the dialog completely. Its name seems to imply that on multi-domain or multi-workgroup systems the dialog would not display the user's local domain or group.)
 BAS Module Code

 Form Code
To a form add one command button (Command1), one text box (Text1), and one Check box with its Index set to 0 to create a control array (Check1(0)). The form's Load event takes care of creating, labelling and positioning all controls.  Add the following to the form:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private Const NERR_SUCCESS                            As Long = 0&
Private Const OPENUSERBROWSER_INCLUDE_SYSTEM          As Long = &H10000
Private Const OPENUSERBROWSER_SINGLE_SELECTION        As Long = &H1000&
Private Const OPENUSERBROWSER_NO_LOCAL_DOMAIN         As Long = &H100&
Private Const OPENUSERBROWSER_INCLUDE_NETWORK         As Long = &H10&
Private Const OPENUSERBROWSER_INCLUDE_USERS           As Long = &H8&
Private Const OPENUSERBROWSER_INCLUDE_GROUPS          As Long = &H2&
Private Const OPENUSERBROWSER_INCLUDE_ALIASES         As Long = &H1&
                                                                OPENUSERBROWSER_INCLUDE_USER_BUTTONS Or _
                                                                OPENUSERBROWSER_INCLUDE_EVERYONE Or _
                                                                OPENUSERBROWSER_INCLUDE_INTERACTIVE Or _
                                                                OPENUSERBROWSER_INCLUDE_NETWORK Or _
   cbSize        As Long
   fCancelled    As Long
   Unknown       As Long
   hWndParent    As Long
   szTitle       As Long
   szDomainName  As Long
   dwFlags       As Long
   dwHelpID      As Long
   szHelpFile    As Long
End Type

   SidType        As Long
   Sid1           As Long
   Sid2           As Long
   szFullName     As Long
   szUserName     As Long
   szDisplayName  As Long
   szDomainName   As Long
   szDescription  As Long
   sBuffer        As String * 1000
End Type

Private Declare Function OpenUserBrowser Lib "netui2.dll" _
  (lpOpenUserBrowser As Any) As Long
Private Declare Function EnumUserBrowserSelection Lib "netui2.dll" _
  (ByVal hBrowser As Long, _
   ByRef lpEnumUserBrowser As Any, _
   ByRef cbSize As Long) As Long
Private Declare Function CloseUserBrowser Lib "netui2.dll" _
   (ByVal hBrowser As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" _
   (ByVal lpString As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (Destination As Any, _
   Source As Any, _
   ByVal Length As Long)

Private Sub Form_Load()

   Dim cnt As Long

  'load and show 11 Check1 controls
   For cnt = 0 To 10
      If cnt <> 0 Then Load Check1(cnt)
      With Check1(cnt)
         If cnt < 6 Then
            .Move 360, 360 + (Check1(cnt).Height * cnt), 2500
            .Move 2860, 360 + (Check1(cnt).Height * (cnt - 6)), 2500
         End If
         Select Case cnt
            Case 0:  .Caption = "include aliases"
            Case 1:  .Caption = "include groups"
            Case 2:  .Caption = "include user buttons"
            Case 3:  .Caption = "include users"
            Case 4:  .Caption = "include network"
            Case 5:  .Caption = "include 'interactive'"
            Case 6:  .Caption = "include 'everyone'"
            Case 7:  .Caption = "include 'creator owner'"
            Case 8:  .Caption = "include 'system'"
            Case 9:  .Caption = "single selection"
            Case 10: .Caption = "no local domain"
            Case Else
         End Select
         .Visible = True
      End With

   With Command1
      .Caption = "OpenUserBrowser"
      .Move Check1(5).Left, _
           (Check1(5).Height * 5) + 780
   End With
   With Text1
      .Move Command1.Left, _
            Command1.Top + Command1.Height + 300, _
            Me.ScaleWidth - 720
      Me.Height = .Top + .Height + 780
   End With 
End Sub

Private Sub Command1_Click()

   Dim sUsers As String

   If GetBrowserNames(Me.hWnd, _
                      "\\vbnetdev", _
                      "VBnet Add Users & Groups Demo", _
                      sUsers) Then
      Text1.Text = sUsers
   End If

End Sub

Private Function BuildFlags() As Long

  'using a var to shorten web display ...
  'in application can replace var with
  'the function name itself
   Dim bf As Long

  'clear and set flags
   bf = 0&
   If Check1(0).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_ALIASES
   If Check1(1).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_GROUPS
   If Check1(2).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_USER_BUTTONS
   If Check1(3).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_USERS
   If Check1(4).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_NETWORK
   If Check1(5).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_INTERACTIVE
   If Check1(6).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_EVERYONE
   If Check1(7).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_CREATOR_OWNER
   If Check1(8).Value = 1 Then bf = bf Or OPENUSERBROWSER_INCLUDE_SYSTEM
   If Check1(9).Value = 1 Then bf = bf Or OPENUSERBROWSER_SINGLE_SELECTION
   If Check1(10).Value = 1 Then bf = bf Or OPENUSERBROWSER_NO_LOCAL_DOMAIN
   BuildFlags = bf

End Function

Private Function GetBrowserNames(ByVal hParent As Long, _
                                 ByVal sDomain As String, _
                                 ByVal sTitle As String, _
                                 sBuff As String) As Boolean

   Dim hBrowser   As Long
  'initialize the OPENUSERBROWSER structure
   With browser
      .cbSize = Len(browser)
      .fCancelled = 0
      .Unknown = 0
      .hWndParent = hParent
      .szTitle = StrPtr(sTitle)
      .szDomainName = StrPtr(sDomain)
      .dwFlags = BuildFlags()
   End With
  'show the dialog function
   hBrowser = OpenUserBrowser(browser)
  'if not cancelled...
   If browser.fCancelled = NERR_SUCCESS Then
      '...retrieve any selections and populate
      'the sBuff string passed to this function,
      'returning True if successful.
       Do While EnumUserBrowserSelection(hBrowser, enumb, Len(enumb) + 1) <> 0
          'return selection as \\DOMAIN\NAME
          'can be adjusted at will
           sBuff = sBuff & GetPointerToByteStringW(enumb.szDomainName) & "\" & _
                           GetPointerToByteStringW(enumb.szUserName) & vbCrLf
           GetBrowserNames = True
       Call CloseUserBrowser(hBrowser)
      'if desired, strip the last crlf from the string
       If GetBrowserNames = True Then
           sBuff = Left(sBuff, Len(sBuff) - 2)
       End If
   End If
End Function

Private Function GetPointerToByteStringW(ByVal dwData As Long) As String
   Dim tmp() As Byte
   Dim tmplen As Long
   If dwData <> 0 Then
      tmplen = lstrlenW(dwData) * 2
      If tmplen <> 0 Then
         ReDim tmp(0 To (tmplen - 1)) As Byte
         CopyMemory tmp(0), ByVal dwData, tmplen
         GetPointerToByteStringW = tmp
     End If
   End If
End Function


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter