用于确定应用程序是否在Citrix或终端服务上运行的API

时间:2010-11-15 15:57:16

标签: vb.net api citrix terminal-services

我正在寻找一个API /函数,我可以调用它来确定软件是在Citrix,终端服务还是独立PC上运行。最理想的是,它可以像这样工作:

Select Case APIWhatSystem.Type.ToString
   Case "Citrix"
      bCitrix = True
   Case "TS"
      bTerminalServices = True
   Case "PC"
      bPC = True
End Select

我希望通过API调用起作用,而不是在注册表中查看某些内容,因为我们有越来越多的客户锁定注册表。

感谢。

4 个答案:

答案 0 :(得分:12)

有一个API函数可以让您确定特定用户会话是在控制台上显示(本地)还是通过远程协议Citrix ICA(现在称为HDX)或Microsoft RDP显示。

调用WTSQuerySessionInformation,将第三个参数设置为WTSClientProtocolType。该函数返回:

  • 0用于控制台会话
  • ICA会议
  • 1
  • 2用于RDP会话

有趣的是,返回值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上测试了这个。