NT - Get Username, Full Name and Description (On Domain)

Hi All,

I have several clients (NT) connected via a LAN to an NT server. I wish to run a small widget on each client at startup. This widget will write the UserName, Full Name and Description to the registry on the client.

I.e. the widget is on the client and when it runs will get three details for the current logged in user on that client.

Now, I have this working if the client is standalone. But if the account logged into is on the domain, I get UserName only.

I need some Delphi (4) code to perform the task. Points awarded once fully tested.

Cheers

Ian
iwatkinsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MadshiCommented:
Would the API NetUserGetInfo help? The problem is: This API is only available under winNT. Look at

http://www.wsb.poznan.pl/~pawel/vb/www.mvps.org/win32/network/nt95.html#Section

to read more about the 9x/NT API problem.

Regards, Madshi.
0
iwatkinsAuthor Commented:
Yes, seen all that. The problem is you need to know what server you are logged into to then query it to get your details. I don't know how to do this hence the request for code.

Cheers

Ian
0
jeurkCommented:
Hi,
Here is a link to look for :
http://members.xoom.com/ray_adams

there you should find a sample
and some source code associated with
your problem.

For the moment, xoom seems to be down
so I cannot get you the stuff. So
I'm going home for now, I give you the
link if you want to take a look.
I hope it helps.

regards.
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

MadshiCommented:
This looks interesting, too...


HOWTO: Look Up a User's Full Name
Last reviewed: August 4, 1998
Article ID: Q119670
 


--------------------------------------------------------------------------------


The information in this article applies to:
Microsoft Win32 Software Development Kit (SDK) for Windows NT, versions 3.1, 3.5


SUMMARY
Windows NT workstations can be organized into a domain, which is a collection of computers on a Windows NT Advanced Server network. The domain administrator maintains centralized user and group account information.



MORE INFORMATION
To find the full name of a user if you have the user name and domain name:


Convert the user name and domain name to Unicode, if they are not already Unicode strings. This is a requirement of the ported LAN Manager APIs that are used in the following steps.

Look up the name of the domain controller (DC) for the domain name by calling NetServerEnum().

Look up the user name by calling NetUserGetInfo()

Convert the full user name to ANSI, unless the program is expecting to work with Unicode strings.

The sample code below is a function that takes a user name and a domain name as the first two arguments and returns the user's full name in the third argument.
For information on how to get the current user and domain, please see the following article in the Microsoft Knowledge Base:


   ARTICLE-ID: Q111544
   TITLE     : Looking Up the Current User and Domain


Sample Code

   #include <windows.h>
   #include <lm.h>
   #include <stdio.h>

   /********************************************************************\
   * Function: GetFullName( char *UserName, char *Domain, char *dest ); *
   *                                                                    *
   * Parameters:                                                        *
   *    UserName: the user name                                         *
   *    Domain  : the domain to which the user belongs                  *
   *    dest    : receives the user's full name                         *
   *                                                                    *
   \********************************************************************/

   BOOL GetFullName(char *UserName, char *Domain, char *dest)
   {
      WCHAR  wszUserName[256];           // Unicode user name
      WCHAR  wszDomain[256];
      LPBYTE ComputerName;

      struct _SERVER_INFO_100 *si100;   // Server structure
      struct _USER_INFO_2 *ui;          // User structure

      // Convert ASCII user name and domain to Unicode.

      MultiByteToWideChar( CP_ACP, 0, UserName,
         strlen(UserName)+1, wszUserName, sizeof(wszUserName) );
      MultiByteToWideChar( CP_ACP, 0, Domain,
         strlen(Domain)+1, wszDomain, sizeof(wszDomain) );

      // Get the computer name of a DC for the specified domain.

      NetGetDCName( NULL, wszDomain, &ComputerName );

      // Look up the user on the DC.

      if(NetUserGetInfo( (LPWSTR) ComputerName,
         (LPWSTR) &wszUserName, 2, (LPBYTE *) &ui))
      {
         printf( "Error getting user information.\n" );
         return( FALSE );
      }

      // Convert the Unicode full name to ASCII.

      WideCharToMultiByte( CP_ACP, 0, ui->usri2_full_name,
         -1, dest, 256, NULL, NULL );

      return( TRUE );
   }

 
Regards, Madshi.
0
iwatkinsAuthor Commented:
You are getting there. But for 600 points I want some delphi code (function, maybe) to do all this for me. Not too much to ask I hope ? :-)

I would prefer a function (or functions) that return the three variables (Username, Full Name and Description). Assume that the client PC doesn't know anything about its network. I.e. I want code to go off and find the domain/workgroup details etc. before quering the server etc.

Only has to work on NT and with Delphi 4.

Cheers

Ian
0
MadshiCommented:
You're right. For 600 points you should get some sources...   :-)

Well, I was only able to test a part of it. NetGetDCName fails on my computer, because I've no network at home. But I hope the rest works, too.

