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

发布于 2024-10-02 17:39:24 字数 1539 浏览 4 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

时光无声 2024-10-09 17:39:24

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

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

  • 0(控制台会话)
  • 1(ICA 会话)
  • 2(RDP 会话)

有趣的是,返回值 1 在 MSDN(上面的第二个链接)上不再记录为 WTS_PROTOCOL_TYPE_ICA,而是记录为“此值是保留用于遗留目的。”。

更新:

XenDesktop 无法使用 WTSQuerySessionInformation 检测会话(它返回 0,表示控制台)。如果您想要通用解决方案:

  • 调用 WTSQuerySessionInformation。如果返回 1 或 2(ICA 或 RDP),则您已完成。
  • 如果WTSQuerySessionInformation返回0(控制台),则动态加载wfapi.dll并获取WFGetActiveProtocol的地址
  • 调用WFGetActiveProtocol WF_CURRENT_SESSION 参数,定义为 ((DWORD)-1)
  • WFGetActiveProtocol 的返回值为会话类型。它应该是 0(控制台)或 1(ICA)

我已经详细描述了该过程 此处以及 C++ 代码示例和返回当前会话的远程处理协议类型的工作编译工具。

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 load wfapi.dll and get the address of WFGetActiveProtocol
  • Call WFGetActiveProtocol with a parameter of WF_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.

坐在坟头思考人生 2024-10-09 17:39:24

根据: http://forums.citrix.com/message.jspa?messageID=1363711< /a> 您可以检查SESSIONNAME环境变量。

另一种更简单的方法是读取系统环境变量“SESSIONNAME”。如果它存在并且以“ICA”开头,那么您正在 Citrix 会话中运行。如果它以“RDP”开头,那么您正在 RDP 会话中运行。

我用我的电脑测试了它,并在本地得到:

C:\>echo %SESSIONNAME%
Console

虽然远程我得到了

C:\>echo %SESSIONNAME%
RDP-tcp1

所以这似乎是一条简单的路线,否则听起来像检查注册表值或某些 dll 是否存在将是下一个最好的事情。

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.

黑色毁心梦 2024-10-09 17:39:24

按照@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 盒子上测试这一点,我们将不胜感激!

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!

眉黛浅 2024-10-09 17:39:24

根据 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 上对此进行了测试。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文