Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用API调用重现quser.exe?_C#_C++_.net_Winapi_Terminal Services - Fatal编程技术网

C# 如何使用API调用重现quser.exe?

C# 如何使用API调用重现quser.exe?,c#,c++,.net,winapi,terminal-services,C#,C++,.net,Winapi,Terminal Services,允许客户端查看远程RDP服务器上的用户会话。比如说, C:\>quser /server:MyRDPserver USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME userA 3 Disc 1+20:03 08/07/2014 12:36 userB

允许客户端查看远程RDP服务器上的用户会话。比如说,

 C:\>quser /server:MyRDPserver

 USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
 userA                                     3  Disc      1+20:03  08/07/2014 12:36
 userB                                     4  Disc      1+22:28  08/07/2014 10:38
我想把这个功能构建成C++或C语言程序。是的,我可以生成quser.exe并解析输出,但是是否有Win32 API或.Net framework类可以提供相同的信息?具体而言:

  • 用户名
  • 连接状态
  • 登录时间

我发现使用WMI(Win32_LoggedOnUser)查找相同的信息是不可靠的,因为它经常列出过时的连接。我也尝试过枚举HKEY_用户的子键并查找Volatile环境键的方法,但这也遇到了同样的问题。

您可以调用Win32 API来创建进程并将“quser/server:MyRDPserver”作为参数传递,我通常这样做:

PROCESS_INFORMATION process_info;
STARTUPINFOA startup_info;
string cmdline2;
char error_msg[1024];

memset(&process_info, 0, sizeof(process_info));
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);

argc = argarray.size();
for(int i = 0; i < argc; i++) {
    cmdline2 += argarray.at(i);
    if(i != (argc - 1)) cmdline2 += " ";
}

string command = suCmdLineRemoveQuotations(argarray.at(0));
retval = CreateProcessA(command.c_str(), (LPSTR)cmdline2.c_str(), NULL, NULL, TRUE,
    0, NULL, NULL, &startup_info, &process_info);

if (!retval) {
    windows_error_string(error_msg, sizeof(error_msg));
    error = error_msg;
    return false;
}

WaitForSingleObject(process_info.hProcess, msecs);
if(GetExitCodeProcess(process_info.hProcess, &status)) {
    // status maybe is STILL_ACTIVE, in that case, the process is killed
    if(status == STILL_ACTIVE) {
        TerminateProcess(process_info.hProcess, 1);
    }
    ecode = status;
}

return true;
PROCESS\u INFORMATION PROCESS\u INFORMATION;
STARTUPINFOA启动信息;
字符串cmdline2;
字符错误消息[1024];
memset(&process_info,0,sizeof(process_info));
memset(&startup_info,0,sizeof(startup_info));
startup_info.cb=sizeof(startup_info);
argc=argarray.size();
对于(int i=0;i

当进程启动时,您可以重定向输出。如果使用Qt,问题就会变得简单,您可以使用QProcess来实现。

我将回答我自己的问题

首先,您需要确保在目标计算机上正确设置了权限。这需要将HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\AllowRemoteRPC设置为1。执行此操作的powershell脚本是:

# Get the service account credential
$cred = Get-Credential my_admin_account
$Target_Computers = @("Computer_1","Computer_2")

# open the remote registry
[long]$HIVE_HKLM = 2147483650
foreach($c in $Target_Computers)
{
  $StdRegProv = Get-WmiObject -List -Namespace root\default -ComputerName $c -Credential $cred | where { $_.Name -eq "StdRegProv" }
  $StdRegProv.SetDWORDValue($HIVE_HKLM, "SYSTEM\CurrentControlSet\Control\Terminal Server", "AllowRemoteRPC", 1)
}

正如Xearinox所说,对于C++,可以使用Win32 API中的WTSXXX函数。假设你的计算机不是XP,这里有一些C++代码:

#include <string>
#include <iostream>
#include <iomanip>
#include <windows.h>
#include <WtsApi32.h>

using namespace std;

const unsigned num_connection_states = 10;
const wchar_t* connection_state_list[num_connection_states] = {
    L"Active",
    L"Connected",
    L"ConnectQuery",
    L"Shadow",
    L"Disc",
    L"Idle",
    L"Listen",
    L"Reset",
    L"Down",
    L"Init" };

int print_error(DWORD err)
{
  // format the message
  LPTSTR* ppBuffer = nullptr;
  DWORD retval = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, err, 0, reinterpret_cast<LPTSTR>(ppBuffer), 0, nullptr);

  // print out
  wcerr << "Error: *ppBuffer" << endl;
  return 1;
}

wstring format_time(const LARGE_INTEGER& time)
{
  // convert to a local Win32 file time
  FILETIME ft = { time.LowPart, time.HighPart };
  FileTimeToLocalFileTime( &ft, &ft );

  // convert to a system time
  SYSTEMTIME st;
  FileTimeToSystemTime( &ft, &st );

  wchar_t local_date[255], local_time[255];
  GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, local_date, sizeof(local_date)/sizeof(wchar_t) );
  GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );

  wstring result = local_date;
  result.append(L" ");
  result.append(local_time);

  return result;
}

