Delphi6:需要知道的是我的应用程序在控制台会话或远程桌面会话中运行

时间:2013-07-11 21:06:12

标签: delphi delphi-6

我的应用程序是从远程桌面客户端不时访问的,我想知道它是否正在控制台会话或远程桌面会话中使用,如果以后是这种情况并且会话已断开连接(用户已断开连接但未记录它应该重定向到控制台(如Windows XP上的“tscon.exe 0 / dest:console”)。 现在,我正在运行shell脚本来实现它(使用“query.exe用户”和“tscon.exe”),但希望我的Delhi6应用程序能够做到这一点。

1 个答案:

答案 0 :(得分:3)

我使用以下

const
  SM_REMOTESESSION = $1000;
if GetSystemMetrics(SM_REMOTESESSION) <> 0 then
begin
  // you are in a remote session
end

根据GetSystemMetrics的MSDN页面:
SM_REMOTESESSION = 0x1000
此系统度量标准用于终端服务环境中。如果调用进程与终端服务客户端会话关联,则返回值为非零。如果调用进程与终端服务控制台会话关联,则返回值为0。 Windows Server 2003和Windows XP:控制台会话不一定是物理控制台。有关详细信息,请参阅WTSGetActiveConsoleSessionId

我在Delphi 2007中使用它并且该功能是在Windows单元中定义的,但我确实需要自己定义常量。我不知道Delphi 6是否定义了函数。最低支持的Windows版本是Windows 2000,因此您应该可以使用它,除非您要回去。

-

要查找会话的当前状态,您需要WTSQuerySessionInformation功能。您可以使用此功能查找当前会话的大量信息,包括当前状态。

我在Embarcadero论坛中找到了一个条目,它给了我起始代码。该帖子被称为remote desktop question

以下是您需要的一些常量和函数原型:


const
  WTS_CURRENT_SERVER_HANDLE: THandle = 0;
  WTS_CURRENT_SESSION: DWORD = DWORD(-1);


type
  WTS_INFO_CLASS = (
    WTSInitialProgram,
    WTSApplicationName,
    WTSWorkingDirectory,
    WTSOEMId,
    WTSSessionId,
    WTSUserName,
    WTSWinStationName,
    WTSDomainName,
    WTSConnectState,
    WTSClientBuildNumber,
    WTSClientName,
    WTSClientDirectory,
    WTSClientProductId,
    WTSClientHardwareId,
    WTSClientAddress,
    WTSClientDisplay,
    WTSClientProtocolType,
    WTSIdleTime,
    WTSLogonTime,
    WTSIncomingBytes,
    WTSOutgoingBytes,
    WTSIncomingFrames,
    WTSOutgoingFrames,
    WTSClientInfo,
    WTSSessionInfo,
    WTSSessionInfoEx,
    WTSConfigInfo,
    WTSValidationInfo,
    WTSSessionAddressV4,
    WTSIsRemoteSession
  );

 WTS_CONNECTSTATE_CLASS = (
    WTSActive,              // User logged on to WinStation
    WTSConnected,           // WinStation connected to client
    WTSConnectQuery,        // In the process of connecting to client
    WTSShadow,              // Shadowing another WinStation
    WTSDisconnected,        // WinStation logged on without client
    WTSIdle,                // Waiting for client to connect
    WTSListen,              // WinStation is listening for connection
    WTSReset,               // WinStation is being reset
    WTSDown,                // WinStation is down due to error
    WTSInit);               // WinStation in initialization

  TWTSQuerySessionInformationFunction = function(hServer: THandle; SessionId:
                DWORD; WTSInfoClass: WTS_INFO_CLASS; var ppBuffer: Pointer; var pBytesReturned: DWORD): BOOL; stdcall;
  TWTSFreeMemoryProcedure = procedure(pMemory: Pointer); stdcall;
 

这是正在使用的代码。我把它放在计时器中并将状态输出到列表框。我可以断开然后重新连接,并在列表框中看到状态更改。

有不同的方法来处理加载库和函数映射调用。如果您最终以这样的方式进行轮询,可能不应该在每次调用时加载库。我只是用我找到的例子。


function TForm3.GetTSClientState: WTS_CONNECTSTATE_CLASS;
var
  LibHandle: HMODULE;
  WTSQuerySessionInformation: TWTSQuerySessionInformationFunction;
  WTSFreeMemory: TWTSFreeMemoryProcedure;
  ClientState: Pointer;
  cBytesReturned: DWORD;
begin

  LibHandle := LoadLibrary('wtsapi32.dll');
  if LibHandle <> 0 then
  begin
    try
      @WTSQuerySessionInformation := GetProcAddress(LibHandle, 'WTSQuerySessionInformationA');
      @WTSFreeMemory := GetProcAddress(LibHandle, 'WTSFreeMemory');
      if Assigned(WTSQuerySessionInformation) and Assigned(WTSFreeMemory) 
      then
      begin
        if WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
                                      WTSConnectState, ClientState, cBytesReturned) then
        try
          result := WTS_CONNECTSTATE_CLASS(ClientState^);
        finally
          WTSFreeMemory(ClientState);
        end;

      end;
    finally
      FreeLibrary(LibHandle);
    end;
  end;
end;


procedure TForm3.Timer1Timer(Sender: TObject);
var
  State: WTS_CONNECTSTATE_CLASS;
begin
   ListBox1.AddItem(GetTSClientName, nil);

   State := GetTSClientState;

   case State of
     WTSActive: ListBox1.AddItem('WTSActive', nil);
     WTSConnected: ListBox1.AddItem('WTSConnected', nil);
     WTSConnectQuery: ListBox1.AddItem('WTSConnectQuery', nil);
     WTSShadow: ListBox1.AddItem('WTSShadow', nil);
     WTSDisconnected: ListBox1.AddItem('WTSDisconnected', nil);
     WTSIdle: ListBox1.AddItem('WTSIdle', nil);
     WTSListen: ListBox1.AddItem('WTSListen', nil);
     WTSReset: ListBox1.AddItem('WTSReset', nil);
     WTSDown: ListBox1.AddItem('WTSDown', nil);
     WTSInit: ListBox1.AddItem('WTSInit', nil);
   end;
end;