Solved

Login name on NT4

Posted on 1998-06-05
13
526 Views
Last Modified: 2010-04-06
How do i get the login name from another NT4 workstation in the network?
0
Comment
Question by:rene_moeller
  • 6
  • 5
  • 2
13 Comments
 
LVL 4

Expert Comment

by:d003303
ID: 1350609
Do you mean you supply the computer name and get the currently logged on console user ?
0
 
LVL 1

Author Comment

by:rene_moeller
ID: 1350610
Yes, a more exactly way to put it. And a little piece of code would be nice.
0
 
LVL 1

Expert Comment

by:Edo082297
ID: 1350611
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
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 
LVL 1

Expert Comment

by:Edo082297
ID: 1350612
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
 
LVL 1

Author Comment

by:rene_moeller
ID: 1350613
Thx EDO, but I don't use BDE in the app. I'll keep the example in mind to another time.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1350614
mmh, I am fighting around with some netapi32.dll calls right now, always get GPFs... I'll keep digging.

Slash/d003303
0
 
LVL 1

Author Comment

by:rene_moeller
ID: 1350615
Hi d003303,
I knew this was a "tuffy". Still getting GPF's?

0
 
LVL 4

Accepted Solution

by:
d003303 earned 200 total points
ID: 1350616
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
 
LVL 1

Author Comment

by:rene_moeller
ID: 1350617
Thanks d003303,

I'll test it in the week-end. It looks very promising.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1350618
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
 
LVL 1

Author Comment

by:rene_moeller
ID: 1350619
Thanks d003303,

You are nothing less than brilliant. It works and it was exacltly what I was looking for. Thanks again.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1350620
Thx, no prob.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1350621
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

Featured Post

Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Why does formely good SQL code in Delphi 2009 not work under Windows 10? 5 97
Printing problem 2 93
Delphi Form ownership 4 89
control image tags in a string ? 12 131
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question