Solved

Login name on NT4

Posted on 1998-06-05
13
522 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
Comment Utility
Do you mean you supply the computer name and get the currently logged on console user ?
0
 
LVL 1

Author Comment

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

Expert Comment

by:Edo082297
Comment Utility
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
 
LVL 1

Expert Comment

by:Edo082297
Comment Utility
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
Comment Utility
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
Comment Utility
mmh, I am fighting around with some netapi32.dll calls right now, always get GPFs... I'll keep digging.

Slash/d003303
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

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

0
 
LVL 4

Accepted Solution

by:
d003303 earned 200 total points
Comment Utility
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
Comment Utility
Thanks d003303,

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

Expert Comment

by:d003303
Comment Utility
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
Comment Utility
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
Comment Utility
Thx, no prob.
0
 
LVL 4

Expert Comment

by:d003303
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video discusses moving either the default database or any database to a new volume.

763 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now