type
  TUserInfo2 = packed record
    usri2_name           : PWideChar;
    usri2_password       : PWideChar;
    usri2_password_age   : cardinal;
    usri2_priv           : cardinal;
    usri2_home_dir       : PWideChar;
    usri2_comment        : PWideChar;
    usri2_flags          : cardinal;
    usri2_script_path    : PWideChar;
    usri2_auth_flags     : cardinal;
    usri2_full_name      : PWideChar;
    usri2_usr_comment    : PWideChar;
    usri2_parms          : PWideChar;
    usri2_workstations   : PWideChar;
    usri2_last_logon     : cardinal;
    usri2_last_logoff    : cardinal;
    usri2_acct_expires   : cardinal;
    usri2_max_storage    : cardinal;
    usri2_units_per_week : cardinal;
    usri2_logon_hours    : pointer;
    usri2_bad_pw_count   : cardinal;
    usri2_num_logons     : cardinal;
    usri2_logon_server   : PWideChar;
    usri2_country_code   : cardinal;
    usri2_code_page      : cardinal;
  end;
  PUserInfo2 = ^TUserInfo2;

function NetGetDCName(serverName, domainName: PWideChar; var pdcName: PWideChar) : cardinal; stdcall;
         external 'netapi32.dll' name 'NetGetDCName';
function NetApiBufferFree(buf: pointer) : cardinal; stdcall;
         external 'netapi32.dll' name 'NetApiBufferFree';
function NetUserGetInfo(serverName, userName: PWideChar; level: cardinal; var ui2: PUserInfo2) : cardinal; stdcall;
         external 'netapi32.dll' name 'NetUserGetInfo';

function GetUserInfos(var userName, fullUserName, comment: string) : boolean;
var c1, c2, c3, c4 : cardinal;
    sid            : ^PSid;
    ac1, ac2       : array [0..MAX_PATH] of char;
    pdc            : PWideChar;
    ui2            : PUserInfo2;
begin
  result := false;
  if OpenProcessToken(windows.GetCurrentProcess, TOKEN_READ, c1) then
    try
      GetTokenInformation(c1, TokenUser, nil, 0, c2);
      sid := AllocMem(c2);
      try
        c3 := MAX_PATH; c4 := MAX_PATH;
        if GetTokenInformation(c1, TokenUser, sid, c2, c2) and
           LookupAccountSid(nil, sid^, ac1, c3, ac2, c4, c2) then begin
          userName := ac1;
          if NetGetDCName(nil, PWideChar(wideString(string(ac2))), pdc) = 0 then
            try
              if NetUserGetInfo(pdc, PWideChar(wideString(userName)), 2, ui2) = 0 then
                try
                  result := true;
                  fullUserName := wideString(ui2^.usri2_full_name);
                  comment      := wideString(ui2^.usri2_comment  );
                finally NetApiBufferFree(ui2) end;
            finally NetApiBufferFree(pdc) end;
        end;
      finally FreeMem(sid) end;
    finally CloseHandle(c1) end;
end;

Regards, Madshi.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MadshiCommented:
John, still can't reach that site...   :-(
0
jeurkCommented:
Hello,
It is open now.
the other definitive site you should look at is

http://www.jgsoftware.com/nt.htm

http://members.xoom.com/ray_adams 
I know, you want a sample. But I'm
short of time, sorry.

---------------------------------------

Retrieving Network information

List of users

List of computers

NetQueryDisplayInformation

 

Retrieving Network information

Getting list of users in domain.

For the beginning I shall tell a pair of words about a list of the users. The main list of the users (User Data Base) is stored on Primary Domain Controller, if the network has Backup Domain Controllers, on each of them the copy of main base is stored. Replication is carried out after changes in main base on PDC. To receive a list of all users, we should at first determine a name of Domain Controller. Is used a function NetGetDCName.


NetGetDCName(servername:PChar;  
                                    domainname:PChar;
                                    bufptr:Pointer
                                    ):NET_API_STATUS ;    


servername - Pointer to a Unicode string containing the name of the remote server on which the function is to execute. A nil pointer or string specifies the local computer.

domainname - Pointer to a Unicode string containing the name of the domain. A nil pointer or string indicates that the function returns the name of the domain controller for the primary domain.

bufptr- Returns a pointer to an allocated buffer containing the server name of the PDC of the domain. The server name is prefixed by \\. The buffer should be deallocated using NetApiBufferFree.

Further we can apply two functions
NetUserEnum And NetQueryDisplayInformation
The main difference of these functions is that, maiden returns more than parameters (such as last_logon, units_per_week) whereas second only most basic.We is applicable second.Check example here.

var buf:pointer;
     Item:^NET_DISPLAY_USER;
     i,Count:Integer;
     Domain:PWideChar;