const _int64 SECOND = 10000000;
const _int64 MINUTE = 60*SECOND;
const _int64 HOUR = 60*MINUTE;
const _int64 DAY = 24*HOUR;

wstring format_timespan(const LARGE_INTEGER& timespan)
{
  // convert to a local Win32 file time
  FILETIME ft = { timespan.LowPart, timespan.HighPart };
  FileTimeToLocalFileTime( &ft, &ft );

  // convert to a system time
  SYSTEMTIME st;
  FileTimeToSystemTime( &ft, &st );

  wchar_t local_time[255];
  int daydiff = floor(
  GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );

  wstring result = local_date;
  result.append(L" ");
  result.append(local_time);

  return result;
}

int wmain(int argc, wchar_t* argv[])
{
  // check args
  if(argc > 2)
  {
    wcout << "Usage: " << argv[0] << " [server_name]\n";
    return 1;
  }

  // server name
  bool current_server = true;
  wstring server_name = L".";
  if(argc == 2)
  {
    server_name = argv[1];
    current_server = false;
  }

  // open the server
  HANDLE hServer;
  if(current_server)
    hServer = WTS_CURRENT_SERVER_HANDLE;
  else
    hServer = WTSOpenServer(const_cast<LPWSTR>(server_name.c_str()));  

  // enumerate through the sessions
  DWORD Count = 0;
  WTS_SESSION_INFO* pSessionInfo = nullptr;
  BOOL success = WTSEnumerateSessions(hServer, 0, 1, &pSessionInfo, &Count);
  if(success == 0)
    return false;

  // write the headers
  wcout << " " << left << setw(24) << "USERNAME";
  wcout << setw(19) << "SESSIONNAME";
  wcout << "ID  ";
  wcout << setw(9) << "STATE";
  wcout << "IDLE TIME  LOGON TIME";

  // loop through each session
  for(unsigned long s=0; s<Count; s++)
  {
    LPTSTR pBuffer = nullptr;
    DWORD BytesReturned = 0;
    wcout << "\n " << left;

    // try getting all info at once
    WTSINFO* info = nullptr; 
    success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSSessionInfo, reinterpret_cast<LPTSTR*>(&info), &BytesReturned);
    bool have_wtsinfo = true;
    if(!success)
    {
      // see why failed
      DWORD err = GetLastError();
      if(err == ERROR_NOT_SUPPORTED)
        have_wtsinfo = false;
      else
        return print_error(err);
    }

    // print user name 
    wstring user_name;
    if(have_wtsinfo)
      user_name = info->UserName;
    else
    {
      success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSUserName, &pBuffer, &BytesReturned);
      if(!success)
        continue;
      user_name = pBuffer;
      WTSFreeMemory(pBuffer);
    }
    wcout << setw(24) << user_name;

    // print session name 
    wstring session_name;
    if(have_wtsinfo)
      session_name = info->WinStationName;
    else
    {
      success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSWinStationName, &pBuffer, &BytesReturned);
      if(!success)
        continue;
      session_name = pBuffer;
      WTSFreeMemory(pBuffer);
    }
    wcout << setw(19) << session_name;

    // print session ID
    wcout << right << setw(2) << pSessionInfo[s].SessionId;

    // print connection state
    WTS_CONNECTSTATE_CLASS connect_state;
    if(have_wtsinfo)
      connect_state = info->State;
    else
    {
      success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSConnectState, &pBuffer, &BytesReturned);
      if(!success)
        continue;
      connect_state = *reinterpret_cast<WTS_CONNECTSTATE_CLASS*>(pBuffer);
      WTSFreeMemory(pBuffer);
    }
    if(connect_state>=num_connection_states)
      continue;
    wcout << "  " << left << setw(8) << connection_state_list[connect_state];

    // get idle time 
    LARGE_INTEGER idle = info->CurrentTime;
    idle.QuadPart -= info->LogonTime.QuadPart;

    // print logon time - not supported
    if(info->LogonTime.QuadPart!=0)
    {
      wcout << format_time(info->LogonTime);
    }

    // clean up
    WTSFreeMemory(info);
  }

  // clean up
  WTSFreeMemory(pSessionInfo);
  if(!current_server)
    WTSCloseServer(hServer);
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
const unsigned num_connection_states=10;
const wchar_t*连接状态列表[num_连接状态]={
L“活动”,
L“已连接”,
L“连接查询”,
L“影子”,
L“光盘”,
L“空闲”,
我“听着”,
L“重置”,
L“向下”,
L“Init”};
整数打印错误(DWORD err)
{
//格式化消息
LPTSTR*ppBuffer=nullptr;
DWORD retval=FormatMessage(格式化消息分配缓冲区,nullptr,err,0,重新解释转换(ppBuffer),0,nullptr);
//打印出来

wcerr可能WTS函数可以帮助您。我已经想到了这一点,但我要寻找的是关于如何使用与quser.exe相同的API函数的信息