远程 IDD 的 IddCx 1.4 更新

IddCx 版本 1.4 的以下更新仅适用于远程间接显示驱动程序(IDD)。

远程 IDD 开发人员还应查看 有关控制台和远程 IDD 的 IddCx 1.4 更新以获取其他更新。

定义远程会话的远程 IDD

IDD 声明它想要创建一个远程 ID 适配器,通过在调用 IddCxAdapterInitAsync 时,在 IDDCX_ADAPTER_CAPS.Flags 字段中设置 IDDCX_ADAPTER_FLAGS_REMOTE_SESSION_DRIVER 位。 操作系统会跟踪是否因为远程桌面堆栈连接到远程会话而加载 IDD,且在以下两种情况下 IddCxAdapterInitAsync 调用会失败:

  1. IDD 未为由 OS 远程桌面堆栈创建用于远程会话的设备设置IDDCX_ADAPTER_FLAGS_REMOTE_SESSION_DRIVER
  2. 未由操作系统的远程桌面堆栈创建的设备,其 IDD 集为IDDCX_ADAPTER_FLAGS_REMOTE_SESSION_DRIVER

远程 IDD 的安装建议

UMDF 允许驱动程序使用 UmdfHostProcessSharingDeviceGroupId 等指令控制其 INF 文件中的设备池选项。 由于存在一些锁争用问题,强烈建议远程 IDD 将 UmdfHostProcessSharing 指令设置为 ProcessSharingDisabled 并删除任何 DeviceGroupId 指令。 此设置会将每个会话的远程 IDD 配置为在其自己的进程中。

对远程 IDD 的现有 IddCx 功能的其他限制

远程 IDD 需要在 IDDCX_ADAPTER_CAPS.Flags 字段中设置 IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE。 这可确保不使用虚拟模式,因此交换链大小将始终与桌面分辨率匹配。 如果未设置此标志,IddCxAdapterInitAsync 将失败。

远程 IDD 仅支持渐进式目标模式,因此 IDDCX_TARGET_MODE.TargetVideoSignalInfo.targetVideoSignalInfo.scanLineOrdering 必须设置为 DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE。 如果未设置此值,IddCxMonitorArrival 将失败。

设置远程会话的显示配置

当远程 IDD 控制远程会话中的所有监视器时,远程会话显示配置应镜像客户端的监视器,远程 IDD 需要能够指定 OS 将在远程会话中设置的显示配置。 当会话创建为远程会话或转换为远程会话时,需要设置此显示配置。

远程 IDD 可以在远程会话期间将显示配置更新为以下任一项:

  • 更改当前监视器的设置(例如,更改桌面位置、方向、物理大小或 DPI)
  • 通过调用 IddCxMonitorArrival/IddCxMonitorDeparture 在添加/删除监视器后设置桌面配置。 远程 IDD 使用 IddCxMonitorArrivalIddCxMonitorDeparture 来告知操作系统监视器到达和离开,这与控制台 IDD 的使用方式相同。

下面是操作系统用于处理显示器到达、离开和桌面配置更改的逻辑。 对于每个远程会话,OS 将存储远程 IDD 提供的单个当前桌面配置。 此桌面配置将启动为空,每次远程 IDD 成功调用 IddCxDisplayConfigUpdate 时都会更新。

当驱动程序收到新的显示配置时

If all monitors in the new display configuration are present in the system
    If new display configuration is supported by driver (eg resolutions)
        Store new display configuration
        Set new display configuration (this will disable any active monitors
            that are not part of new configuration)

If all monitors in the new display config are not currently present in the system
    Store new display configuration
    Disable all active paths and wait for the correct set of monitors to arrive

监视器被移除时

If removed monitor is not in the current display configuration
    Remove the monitor and do not change the current desktop configuration

If removed monitor is part of the current display configuration
    Remove the monitor
    Disable all active paths and wait for the correct set of monitors to arrive

当显示器到达时

If added monitor is not part of current display configuration
    Do not change the display configuration

If added monitor is part of the current display configuration
    If now all the monitors in the current display configurations are present
        Set the new display configuration

下面是一些简单方案,演示如何使用 IddCxDisplayConfigUpdate

方案 1:启动新会话并连接两个监视器

驱动程序操作 当前显示拓扑 当前连接的监视器 当前处于活动状态的监视器 注释
没有 没有 没有 会话启动配置
IddCxMonitorArrival(Mon1) 没有 Mon1 没有 无活动显示配置,因此不会发生任何更改
IddCxMonitorArrival(Mon2) 没有 Mon1、Mon2 没有 显示配置中仍然没有更改
IddCxDisplayConfigUpdate Mon1、Mon2 Mon1、Mon2 Mon1、Mon2 连接所有监视器时,设置配置

注意:为达到相同的结果,驱动程序可能已在添加监视器之前调用 IddCxDisplayConfigUpdate

方案 2:将第三个监视器添加到方案 1 并使其处于活动状态

驱动程序操作 当前显示拓扑 当前连接的监视器 当前处于活动状态的监视器 注释
IddCxMonitorArrival(Mon3) Mon1、Mon2 Mon1、Mon2、Mon3 Mon1、Mon2 不更改显示配置
IddCxDisplayConfigUpdate Mon1、Mon2、Mon3 Mon1、Mon2、Mon3 Mon1、Mon2、Mon3 新建配置集

