【问题标题】:Getting the full-name of the current user, returns an empty string (C#/C++)获取当前用户的全名,返回一个空字符串(C#/C++)
【发布时间】:2010-06-07 14:27:35
【问题描述】:
  • 我尝试获取当前登录用户的全名(全名,而不是用户名)。

  • 以下代码 C#、C++ 工作正常,但在未连接到网络的 XP 计算机上,如果我在登录后约 20 分钟运行它会得到空字符串(它在第一个 ~20 分钟后运行正常登录)

  • 使用 Win32 API (GetUserNameEx) 而不是 PrincipalContext,因为 PrincipalContext 在离线工作时可能需要长达 15 秒。

  • 任何帮助,为什么我得到一个空字符串作为结果虽然指定了用户全名???

- C#代码

    public static string CurrentUserFullName
    {
        get
        {
            const int EXTENDED_NAME_FORMAT_NAME_DISPLAY = 3;
            StringBuilder userName = new StringBuilder(256);
            uint length = (uint) userName.Capacity;
            string ret;

            if (GetUserNameEx(EXTENDED_NAME_FORMAT_NAME_DISPLAY, userName, ref length))
            {
                ret = userName.ToString();
            }
            else
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new Win32Exception("GetUserNameEx Failed. Error code - " + errorCode);
            }

            return ret;
        }
    }

    [DllImport("Secur32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool GetUserNameEx(int nameFormat, StringBuilder lpNameBuffer, ref uint lpnSize);

- C++ 代码

#include "stdafx.h"
#include <windows.h>
#define SECURITY_WIN32
#include <Security.h>
#pragma comment( lib, "Secur32.lib" )

int _tmain(int argc, _TCHAR* argv[])
{
    char szName[100];
    ULONG nChars = sizeof( szName );

    if ( GetUserNameEx( NameDisplay, szName, &nChars ) )
    {
        printf( "Name: %s\n", szName);
    }
    else
    {
        printf( "Failed to GetUserNameEx\n" );      
        printf( "%d\n", GetLastError() );
    }
    return 0;
}

【问题讨论】:

    标签: c# c++ winapi


    【解决方案1】:

    函数GetUserNameExNameDisplay不能在离线模式下工作。仅当计算机在线时才能访问此信息。我建议您实现一些信息缓存,例如全名或其他只能在在线模式下访问的信息。例如,如果计算机在线,您可以检索和保存完整用户名等信息。因此,您可以在注册表中的某些配置文件中包含用户 SID 与其全名之间的映射。如果您不能直接提供全名,您可以从现金中获取信息。

    Windows 有许多不同的通知(如NotifyAddrChange),您可以使用(如果需要)监控从在线模式到离线模式的变化。

    您可以从LsaGetLogonSessionDataWTSQuerySessionInformation API(GetUserNameEx 你已经知道)获得有关当前用户会话的大多数信息(也可以在离线模式下),但您不会在其中找到完整的用户名。

    如果您确实找到了在离线模式下获取用户全名的方法,请将信息发布给我。

    【讨论】:

    • 问题是我的站可能一直离线。在 C# 中,您可以使用 UserPrincipal.Current.DisplayName (UserPrincipal namespace: System.DirectoryServices.AccountManagement) 轻松获取完整的用户名(无论您的站点是否连接到网络)。问题是此调用可能需要 5 -15 秒断开连接,这对我来说太多了(我可以第一次缓存它,但第一次调用仍然是 10 秒太多了)
    • @Nir:对我来说,UserPrincipal.Current.DisplayName 在断开连接的站点上抛出 PrincipalServerDownException。
    【解决方案2】:

    尝试使用 GetUserNameExA(用于 ASCII)而不是 GetUserNameEx 宏。它有帮助吗?也打印程序的输出。

    【讨论】:

    • 我刚试过。 GetUserNameExA 的 GetUserNameEx 结果相同。我打印了错误代码 1332,这意味着“没有完成帐户名称和安全 ID 之间的映射”。但是,为当前用户指定了一个全名,并且在登录后约 20 分钟开始返回有效结果。它因未知原因停止工作(我搜索了病毒,禁用了屏幕保护程序以及任何其他可能在这 20 分钟内出现问题的东西......)
    【解决方案3】:

    我很好奇:对于“永久离线”站,用户名存储在哪里(在操作系统中)?通过浏览控制面板用户,看起来本地用户帐户没有地方存储“名称显示”,只有一个用户名。

    未连接节点的数据存储在哪里对我来说是个谜。如果(实际上)数据只存储在域控制器中,我唯一能想到的就是如前所述缓存信息。

    【讨论】:

      【解决方案4】:

      所以使用第一个,检查结果,然后通过异步委托调用第二个。您的应用不会有任何延迟,而且全名肯定不是它的核心功能 - 我希望 :-)

      【讨论】:

        【解决方案5】:

        请尝试在您的计算机上禁用 UAC。我想它应该在那之后工作。

        禁用它的步骤。

        1. 转到控制面板。
        2. 然后发给用户。
        3. 选择您要保留的管理员帐户。
        4. 删除您不希望拥有的具有管理员权限的帐户。

        如果将来您想创建任何具有管理员权限的新帐户,您可以创建一个帐户并使用更改帐户类型将其设为管理员帐户。

        【讨论】:

          猜你喜欢
          • 2011-04-01
          • 1970-01-01
          • 2022-06-15
          • 2016-09-21
          • 2018-08-15
          • 2014-12-22
          • 1970-01-01
          • 2014-12-15
          • 1970-01-01
          相关资源
          最近更新 更多