如何可靠地在所有版本的Windows上读取用户的显示(第一个和最后一个)名称?

War*_* P 4 c# delphi winapi msdn

我发现在Windows 7 64位上,在具有域名的机器上,GetUserNameEx(3,....)应该将扩展名称格式DisplayName(== 3)放入缓冲区,工作正常.

但是,它不适用于Windows 7 32位,工作组上的虚拟机,而不是域,它返回ERROR_NONE_MAPPED.

例如,你如何以适用于Windows的方式阅读该人的友好名称"Fred Smith"?GetUserNameEx明显被破坏了.实际上,没有破坏,我被告知,只是不打算为不在域上的用户工作.我想知道为什么不存在本地SAM信息?并且似乎没有其他直接API来执行此操作.

如果Windows为您提供ERROR_NONE_MAPPED,那么您运气不佳,可能不在域上.所以这不是API的友好区域.

[看起来有可能,调用NetUserGetInfo,读取本地SAM信息,当不在域上时,但您需要首先知道用户名和密码,然后它可能会查找友好名称.]

相关问题:这里没有提到问题

Mat*_*ers 7

这是Warren的解决方案移植到C#.我添加了从域名中检索域控制器的IP,因为至少在我的域上,仅使用\\<domain>服务器名称不起作用.

using System;
using System.Text;
using System.Net;
using System.Runtime.InteropServices;
using System.DirectoryServices.ActiveDirectory;

[DllImport("secur32.dll", CharSet = CharSet.Auto)]
private static extern int GetUserNameEx (int nameFormat, StringBuilder userName, ref uint userNameSize);

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int NetUserGetInfo ([MarshalAs(UnmanagedType.LPWStr)] string serverName,
                                          [MarshalAs(UnmanagedType.LPWStr)] string userName,
                                          int level, out IntPtr bufPtr);

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern long NetApiBufferFree (out IntPtr bufPtr);

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct USER_INFO_10
{
    [MarshalAs(UnmanagedType.LPWStr)] public string usri10_name;
    [MarshalAs(UnmanagedType.LPWStr)] public string usri10_comment;
    [MarshalAs(UnmanagedType.LPWStr)] public string usri10_usr_comment;
    [MarshalAs(UnmanagedType.LPWStr)] public string usri10_full_name;
}

private string getUserDisplayName ()
{
    var username = new StringBuilder(1024);
    uint userNameSize = (uint) username.Capacity;

    // try to get display name and convert from "Last, First" to "First Last" if necessary
    if (0 != GetUserNameEx(3, username, ref userNameSize))
        return Regex.Replace(username.ToString(), @"(\S+), (\S+)", "$2 $1");

    // get SAM compatible name <server/machine>\\<username>
    if (0 != GetUserNameEx(2, username, ref userNameSize))
    {
        IntPtr bufPtr;
        try
        {
            string domain = Regex.Replace(username.ToString(), @"(.+)\\.+", @"$1");
            DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, domain);
            DomainController dc = DomainController.FindOne(context);

            if (0 == NetUserGetInfo(dc.IPAddress,
                                    Regex.Replace(username.ToString(), @".+\\(.+)", "$1"),
                                    10, out bufPtr))
            {
                var userInfo = (USER_INFO_10) Marshal.PtrToStructure(bufPtr, typeof (USER_INFO_10));
                return Regex.Replace(userInfo.usri10_full_name, @"(\S+), (\S+)", "$2 $1");
            }
        }
        finally
        {
            NetApiBufferFree(out bufPtr);
        }
    }

    return String.Empty;
}
Run Code Online (Sandbox Code Playgroud)

  • 由于您已经满意地回答了自己的问题,我发布了一个替代语言版本(这可能更容易移植到C++),因为我预计它会在将来因为同样的原因找到您的问题时帮助其他人我做到了. (2认同)