方案 3:从活动配置中删除监视器

驱动程序操作 当前显示拓扑 当前连接的监视器 当前处于活动状态的监视器 注释
Mon1、Mon2 Mon1、Mon2 Mon1、Mon2 启动配置
IddCxDisplayConfigUpdate() Mon1 Mon1、Mon2 Mon1 将配置更改为仅先使用 Mon1
IddCxMonitorDeparture(Mon2) Mon1 Mon1 Mon1

方案 4:当驱动程序仅支持单个模式时更改路径的模式

驱动程序操作 当前显示拓扑 当前连接的监视器 当前处于活动状态的监视器 注释
Mon1 10x7、Mon2 19x10 Mon1、Mon2 Mon1、Mon2 启动配置
IddCxMonitorUpdateModes(Mon1 支持 16:9) 没有 Mon1、Mon2 没有 已将 Mon1 的模式列表更新为 16x9
IddCxDisplayConfigUpdate() Mon1 16x9、Mon2 19x10 Mon1、Mon2 Mon1、Mon2 将 Mon1 的配置设置为 16x9

处理 IddCxDisplayConfigUpdate 错误

远程驱动程序需要处理 IddCxDisplayConfigUpdate 中的错误。 预期会出现一些错误;例如,当连接使用临时会话时。

在初始配置中出现意外情况时,驱动程序具有如下选项:

  • 调用 IddCxReportCriticalError 终止驱动程序进程并断开用户会话的连接。 建议驱动程序使用唯一的主要/次要组合,以便在崩溃和 Watson 报告中识别这些情况。
  • 如果出现暂时性错误,请再次重试配置。
  • 尝试其他配置。

远程驱动程序可能会认为,会话中的配置更改失败不像初始配置失败那么严重,因此可能永远不会在会话中调用 IddCxReportCriticalError

如果 IddCxDisplayConfigUpdate 返回 STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED,这是因为 OS 检测到目标会话正在断开连接或该会话的 IddCx 适配器正在停止,这属于预期情况,因此驱动程序不应调用 IddCxReportCriticalError

在间接显示远程会话中显示 API 更改

在远程 XDDM 会话中,OS 显示控制面板不会向用户提供任何控件来更改显示配置。 这主要是因为远程会话桌面配置由连接的客户端系统控制,而不是由会话中运行的应用程序控制。 例如,支持 Win+P 投影用户界面在远程会话中没有意义。

对于远程 ID 会话,通常为:

有趣的是,远程 XDDM 解决方案使用 ChangeDisplaySetting 来更改模式和桌面位置,因为这是应用客户端更改的唯一方式。 由于远程 ID 解决方案具有 IddCxDisplayConfigUpdate 功能, 因此不再需要 ChangeDisplaySetting 在远程 ID 会话中运行。

下表显示了 XDDM 远程会话和 WDDM 远程会话中的 API 和显示控制面板(CPL)功能。

API/CPL XDDM 远程会话 WDDM 远程会话
显示 CPL 不会显示任何信息,并显示一条消息,指出“无法从远程会话更改显示设置”。 与 XDDM 远程会话的行为相同。
Win+P UI 和功能 UI 未显示,API 失败。 与 XDDM 远程会话的行为相同。
旧版显示枚举 API(如 EnumDisplaySettings 和 EnumDisplayDevices) API 按预期工作并返回相关信息。 与 XDDM 远程会话的行为相同。
旧版 ChangeDisplaySetting 正常工作,用于反映来自客户端的桌面更改。 为了应用程序兼容性而返回成功,但实际上忽略该调用,不会更改任何显示配置。 IDD 将使用 IddCxDisplayConfigUpdate 更改桌面配置。
QueryDisplayConfig 失败。 按预期工作。
DisplayConfigGetDeviceInfo 失败。 正常运作并报告预期信息。
SetDisplayConfig 和 DisplayConfigSetDeviceInfo 失败。 与 XDDM 远程会话的行为相同。

监视 ID 远程会话中的空闲行为

当协议堆栈调用 IWRdsProtocolConnectionCallback::StopScreenUpdates 以停止更新客户端屏幕时,OS 会销毁交换链并使该会话的所有路径处于非活动状态,从而导致调用 IDD 的 EVT_IDD_CX_ADAPTER_COMMIT_MODES 回调,并在每个路径的 IDDCX_PATH.Flags 中设置 IDDCX_PATH_FLAGS_NONE

当协议堆栈调用 IWRdsProtocolConnectionCallback::RedrawWindow 再次启用更新时,OS 将使用 IDD 的 EVT_IDD_CX_ADAPTER_COMMIT_MODES 回调设置新的活动路径,并创建新的交换链。

ID 远程会话中的断开连接行为

当用户与远程会话断开连接时,OS 会销毁托管该会话的远程 ID 设备的 devnode,导致该会话的远程 ID 适配器被 PnpStopped。 UMDF 将调用远程 IDD 的 EVT_WDF_DEVICE_D0_EXIT 回调。

如果会话再次通过远程连接,操作系统将为该会话的远程 IDD 创建一个新的设备节点。 远程 IDD 应再次经历正常的启动序列,初始化适配器,然后添加监视器等。