API for Determining if App is Running on Citrix or Terminal Services [closed]
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You c开发者_Python百科an edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this questionI'm looking for an API/function I can call to determine if software is running on Citrix, Terminal Services, or a stand-alone PC. Optimally, it would work something like this:
Select Case APIWhatSystem.Type.ToString
Case "Citrix"
bCitrix = True
Case "TS"
bTerminalServices = True
Case "PC"
bPC = True
End Select
I would prefer something that worked from an API call as opposed to looking at something in the registry as we're having more and more customers that are locking down the registry.
Thanks.
There is an API function that lets you determine whether a specific user session is displayed on the console (locally) or via one the the remoting protocols Citrix ICA (nowadays called HDX) or Microsoft RDP.
Call WTSQuerySessionInformation with 3rd parameter set to WTSClientProtocolType. The function returns:
- 0 for console sessions
- 1 for ICA sessions
- 2 for RDP sessions
Interestingly the return value of 1 is not documented as WTS_PROTOCOL_TYPE_ICA
on MSDN (second link above) any more, but as "This value is retained for legacy purposes.".
Update:
XenDesktop sessions cannot be detected with WTSQuerySessionInformation
(it returns 0, meaning Console). If you want a universal solution:
- Call
WTSQuerySessionInformation
. If that returns 1 or 2 (ICA or RDP), you are done. - If
WTSQuerySessionInformation
returns 0 (Console), dynamically loadwfapi.dll
and get the address ofWFGetActiveProtocol
- Call
WFGetActiveProtocol
with a parameter ofWF_CURRENT_SESSION
, which is defined as ((DWORD)-1) - The return value of
WFGetActiveProtocol
is the session type. It should be either 0 (Console) or 1 (ICA)
I have described the process in detail here along with a C++ code sample and a working compiled tool that returns the current session's remoting protocol type.
According to: http://forums.citrix.com/message.jspa?messageID=1363711 you can check the SESSIONNAME environment variable.
Another simpler way is to read the system environment variable "SESSIONNAME". If it exists and starts with "ICA" then you're running within a Citrix session. If it starts with "RDP" then you're running within an RDP session.
I tested it with my PC and locally I get:
C:\>echo %SESSIONNAME%
Console
While remotely I got
C:\>echo %SESSIONNAME%
RDP-tcp1
So it seems like it might be an easy route to go, otherwise it sounds like checking for registry values or if certain dlls exist will be the next best thing.
Following @Josh's answer, the code would look like this:
Select Case Environment.GetEnvironmentVariable("SessionName").ToUpper.SubString(0,3))
Case "ICA"
bCitrix = True
Case "RDP"
bTerminalServer = True
Case "CON"
bPC = True
End Select
I haven't fully tested it out yet, but it looks like it will do what I want. PCs and Terminal Servers reports correctly.
If someone has a way to test this on a Citrix box, it would be much appreciated!
Based on Helge Klein's revised answer (above) I thought I'd post the VBA code to make this happen to help future VBA users hitting this page. Helge already has the C++ code on his own site. If you find this helpful, please upvote Helge Klein's answer.
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
I've tested this on XenApp and XenDesktop.
精彩评论