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