2

I've done a fair amount of searching and have found some useful tips right here on Stackoverflow to get the Username and Computer name - and I've even found some code posted by Norrit on Delphipages doing exactly what I need it to do - except that when running it under a Win64 Target Platform, obtaining the Full Name doesn't work - it returns an empty string. It returns the full name fine when running a Win32 build.

The GetCurrentUser and GetDomainServerName functions work in both Win32 and Win64.

Doing Google searches for "delphi netusergetinfo" brings up a lot of results which are more than 10 years old - even before Delphi had Win64. It also brings up an Experts-Exchange answer which links to some lanman example code which 404's on me, so I'm a bit stuck there.

Does anybody know what changes I have to make to get GetDomainFullName to work under Win64 - or does anybody have alternate code I can use to obtain the Full Name of the currently logged on user?

Full code shown below in case of link rot.

unit NetAPI32;

interface

uses
  Windows, SysUtils;

  function GetCurrentUser(): String;
  function GetDomainServerName(): String;
  function GetDomainFullName(ServerName, UserName: String): String;

implementation

  function NetUserGetInfo(ServerName, UserName: PWideChar; Level: DWORD; var Buffer: Pointer): DWORD; stdcall; external 'netapi32.dll' name 'NetUserGetInfo';
  function NetApiBufferFree(Buffer: pointer): DWORD; stdcall; external 'netapi32.dll' name 'NetApiBufferFree';
  function NetWkstaUserGetInfo(ServerName: PWideChar; Level: DWORD; var Buffer: Pointer): Longint; stdcall; external 'netapi32.dll' name 'NetWkstaUserGetInfo';

type
  TUserInfo1 = packed record
    UserName: PWideChar;
    DomainName : PWideChar;
    OtherDomainNames: PWideChar;
    ServerName: PWideChar;
  end;
  PUserInfo1 = ^TUserInfo1;

  TUserInfo2 = packed record
    Name: PWideChar;
    Password: PWideChar;
    PasswordAge: DWORD;
    Priv: DWORD;
    HomeDir: PWideChar;
    Comment: PWideChar;
    Flags: DWORD;
    ScriptPath: PWideChar;
    AuthorFlags: DWORD;
    FullName: PWideChar;
    UserComment: PWideChar;
    Params: PWideChar;
    WorkStations: PWideChar;
    LastLogon: DWORD;
    LastLogoff: DWORD;
    AccountExpires: DWORD;
    MaxStorage: DWORD;
    UnitsPerWeek: DWORD;
    LogonHours: DWORD;
    BadPasswordCount: DWORD;
    LogonCount: DWORD;
    Server: PWideChar;
    CountryCode: DWORD;
    Codepage: DWORD;
  end;
  PUserInfo2 = ^TUserInfo2;

function GetCurrentUser(): String;
var
  username: String;
  size: DWORD;
begin
  size := 255;
  SetLength(username, size) ;
  if GetUserName(PChar(username), size) then
    Result := Copy(username, 1, size - 1)
  else
    Result := '';
end;

function GetDomainServerName(): String;
var
  PUI1: PUserInfo1;
begin
  Result := '';
  if NetWkstaUserGetInfo(nil, 1, Pointer(PUI1)) = 0 then
  begin
    try
      Result := WideCharToString(PUI1^.ServerName);
    finally
      NetApiBufferFree(PUI1);
    end;
  end;
end;

function GetDomainFullName(ServerName, UserName: String): String;
var
  PUI2: PUserInfo2;
begin
  Result := '';
  if NetUserGetInfo(PWideChar(WideString(ServerName)), PWideChar(WideString(UserName)), 2, Pointer(PUI2)) = 0 then
    try
      Result := WideString(PUI2^.FullName);
    finally
      NetApiBufferFree(PUI2);
    end;
end;

end.

Example of how to use:

ShowMessage(GetDomainFullName(GetDomainServerName(), GetCurrentUser()));

Delphi XE6 running on Windows 2012 R2

Community
  • 1
  • 1
KeyszerS
  • 684
  • 9
  • 29
  • 1
    Use [System.SysUtils.Win32Check](http://docwiki.embarcadero.com/Libraries/XE6/en/System.SysUtils.Win32Check) to get the reason why the api call fails – Sir Rufo Sep 03 '14 at 20:31
  • `.LogonHours` must be `PByte` as per [`USER_INFO_2`](https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/ns-lmaccess-user_info_2). – AmigoJack Jul 29 '22 at 21:33

1 Answers1

7

The use of packed is wrong, and has always been wrong. You just got away with it because it so happened that the layout on 32 bit is the same packed as aligned.

Remove the packed modifier from the struct declarations and your code will work.

Since you've moved to Unicode Delphi, you can stop using WideString now.

function GetDomainFullName(const ServerName, UserName: string): string;
var
  PUI2: PUserInfo2;
begin
  if NetUserGetInfo(PChar(ServerName), PChar(UserName), 2, Pointer(PUI2)) = 0 then
    try
      Result := PUI2^.FullName;
    finally
      NetApiBufferFree(PUI2);
    end
  else
    Result := '';
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490