Login name on NT4

How do i get the login name from another NT4 workstation in the network?
LVL 1
rene_moellerAsked:
Who is Participating?
 
d003303Connect With a Mentor Commented:
Yo,
here is what's possible. Since NT allows several user contexts for processes, there may be several active users on a workstation (like services running in a user context).
This code is an example how to use the NetWkstaUserEnum function. Note that this app will run on NT only.

// unit code
unit _enum_ok;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Label1: TLabel;
    GroupBox1: TGroupBox;
    ListBox1: TListBox;
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type

  ENetAPIException = class(Exception)
    NetAPIErrorCode : LongInt;
  end;

  PWKSTA_USER_INFO_0 = ^TWKSTA_USER_INFO_0;
  TWKSTA_USER_INFO_0 = packed record
    wkui0_username : PWideChar;
  end;
  ATWKSTA_USER_INFO_0 = array[0..0] of TWKSTA_USER_INFO_0;

  PWKSTA_USER_INFO_1 = ^TWKSTA_USER_INFO_1;
  TWKSTA_USER_INFO_1 = packed record
    wkui1_username,
    wkui1_logon_domain,
    wkui1_oth_domains,
    wkui1_logon_server : PWideChar;
  end;
  ATWKSTA_USER_INFO_1 = array[0..0] of TWKSTA_USER_INFO_1;

  PSERVER_INFO_100 = ^TSERVER_INFO_100;
  TSERVER_INFO_100 = packed record
    sv100_platform_id : DWORD;
    sv100_name        : PWideChar;
  end;

const

  NERR_BASE            = 2100;
  NERR_SUCCESS         = 0;
  NERR_UserNotFound    = (NERR_BASE + 121);
  NERR_InvalidComputer = (NERR_BASE + 251);

// function prototypes
function NetWkstaUserEnum(servername : PWideChar; level : DWORD; var bufptr{ : Pointer};
                          prefmaxlen : DWORD; var entriesread : DWORD; var totalentries : DWORD;
                          var resumehandle : DWORD): LongInt; stdcall; forward;
function NetApiBufferFree(Buffer : Pointer): LongInt; stdcall; forward;
function NetServerGetInfo(servername : PWideChar; level : DWORD; var bufptr : Pointer): LongInt; stdcall; forward;

// function includes
function NetWkstaUserEnum; external 'netapi32.dll' name 'NetWkstaUserEnum';
function NetApiBufferFree; external 'netapi32.dll' name 'NetApiBufferFree';
function NetServerGetInfo; external 'netapi32.dll' name 'NetServerGetInfo';

function SafeWideCharToString(Source: PWideChar): string;
begin
  Result := '';
  if Source <> nil
   then Result := WideCharToString(Source);
end;

function GetLocalWorkstationName: string;
var PServerInfo : PSERVER_INFO_100;
    FResult     : LongInt;
begin
  Result := '';
  FResult := NetServerGetInfo(nil, 100, Pointer(PServerInfo));
  if FResult <> NERR_SUCCESS
   then Exit;
  Result := '\\' + SafeWideCharToString(PServerInfo.sv100_name);
  NetApiBufferFree(PServerInfo);
end;

procedure GetActiveWorkstationUsers(WksName : string; UserList : TStrings);
const PrefMaxLen : Integer = 1024;
var AUserInfo   : ^ATWKSTA_USER_INFO_1;
    PWWkstName  : PWideChar;
    lPWWkstName,
    FResult     : LongInt;
    Index,
    UsrRead,
    UsrTotal,
    ResHandle   : Integer;
begin
  UsrRead := -1;
  UsrTotal := 0;
  ResHandle := 0;
  lPWWkstName := (Length(WksName) + 1) * 2;
  if lPWWkstName > 2
   then GetMem(PWWkstName, lPWWkstName)
   else PWWkstName := nil;
  try
    StringToWideChar(WksName, PWWkstName, lPWWkstName);
    while UsrRead < UsrTotal do
     begin
       FResult := NetWkstaUserEnum(PWWkstName, 1, Pointer(AUserInfo), PrefMaxLen, UsrRead, UsrTotal, ResHandle);
       if (FResult = NERR_SUCCESS) or ((FResult = ERROR_MORE_DATA) and (UsrRead <> 0)) then
        begin
          for Index := 1 to UsrRead do
           with AUserInfo[Index - 1]
            do UserList.Add(SafeWideCharToString(wkui1_logon_domain) + '\' +
                            SafeWideCharToString(wkui1_username));
          NetApiBufferFree(AUserInfo);
        end
       else
        begin
          if (FResult = ERROR_MORE_DATA) and (UsrTotal <> 0)
           then PrefMaxLen := PrefMaxLen * 2
           else raise Exception.Create('NetWkstaUserEnum ' + IntToStr(FResult));
        end;
     end;
  finally
    if lPWWkstName > 2
     then FreeMem(PWWkstName, lPWWkstName);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := GetLocalWorkstationName;