begin
NetGetDCName(nil,nil,pointer(Domain)); //Geting Primary Domain Controller
{Retieving list of registered user in current domain}
NetQueryDisplayInformation(Domain,1,0,100000,100000*sizeof(NET_DISPLAY_USER),Count,buf);
item:=buf;
if Count>0 then
begin
for i:=1 to Count do
begin
  with ListView1.Items.Add do //Adding user to list
   begin
   Caption:=WideCharToString(Item.usri1_name);
   SubItems.add(WideCharToString(Item.usri1_full_name));
   SubItems.add(WideCharToString(Item.usri1_comment));
   ImageIndex:=4;
   end;
   inc(item);
  end;
end;
NetApiBufferFree(buf);
NetApiBufferFree(Domain);
if ListView1.Items.count<>0 then
   begin
   ListView1.Selected:=ListView1.items[0];
   end;
 

Retrieving List of Copmuters in Domain


The NetServerEnum function lists all servers of the specified type that are visible in the specified domain. For example, an application can call NetServerEnum to list all domain controllers only or all SQL servers only.

Systax:

function NetServerEnum(
            servername:PWideString;
            level:DWORD;
            bufptr:pointer;
            prefmaxlen:DWORD;
            entriesread:^LONGINT;
            totalentries:^LONGINT;
            servertype:DWORD;
            domain:PWideString;
            resume_handle:^Longint ):NET_API_STATUS ;

 
servername
Pointer to a Unicode string containing the name of the remote server on which the function is to execute. A nil pointer or string specifies the local computer
level
Specifies one of the following values to return the level of information provided. Value Meaning
100 The bufptr parameter points to an array of SERVER_INFO_100 structures.
101 The bufptr parameter points to an array of SERVER_INFO_101 structures.

 
bufptr
Pointer to the buffer in which the data set with the level parameter is stored.
prefmaxlen
Preferred maximum length, in 8-bit bytes of returned data.
entriesread
On return, the actual enumerated element count is located in the doubleword pointed to by entriesread.
totalentries
Returns the total number of visible servers and workstations on the network.
 
servertype
A DWORD mask that filters server entries to return from the enumeration. The defined mask bits specify: Symbolic constant Value Meaning
SV_TYPE_WORKSTATION $00000001  All Net workstations
SV_TYPE_SERVER $00000002  All Net servers
SV_TYPE_SQLSERVER $00000004 Any server running with Microsoft SQL Server
SV_TYPE_DOMAIN_CTRL $00000008 Primary domain controller
SV_TYPE_DOMAIN_BAKCTRL $00000010 Backup domain controller
SV_TYPE_TIMESOURCE $00000020 Server running the Timesource service
SV_TYPE_AFP $00000040 Apple File Protocol servers
SV_TYPE_NOVELL $00000080 Novell servers
SV_TYPE_DOMAIN_MEMBER $00000100 LAN Manager 2.x Domain Member
SV_TYPE_LOCAL_LIST_ONLY $40000000 Servers maintained by the browser. See the following Remarks section.
SV_TYPE_PRINT $00000200 Server sharing print queue
SV_TYPE_DIALIN $00000400 Server running dial-in service
SV_TYPE_XENIX_SERVER $00000800 Xenix server
SV_TYPE_MFPN $00004000 Microsoft File and Print for Netware
SV_TYPE_NT $00001000 Windows NT (either Workstation or Server)
SV_TYPE_WFW $00002000 Server running Windows for Workgroups
SV_TYPE_SERVER_NT $00008000 Windows NT Non-DC server
SV_TYPE_POTENTIAL_BROWSER $00010000 Server that can run the Browser service
SV_TYPE_BACKUP_BROWSER  $00020000 Server running a Browser service as backup
SV_TYPE_MASTER_BROWSER $00040000 Server running the master Browser service
SV_TYPE_DOMAIN_MASTER $00080000 Server running the domain master Browser
SV_TYPE_DOMAIN_ENUM $80000000 Primary Domain  
SV_TYPE_WINDOWS $00400000 Windows 95 or later
SV_TYPE_ALL $FFFFFFFF All servers

 
domain
A pointer to a Unicode string containing the name of the domain for which a list of servers is to returned. If nil is specified, the primary domain is implied.
resume_handle
Reserved. Must be set to zero.
var
   buf2:pointer;
   rh:longint;
   pComp:PSERVER_INFO_100;
   u,j,lCountComputer:longint;
   sCompName:string;
begin
   rh:=0;
   NetServerEnum(nil,100,buf2,9999999,lCountComputer,u,SV_TYPE_ALL,nil,rh);
   pComp:=buf2;
   for j:=1 to lCountComputer do begin
     sCompName:=pComp.sv100_name;
     ListBox1.Items.Add(pComp.sv100_name);
     inc(pComp);
   end;
NetApiBufferFree(buf2);
end;
0
iwatkinsAuthor Commented:
Works OK as long as you are on a network. Can take some time and no error messages should it fail. I will add these in over time though.

Now I can see some code, it is actually straightforward ;-)

Thanks to all

Cheers

Ian
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.