API для определения, работает ли приложение в Citrix или службах терминалов
Я ищу API/ функцию, которую я могу вызвать, чтобы определить, работает ли программное обеспечение на Citrix, Terminal Services или на автономном ПК. Оптимально, это будет работать примерно так:
Select Case APIWhatSystem.Type.ToString
Case "Citrix"
bCitrix = True
Case "TS"
bTerminalServices = True
Case "PC"
bPC = True
End Select
Я предпочел бы что-то, что работает от вызова API, а не смотреть что-то в реестре, поскольку у нас все больше и больше клиентов, которые блокируют реестр.
Благодарю.
4 ответа
В соответствии с: http://forums.citrix.com/message.jspa?messageID=1363711 вы можете проверить переменную среды SESSIONNAME.
Другой более простой способ - прочитать системную переменную среды "SESSIONNAME". Если он существует и начинается с "ICA", то вы работаете в сеансе Citrix. Если он начинается с "RDP", то вы работаете в рамках сеанса RDP.
Я проверил это на своем ПК и локально получаю:
C:\>echo %SESSIONNAME%
Console
В то время как я получил удаленно
C:\>echo %SESSIONNAME%
RDP-tcp1
Таким образом, кажется, что это может быть простой путь, в противном случае это звучит как проверка значений реестра или, если существуют определенные dll, будет следующей лучшей вещью.
Существует функция API, которая позволяет определить, отображается ли конкретный пользовательский сеанс на консоли (локально) или с помощью одного из протоколов удаленного взаимодействия Citrix ICA (в настоящее время называемых HDX) или Microsoft RDP.
Вызовите WTSQuerySessionInformation с третьим параметром, для которого установлено значение WTSClientProtocolType. Функция возвращает:
- 0 для консольных сессий
- 1 для сессий ICA
- 2 для сеансов RDP
Интересно, что возвращаемое значение 1 не задокументировано как WTS_PROTOCOL_TYPE_ICA
в MSDN (вторая ссылка выше) больше, но как "Это значение сохраняется для устаревших целей".
Обновить:
Сессии XenDesktop не могут быть обнаружены с WTSQuerySessionInformation
(возвращает 0, что означает консоль). Если вы хотите универсальное решение:
- Вызов
WTSQuerySessionInformation
, Если это возвращает 1 или 2 (ICA или RDP), все готово. - Если
WTSQuerySessionInformation
возвращает 0 (консоль), динамически загружаетсяwfapi.dll
и получить адресWFGetActiveProtocol
- Вызов
WFGetActiveProtocol
с параметромWF_CURRENT_SESSION
, который определяется как ((DWORD)-1) - Возвращаемое значение
WFGetActiveProtocol
тип сеанса Должно быть 0 (консоль) или 1 (ICA)
Я подробно описал этот процесс, а также пример кода на C++ и работающий скомпилированный инструмент, который возвращает тип протокола удаленного взаимодействия текущего сеанса.
После ответа @ Джоша код будет выглядеть так:
Select Case Environment.GetEnvironmentVariable("SessionName").ToUpper.SubString(0,3))
Case "ICA"
bCitrix = True
Case "RDP"
bTerminalServer = True
Case "CON"
bPC = True
End Select
Я еще не полностью проверил это, но похоже, что он будет делать то, что я хочу. ПК и терминальные серверы отчитываются правильно.
Если у кого-то есть способ проверить это на коробке Citrix, это будет высоко ценится!
Основываясь на пересмотренном ответе Хельге Кляйн (выше), я решил опубликовать код VBA, чтобы помочь будущим пользователям VBA попасть на эту страницу. Хельге уже имеет код C++ на своем собственном сайте. Если вы найдете это полезным, пожалуйста, ответьте Хельге Кляйн.
Option Explicit
Private Const WTS_CURRENT_SERVER_HANDLE = 0&
Private Const WTS_CURRENT_SESSION As Long = -1
Private Enum 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
End Enum
Private Declare Function WTSQuerySessionInformation _
Lib "wtsapi32.dll" Alias "WTSQuerySessionInformationA" ( _
ByVal hServer As Long, ByVal SessionId As Long, _
ByVal WtsInfoClass As WTS_INFO_CLASS, _
ByRef ppBuffer As LongPtr, _
ByRef pBytesReturned As LongPtr _
) As Long
Private Declare Function WFGetActiveProtocol _
Lib "wfapi.dll" ( _
ByVal SessionId As Long _
) As Long
Private Declare Sub WTSFreeMemory Lib "wtsapi32.dll" ( _
ByVal pMemory As Long)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
Destination As Any, Source As Any, ByVal length As Long)
Public Function SessionType() As String
Dim ResultCode As Long
Dim p As LongPtr
Dim ppBuffer As LongPtr
Dim pBytesReturned As Long
Dim ClientProtocolType As Integer
ResultCode = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSClientProtocolType, ppBuffer, pBytesReturned)
If ResultCode = 0 Then
p = ppBuffer
CopyMemory ClientProtocolType, ByVal p, pBytesReturned
WTSFreeMemory ppBuffer
End If
Select Case ClientProtocolType
Case 0:
On Error Resume Next
ResultCode = WFGetActiveProtocol(WTS_CURRENT_SESSION)
If Err.Number = 53 Then
SessionType = "Console"
ElseIf Err.Number = 0 Then
If ResultCode = 1 Then
SessionType = "Citrix"
Else
SessionType = "Console"
End If
End If
Err.Clear
On Error GoTo 0
Case 1:
SessionType = "Citrix"
Case 2:
SessionType = "RDP"
Case Else
SessionType = "Other (" & ClientProtocolType & ")"
End Select
End Function
Я проверял это на XenApp и XenDesktop.