程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何獲取Windows系統登陸用戶名

如何獲取Windows系統登陸用戶名

編輯:關於VC++

一般用 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即可;否則,需要采用後面的兩種方法,當然,在使用前需要判斷一下操作系統的類型。附 :源代碼。

歡迎諸位與大家分享其他方法。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved