Delphi6: нужно знать, работает ли мое приложение в сеансе консоли или сеанса удаленного рабочего стола
Время от времени к моему приложению обращаются из клиентов удаленного рабочего стола, и я хочу знать, используется ли оно в данный момент в сеансе консоли или сеансе удаленного рабочего стола, если позже это происходит, и сеанс отключен (пользователь отключился, но не вышел из системы), оно должен перенаправить себя на консоль (как это делает "tscon.exe 0 /dest:console" в Windows XP). Теперь я запускаю сценарий оболочки для достижения этой цели (используя "query.exe user" и "tscon.exe"), но хотел бы, чтобы мое приложение Delhi6 сделало это вместо этого.
1 ответ
Я использую следующее
const
SM_REMOTESESSION = $1000;
if GetSystemMetrics(SM_REMOTESESSION) <> 0 then
begin
// you are in a remote session
end
На странице MSDN для GetSystemMetrics:
SM_REMOTESESSION = 0x1000
Этот системный показатель используется в среде служб терминалов. Если вызывающий процесс связан с сеансом клиента служб терминалов, возвращаемое значение отлично от нуля. Если вызывающий процесс связан с сеансом консоли служб терминалов, возвращаемое значение равно 0.
Windows Server 2003 и Windows XP: сеанс консоли не обязательно является физической консолью. Для получения дополнительной информации см. WTSGetActiveConsoleSessionId.
Я использую это в Delphi 2007, и функция определяется в модуле Windows, но мне нужно было определить константу самостоятельно. Я не знаю, имеет ли Delphi 6 определенную функцию. Минимальной поддерживаемой версией Windows была Windows 2000, так что вы должны иметь возможность использовать ее, если не вернетесь назад.
-
Чтобы узнать текущее состояние сеанса, вам нужна функция WTSQuerySessionInformation. Вы можете использовать эту функцию, чтобы узнать много информации о текущем сеансе, включая текущее состояние.
На дискуссионных форумах Embarcadero я нашел запись, которая дала мне стартовый код. Этот пост назывался вопросом удаленного рабочего стола.
Вот некоторые константы и прототипы функций, которые вам понадобятся:
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;