我正在寻找一个API /函数,我可以调用它来确定软件是在Citrix,终端服务还是独立PC上运行。最理想的是,它可以像这样工作:
Select Case APIWhatSystem.Type.ToString
Case "Citrix"
bCitrix = True
Case "TS"
bTerminalServices = True
Case "PC"
bPC = True
End Select
我希望通过API调用起作用,而不是在注册表中查看某些内容,因为我们有越来越多的客户锁定注册表。
感谢。
答案 0 :(得分:12)
有一个API函数可以让您确定特定用户会话是在控制台上显示(本地)还是通过远程协议Citrix ICA(现在称为HDX)或Microsoft RDP显示。
调用WTSQuerySessionInformation,将第三个参数设置为WTSClientProtocolType。该函数返回:
有趣的是,返回值1不再在MSDN(上面的第二个链接)上记录为WTS_PROTOCOL_TYPE_ICA
,而是“为了传统目的而保留此值。”。
<强>更新强>
WTSQuerySessionInformation
无法检测到XenDesktop 会话(它返回0,表示控制台)。如果你想要一个通用的解决方案:
WTSQuerySessionInformation
。如果返回1或2(ICA或RDP),则完成。WTSQuerySessionInformation
返回0(控制台),则动态加载wfapi.dll
并获取WFGetActiveProtocol
的地址WFGetActiveProtocol
调用WF_CURRENT_SESSION
,其定义为((DWORD)-1)WFGetActiveProtocol
的返回值是会话类型。它应该是0(控制台)或1(ICA)我已经详细描述了这个过程here以及一个C ++代码示例和一个返回当前会话的远程协议类型的工作编译工具。
答案 1 :(得分:7)
根据:http://forums.citrix.com/message.jspa?messageID=1363711,您可以检查SESSIONNAME环境变量。
另一种更简单的方法是读取系统环境变量“SESSIONNAME”。如果它存在并以“ICA”开头,那么您将在Citrix会话中运行。如果以“RDP”开头,则表示您正在RDP会话中运行。
我用我的电脑进行测试,然后在当地得到:
C:\>echo %SESSIONNAME%
Console
远程我得到了
C:\>echo %SESSIONNAME%
RDP-tcp1
所以看起来这可能是一条简单的路线,否则听起来像检查注册表值或者是否存在某些dll将是下一个最佳选择。
答案 2 :(得分:3)
按照@Josh的回答,代码看起来像这样:
Select Case Environment.GetEnvironmentVariable("SessionName").ToUpper.SubString(0,3))
Case "ICA"
bCitrix = True
Case "RDP"
bTerminalServer = True
Case "CON"
bPC = True
End Select
我尚未完全测试它,但看起来它会做我想要的。 PC和终端服务器报告正确。
如果有人有办法在Citrix盒子上测试它,我们将不胜感激!
答案 3 :(得分:2)
基于Helge Klein修改后的答案(上图),我认为我会发布VBA代码,以帮助未来的VBA用户访问此页面。 Helge已在自己的网站上拥有C ++代码。如果您觉得这很有帮助,请提升Helge Klein的答案。
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上测试了这个。