end;

procedure TForm1.Button1Click(Sender: TObject);
var ACursor : TCursor;
    Status  : string;
begin
  ACursor := Screen.Cursor;
  Screen.Cursor := crHourglass;
  ListBox1.Enabled := false;
  Button1.Enabled := false;
  Edit1.Enabled := false;
  Listbox1.Items.Clear;
  try
  try
    GetActiveWorkstationUsers(Edit1.Text, Listbox1.Items);
    GroupBox1.Caption := 'Result for ' + Edit1.Text;
    Status := Format('%d user(s) active on %s', [Listbox1.Items.Count, Edit1.Text]);
  except
    // just translate a few error codes
    on E: ENetAPIException do
     begin
       case E.NetAPIErrorCode of
         5  : Status := 'Access is denied.';
         53 : Status := 'The network path was not found.';
         54 : Status := 'The network is busy.';
         65 : Status := 'Network access is denied.';
         71 : Status := Format('No more connections can be made to %s', [Edit1.Text]);
       end;
     end
    else Status := 'An error occured during the function call';
  end;
  finally
    ListBox1.Enabled := true;
    Button1.Enabled := true;
    Edit1.Enabled := true;
    Panel1.Caption := '  ' + Status;
    ActiveControl := Edit1;
    Screen.Cursor := ACursor;
  end;
end;

end.

// form code

object Form1: TForm1
  Left = 200
  Top = 108
  ActiveControl = Edit1
  BorderStyle = bsToolWindow
  Caption = 'Scan Workstation'
  ClientHeight = 257
  ClientWidth = 283
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 17
    Width = 60
    Height = 13
    Caption = 'Workstation:'
  end
  object Edit1: TEdit
    Left = 72
    Top = 13
    Width = 121
    Height = 21
    TabOrder = 0
  end
  object Button1: TButton
    Left = 200
    Top = 12
    Width = 75
    Height = 25
    Caption = 'Show'
    Default = True
    TabOrder = 1
    OnClick = Button1Click
  end
  object GroupBox1: TGroupBox
    Left = 4
    Top = 40
    Width = 273
    Height = 193
    TabOrder = 2
    object ListBox1: TListBox
      Left = 8
      Top = 16
      Width = 257
      Height = 165
      ItemHeight = 13
      TabOrder = 0
    end
  end
  object Panel1: TPanel
    Left = 0
    Top = 239
    Width = 283
    Height = 18
    Align = alBottom
    Alignment = taLeftJustify
    BevelOuter = bvLowered
    TabOrder = 3
  end
end

Have fun,
Slash/d003303
0
 
d003303Commented:
Do you mean you supply the computer name and get the currently logged on console user ?
0
 
rene_moellerAuthor Commented:
Yes, a more exactly way to put it. And a little piece of code would be nice.
0
Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

 
Edo082297Commented:
Hi

  If your application uses the BDE, you can use the following code to get the user logged on:

function GetCurrUser : String;
var
  pcNetUser : PChar;
begin
  pcNetUser := StrAlloc (256);  

  if DbiGetNetUserName (pcNetUser) = 0 then
    Result := StrPas (pcNetUser)
  else
    Result := '';  

  StrDispose (pcNetUser);
end;

I hope this helps with the username.

Edo
0
 
Edo082297Commented:
Hi
  I just found this after some digging.

>>Untested.

procedure GetComputerName
var
  i : integer;
  ComputerName : string;
begin
  SetLength(ComputerName,NSize);
  if GetComputerName(PChar(ComputerName), NSize) then
    StatusBar.Panels[1].Text:= 'PC: '+ ComputerName;
end;

HTH

Edo
0
 
rene_moellerAuthor Commented:
Thx EDO, but I don't use BDE in the app. I'll keep the example in mind to another time.
0
 
d003303Commented:
mmh, I am fighting around with some netapi32.dll calls right now, always get GPFs... I'll keep digging.

Slash/d003303
0
 
rene_moellerAuthor Commented:
Hi d003303,
I knew this was a "tuffy". Still getting GPF's?

