I have found that on Windows 7 64 bit, on a machine with a domain name, GetUserNameEx( 3, .... ) which should get the extended name format DisplayName (==3), into a buffer,
I have a solution that appears to work, which in general means:
Sample code (in Delphi), ported to C# below in Matt's answer:
type
EProcError = class( Exception );
TGetUserNameExWProc = function( FormatType : Integer; Buffer : PWideChar; var BufSize : Integer ) : DWORD; stdcall;
var
_GetUserNameExW : TGetUserNameExWProc;
procedure GetProcedureAddress( var P : Pointer; const ModuleName, ProcName : string );
var
ModuleHandle : HMODULE;
begin
if not Assigned( P ) then
begin
ModuleHandle := GetModuleHandle( pChar( ModuleName ) );
if ModuleHandle = 0 then
begin
ModuleHandle := SafeLoadLibrary( pChar( ModuleName ) );
if ModuleHandle = 0 then
raise EProcError.Create( 'Unable to load module' );
end;
P := GetProcAddress( ModuleHandle, pChar( ProcName ) );
if not Assigned( P ) then
raise EProcError.Create( 'Unable to get proc address' );
end;
end;
function MyGetUserNameEx( aFormat : Integer ) : string;
var
sz : Integer;
sz2 : Integer;
ret : Integer;
begin
if not Assigned( _GetUserNameExW ) then
GetProcedureAddress( Pointer( @_GetUserNameExW ), 'secur32.dll', 'GetUserNameExW' );
if Assigned( _GetUserNameExW ) then
begin
sz := 2000;
SetLength( Result, sz );
Result[ 1 ] := Chr( 0 );
ret := _GetUserNameExW( { 3=NameDisplay } aFormat, PWideChar( Result ), sz );
if ret <> 0 then
begin
sz2 := StrLen( PWideChar( Result ) ); // workaround WinXP API bug
if sz2 < sz then // WinXP bug.
sz := sz2;
SetLength( Result, sz )
end
else
begin
ret := GetLastError;
if ret = ERROR_NONE_MAPPED then
Result := ''
else
Result := 'E' + IntToStr( ret );
end;
end;
end;
function MyNetUserGetInfo : string;
const
netapi32 = 'netapi32.dll';
type
TNetUserGetInfo = function( servername, username : LPCWSTR; level : DWORD; var bufptr : PByte ) : DWORD; stdcall;
TNetApiBufferFree = function( Buffer : PByte ) : DWORD; stdcall;
USER_INFO_10 = record
usri10_name : PWideChar;
usri10_comment : PWideChar;
usri10_usr_comment : PWideChar;
usri10_full_name : PWideChar;
end;
P_USER_INFO_10 = ^USER_INFO_10;
var
_NetUserGetInfo : TNetUserGetInfo;
_NetApiBufferFree : TNetApiBufferFree;
ret : DWORD;
servername : string;
username : string;
level : Cardinal;
info : P_USER_INFO_10;
pbuf : PByte;
pwuser : PWideChar;
n : Integer;
begin
ret := 0;
_NetUserGetInfo := nil;
GetProcedureAddress( Pointer( @_NetUserGetInfo ), netapi32, 'NetUserGetInfo' ); // raises EProcError
if not Assigned( _NetUserGetInfo ) then
Result := 'FunctionNotFound'
else
begin
// usernamesize := 200;
username := MyGetUserNameEx( 2 );
if username = '' then
begin
Result := 'CanNotGetUserName';
Exit;
end;
n := Pos( '\', username ); //' recover SO code formatting
if n > 0 then
begin
servername := '\\' + Copy( username, 1, n - 1 );
username := Copy( username, n + 1, Length( username ) );
end;
level := 10;
pbuf := nil;
pwuser := PWideChar( username );
info := nil;
if servername = '' then
ret := _NetUserGetInfo( { servername } nil, pwuser, level, pbuf )
else
ret := _NetUserGetInfo( PWideChar( servername ), pwuser, level, pbuf );
if ret = 0 then
begin
info := P_USER_INFO_10( pbuf );
if Assigned( info ) then
Result := info.usri10_full_name;
GetProcedureAddress( Pointer( @_NetApiBufferFree ), netapi32, 'NetApiBufferFree' );
if Assigned( info ) and Assigned( _NetApiBufferFree ) then
_NetApiBufferFree( pbuf );
end
else
begin
if ret = 2221 then
Result := 'Error_USER ' + username
else if ret = 1722 then
Result := 'Error_RPC ' + servername
else
Result := 'E' + IntToStr( ret );
end;
end;
end;
Edit: Nov 2011; Removed dead link.