[转] 如何获取Windows系统登陆用户名

如何获取Windows系统登陆用户名
关键字 :获取登陆用户名 GetUserName WTSQuerySessionInformation
    一般用 GetUserName(或 GetUserNameEx )函数可得到当前登陆登陆用户名(但不总会得到,下面会分析),此系统函数在Win95、WinNT 及以后所有操作系统中都可用。代码如下:
    BOOL CSecurityTool::GetCurrProcessUser(CString& strName)
    {
        BOOL bRet(TRUE);
        strName = _T("");
        DWORD dwSize = MAX_PATH;
        TCHAR *pszName = new TCHAR[dwSize];
        if (!GetUserName(pszName, &dwSize))
        {
            delete[] pszName;
            pszName = new TCHAR[dwSize];
            bRet = GetUserName(pszName, &dwSize);
         }
        strName = pszName;
        delete[] pszName;
        return bRet;
    }
     此函数目的准确来说是获取当前线程的用户名(MSDN语:retrieves the user name of the current thread)。如果是NT service(NT服务程序)将此进程启动,得到的结果是NT Service进程的用户名,即“SYSTEM”,而不是登陆用户名;同理,如果此进程是通过CreateProcessAsUser创建的,GetUserName获取的用户将是“AsUser”的用户名。另外,如果当前线程正impersonate其他用户环境(用函数ImpersonateLoggedOnUser可达到此目的),它获取的将是其他用户名。因此,此函数只能在特定环境中才可以获取登陆用户名。那如何不因进程本身运行环境的不同,而准确地获取登陆用户名呢? 我们首先看看Windows XP操作系统,它提供了WTSQuerySessionInformation函数,这个函数可以获取会话(session)相关信息,其中一个用 途是获取会话的登陆用户。代码如下:
     BOOL CSecurityTool::GetLogUserXP(CString& strName)
    {
        BOOL bRet = FALSE;
        strName = _T(""); //for xp or above
        TCHAR *szLogName = NULL;
        DWORD dwSize = 0;
        if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, &szLogName, &dwSize))
        {
            strName = szLogName;
            WTSFreeMemory(szLogName);
            bRet = TRUE;
        }
        return bRet;
     }
     如果用户还没有登陆,获取的用户名将为空(譬如在NT service程序中)。虽然MSDN中指明WTSQuerySessionInformation可以在win2000 pro 中使用,但由于安装win2000 professional时,terminal service是没有安装的(除非用特殊方法如第三方工具可以安装terminal service) ,所以调用此函数会失败,需要寻找其他方法。
    再看Win2000:查阅了许多资料,未能发现在Win2000中直接获取登陆用户名的系统函数,看来只有曲线救国了。
    由于Explorer.exe进程的用户肯定是当前登 陆用户,所以获取到它的用户名就等于获取到登陆用户名。具体实现:首先枚举系统所有进程,找到Explorer.exe进程ID,然后通过ID获取此 进程的令牌(Token),再获取令牌的用户信息,即为登陆用户名。代码如下:
    //获取win2000登陆用户
    BOOL CSecurityTool::GetLogUser2K(CString& strName)
    {
        BOOL bRet = FALSE;
        HANDLE hSnapshot = NULL;
        strName = _T("");
         __try
         {
             // Get a snapshot of the processes in the system
            hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
            if (hSnapshot == NULL)
            {
                __leave;
            }
            PROCESSENTRY32 pe32;
            pe32.dwSize = sizeof(pe32); // Find the "System" process
            BOOL fProcess = Process32First(hSnapshot, &pe32);
            while (fProcess)
            {
                if (lstrcmpi(pe32.szExeFile, TEXT("explorer.exe")) == 0)
                {
                    TCHAR szUserName[MAX_PATH];
                    if (GetProcessUser(pe32.th32ProcessID, szUserName, MAX_PATH))
                    {
                        bRet = TRUE;
                        strName = szUserName;
                    }
                    break;
                }
                fProcess = Process32Next(hSnapshot, &pe32);
            }
            if (!fProcess)
            {
                __leave; // Didn''t find "System" process
            }
        }
        __finally
        {
            // Cleanup the snapshot
            if (hSnapshot != NULL) CloseHandle(hSnapshot);
        }
        return bRet;
    }

    //获取进程的用户名
    BOOL CSecurityTool::GetProcessUser(DWORD dwProcessID, TCHAR *szUserName, DWORD nNameLen)
    {
        BOOL fResult = FALSE;
        HANDLE hProc = NULL;
        HANDLE hToken = NULL;
        TOKEN_USER *pTokenUser = NULL;
        __try {
            // Open the process with PROCESS_QUERY_INFORMATION access
            hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessID);
            if (hProc == NULL) { __leave; }
            fResult = OpenProcessToken(hProc, TOKEN_QUERY, &hToken);
            if (!fResult) 
            { 
                __leave;
            }
            DWORD dwNeedLen = 0;
            fResult = GetTokenInformation(hToken,TokenUser, NULL, 0, &dwNeedLen);
            if (dwNeedLen > 0)
            {
                pTokenUser = (TOKEN_USER*)new BYTE[dwNeedLen];
                fResult = GetTokenInformation(hToken, TokenUser, pTokenUser, dwNeedLen, &dwNeedLen);
                if (!fResult)
                { 
                     __leave;
                }
            }
            else
            { 
                 __leave;
            }
           
            SID_NAME_USE sn;
            TCHAR szDomainName[MAX_PATH];
            DWORD dwDmLen = MAX_PATH;
            fResult = LookupAccountSid(NULL, pTokenUser->User.Sid, szUserName, &nNameLen, szDomainName, &dwDmLen, &sn);
            }
            __finally
            { 
                 if (hProc) 
                      ::CloseHandle(hProc); 
                 if (hToken) 
                      ::CloseHandle(hToken); 
                 if (pTokenUser) 
                      delete[] (char*)pTokenUser; 
                 return fResult;
            }
     }
     熟悉win2000系统的同仁肯定会发现此方法存在缺陷:eXPlorer.exe进程可能不存在(被用户kill掉或自己中断了),这时候这个方法就获取不到登陆用户名。但在没有更好方法前,只能将就。 总结 
    因此,软件中如果需要获取登陆用户名,要根据具体情况选择不同的方法。如果确信自己的进程一定在登陆用户环境下启动,则GetUserName即可;否则,需要采用后面的两种方法,当然,在使用前需要判断一下操作系统的类型。

    
欢迎诸位与大家分享其他方法。

posted on 2008-03-10 16:29  高血压的熊  阅读(1540)  评论(0编辑  收藏  举报