API for Determining if App is Running on Citrix or Terminal Services
Solution 1
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.
Solution 2
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.
Solution 3
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!
Solution 4
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.
Comments
-
John Cruz almost 2 years
I'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.
-
John Cruz over 13 yearsDo you think it would be safe to assume if that function returns ANY number greater than 0, the app is not running on a PC? ie. It's gotta be running on some kind of server. I'm thinking like 5 years in the future... either way a non-zero should always indicate something other than a PC, right?
-
Helge Klein over 13 yearsYes, I think if would be safe to assume that anything > 0 is ... NOT LOCAL. Please note the difference in wording. It can very well run on a PC, but with today's hot topic "VDI" aka virtual desktops served over some remoting protocol (think 2008 R2 SP1 - RemoteFX) the likelihood increases steadily of PCs becoming 1-session terminal servers soon.
-
mischab1 about 12 yearsWorks for me. On my citrix server
?environ("SessionName")
returnsICA-tcp#56
. -
user545829 over 11 yearsNotice, that in Windows 2008 TS RemoteApp mode this env.variable is absent
-
DHW almost 10 yearsIf the application is running under Citrix XenApp, then WTSClientProtocolType will return 1. If, however, the application is running under Citrix XenDesktop, then WTSClientProtocolType will return 0. I am still looking for a way to detect it that doesn't involve enumerating the devices and looking for known virtual drivers.
-
Helge Klein almost 10 years@DHW: XenApp and XenDesktop are fundamentally different in the way they interface with the OS. Whereas XenApp officially tells the OS that it uses a remoting protocol XenDesktop redirects the console session. The user session therefore is not a WTS session and WTSQuerySessionInformation does not help. You should ask another question regarding XenDesktop.
-
DHW almost 10 years@HelgeKlein There are a lot of websites tracing back to your solution here - and a number of those sites are asking exactly what I'm asking - so I'm thinking my not-so-neat solution will do. I checked which registry keys were present in the virtualized desktop for XenDesktop 2.0 and compared it to ones still in play in the current version. I settled on testing for the existence of HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\VirtualDesktopAgent - So your solution comes back with Console, I'll check for the registry key. If it exists, I conclude its Citrix. Close enough for all practical purposes.
-
Helge Klein almost 10 years@DHW: Sounds good enough to me.
-
Helge Klein over 9 years@DHW: I now have a better solution for XenDesktop and updated my answer accordingly.
-
DHW over 9 years@HelgeKlein I'm not sure on the specifics of the XenDesktop implementation - but wfapi.dll does not exist in the XenDesktop build I'm using.
-
Helge Klein over 9 years@DHW: Which version of XenDesktop is that? To be more specific: the version of the VDA software installed on the virtual Windows machines is relevant.
-
DHW over 9 yearsXenDesktop 5.6. Win7. Don't know if its relevant but its launched using Program Neighborhood Agent (pnagent)
-
Helge Klein over 9 years@DHW: I just check on a Windows 7 x64 machine with the XenDesktop 5.6 VDA installed. Wfapi.dll and Wfapi64.dll are in the subdirectory "ICAService" of the VDA installation directory. It should also be in the path so you can find it on the console with "where wfapi.dll".
-
DHW over 9 years@HelgeKlein Ah. See it. C:\Program Files\Citrix\ICAService\wfapi.dll I was looking in Windows tree.
-
Coxy about 4 yearsI just ran this on my infrastructure and I get SESSIONNAME=Console, so it seems to not be a reliable method anymore.