c# - 您如何在所有版本的 Windows 上可靠地读取用户的显示(名字和姓氏)名称?

标签 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 信息,当不在域上时,但您需要先知道用户名和密码,然后它可能会查找友好的姓名。]

RElated Question: does not mention the problem here

最佳答案

这是移植到 C# 的 Warren 解决方案。我添加了从域名中检索域 Controller 的 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;
}

关于c# - 您如何在所有版本的 Windows 上可靠地读取用户的显示(名字和姓氏)名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3686201/

相关文章:

c# - System.Runtime.Serialization.InvalidDataContractException Windows Phone 8

delphi - 记录数组中的默认 boolean 值 - Delphi

delphi - 如何为 firemonkey TForm OnKeyDown 事件 : 分配快捷键

sqlite - 日期参数在Delphi SQLite查询中误读

winapi - 是否有相当于 nanosleep 的 Windows?

winapi - 我们如何在组装中清除控制台?

c++ - MySQL 数据库连接到 c++ win32 项目

c# - 在MailMessage中添加Attachment base64图片,并在html body中读取

c# - 在 C# 中获取最后 'N' 个季度

c# - 带有自定义事件的天蓝色数据工厂项目