0
 
rene_moellerAuthor Commented:
Thanks d003303,

I'll test it in the week-end. It looks very promising.
0
 
d003303Commented:
oops, I forgot to implement the new exception handler.
The lines
type

  ENetAPIException = class(Exception)
    NetAPIErrorCode : LongInt;
  end;

  PWKSTA_USER_INFO_0 = ^TWKSTA_USER_INFO_0;
should read
type

  ENetAPIException = class(Exception)
    NetAPIErrorCode : LongInt;
    constructor Create(AMsg : string; ErrCode : LongInt);
  end;

constructor ENetAPIException.Create(AMsg : string; ErrCode : LongInt);
begin
  inherited Create(AMsg);
  NetAPIErrorCode := ErrCode;
end;

type

  PWKSTA_USER_INFO_0 = ^TWKSTA_USER_INFO_0;
and the lines
          if (FResult = ERROR_MORE_DATA) and (UsrTotal <> 0)
           then PrefMaxLen := PrefMaxLen * 2
           else raise Exception.Create('NetWkstaUserEnum ' + IntToStr(FResult));
should read
          if (FResult = ERROR_MORE_DATA) and (UsrTotal <> 0)
           then PrefMaxLen := PrefMaxLen * 2
           else raise ENetAPIException.Create('Error calling NetWkstaUserEnum', FResult);

Happy testing,
Slash/d003303
0
 
rene_moellerAuthor Commented:
Thanks d003303,

You are nothing less than brilliant. It works and it was exacltly what I was looking for. Thanks again.
0
 
d003303Commented:
Thx, no prob.
0
 
d003303Commented:
Yo,
another method to get the logged on user(s), but only if they are logged on interactively. This returns one entry for ordinary NT WS/Server, and a list of all users connected via terminals/console on e.g. Citrix WinStation or Hydra (tested).

procedure GetUsersFromRemoteReg(WksName : string; HiveList : TStrings);
var Registry : TRegistry;
    Index    : Integer;
begin
  Registry := TRegistry.Create;
  try
    Registry.RootKey := HKEY_USERS;
    if not Registry.RegistryConnect(WksName)
     then Exit;
    Registry.OpenKey('', false);
    if Registry.HasSubkeys then
     begin
       Registry.GetKeyNames(HiveList);
       for Index := 0 to HiveList.Count - 1
        do if UpperCase(HiveList[Index]) = '.DEFAULT' then
         begin
           HiveList.Delete(Index);
           Break;
         end;
      end;
    Registry.CloseKey;
  finally
    Registry.Free;
  end;
end;

procedure TranslateSIDToAccountNames(WksName : string; HiveList : TStrings);
var Registry : TRegistry;
    lUsrName,
    lDomName,
    lSID,
    peUse,
    Index    : Integer;
    UsrName,
    DomName,
    SID      : PChar;
begin
  Registry := TRegistry.Create;
  try
    Registry.RootKey := HKEY_LOCAL_MACHINE;
    if not Registry.RegistryConnect(WksName)
     then Exit;
    for Index := 0 to HiveList.Count - 1 do
     if Registry.OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\' + HiveList[Index], false) then
      begin
        lSID := Registry.GetDataSize('Sid');
        GetMem(SID, lSID);
        try
          Registry.ReadBinaryData('Sid', SID[0], lSID);
          if IsValidSid(SID) then
           begin
             lUsrName := 0;
             lDomName := 0;
             LookupAccountSid(PChar(WksName), SID, UsrName, lUsrName, DomName, lDomName, peUse);
             GetMem(UsrName, lUsrName);
             GetMem(DomName, lDomName);
             try
               if not LookupAccountSid(PChar(WksName), SID, UsrName, lUsrName, DomName, lDomName, peUse)
                then raise Exception.Create('LookupAccountSid failed');
               HiveList[Index] := string(DomName) + '\' + string(UsrName);
             finally
               FreeMem(DomName, lDomName);
               FreeMem(UsrName, lUsrName);
             end;
           end;
        finally
          Registry.CloseKey;
          FreeMem(SID, lSID);
        end;
      end;
  finally
    Registry.Free;
  end;
end;

Call these functions like the above example,

    GetUsersFromRemoteReg(Edit1.Text, Listbox1.Items);
    TranslateSIDToAccountNames(Edit1.Text, Listbox1.Items);

and have fun.
Slash/d003303
0
All Courses

From novice to tech pro — start learning today.