【问题标题】:Process unexpectedly DPI aware意外处理 DPI 感知
【发布时间】:2020-09-11 23:04:40
【问题描述】:

我有一个服务,它使用CreateProcessAsUser 将可执行文件启动到用户会话中,并在STARTUPINFO 参数中指定桌面。效果很好。

我的可执行文件没有显示,也没有调用任何与 DPI 相关的 API。

当我通过双击或通过 cmd.exe 手动启动可执行文件时,任务管理器正确地将 DPI 感知显示为“不知道”。

但是,当我的可执行文件由服务启动时,任务管理器将 DPI Awareness 显示为“每个监视器” - 事实上,它的行为就是这样。

Setting the default DPI awareness for a process 说:

有两种主要方法可以指定进程的默认 DPI 感知:

  1. 通过应用程序清单设置
  2. 通过 API 调用以编程方式

这两件事我都没有做。

我确认 .exe 不是使用 mt.exe 显示的。我在以下位置设置了函数断点:

  • user32.dll!SetProcessDpiAwarenessContext
  • user32.dll!SetThreadDpiAwarenessContext
  • shcore.dll!SetProcessDpiAwareness

没有命中断点;但是,当从服务启动时,我只能在我已经在 main 中时附加我的调试器 - 似乎此时已经设置了 DPI 意识。

还有其他地方可以设置 DPI 意识吗?

这是一个混合 rust / C 应用程序 - 没有(例如)引用 .NET 依赖项。


编辑:

使用 JIT 调试器,我可以在 mainCRTStartup 处中断,此时 DPI Awareness 已经是“PerMonitor”。调用SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE)SetProcessDpiAwareness(PROCESS_DPI_UNAWARE) 无效。


编辑:

当使用CreateProcessAsUser 从我的服务启动时;可执行文件有这个环境变量:

__COMPAT_LAYER=HighDpiAware

传递给CreateProcessAsUser的环境是通过调用来创建的:

CreateEnvironmentBlock 使用我的用户句柄。其余环境如预期。这是从哪里来的?当我在资源管理器中检查它的属性时,可执行文件上没有设置兼容性选项...

【问题讨论】:

  • 进程是否继承父进程?就像,因为一个 DPI 感知线程正在启​​动这个过程......我想我们可以运行一个测试。创建一个 DPI 感知应用程序,然后让它启动一个 DPI 不感知应用程序并查看。如果在子进程中用PROCESS_DPI_UNAWARE 调用SetProcessDpiAwareness 会发生什么?
  • @Andy stackoverflow.com/questions/54449681 "DPI 感知不会从启动进程继承。您的进程启动的应用程序的 DPI 感知将设置为这些应用程序想要的任何值。"
  • @TheNextman 您是否考虑过making your service act as a debugger 用于子进程?将DEBUG_PROCESS 传递给CreateProcessAsUser(),它会自动将您的服务附加为调试器,然后让服务在子进程中的DPI 函数上等待CREATE_PROCESS_DEBUG_EVENTset breakpoints,恢复其正常执行,看看您是否为他们接收任何EXCEPTION_DEBUG_EVENT(EXCEPTION_BREAKPOINT)
  • 真正从第一条指令调试过程没问题。如果有用于调试的二进制文件
  • 我使用 JIT 调试器直接停在mainCRTStartup。从 cmd.exe 执行时,我的 DPI 感知为“不知道”。当使用CreateProcessAsUser 从服务启动时,我的 DPI 感知为“每个监视器”。

标签: winapi dpi


【解决方案1】:

我的服务以 SYSTEM 身份运行。当我调用CreateProcessAsUser 时,在这种情况下,可执行文件也以 SYSTEM 身份运行。我将nullptr 传递给lpEnvironment 参数。 MSDN 说:

指向新进程的环境块的指针。如果该参数为NULL,则新进程使用调用进程的环境。

但是,当我检查可执行文件的环境时,我看到:

__COMPAT_LAYER=HighDpiAware

这是强制每个显示器的 DPI 意识。这很神秘,因为确实 - AppCompatFlag 是在 S-1-5-18 (SYSTEM) 的注册表中为该可执行文件设置的,但我不知道这个值是如何或从哪里来的。

我的服务(也作为 SYSTEM 运行)上没有设置变量 - 可能服务没有获得 AppCompat 环境?但是为什么我的子进程有它,尽管据说继承了它的父进程的环境?我想这些兼容性标志必须有特殊处理。

无论如何,我的问题的答案是:从__COMPAT_LAYER 环境变量中删除HighDpiAware

【讨论】:

  • Aaaa 我想通了。在高 DPI 系统上,如果您的进程不支持高 dpi,调用 DXGI 函数 DuplicateOutput 会为您调用 SetProcessDpiAwarenessContext,并添加兼容性标志。这似乎没有记录。
  • 不错的侦探作品,两次+1。想知道如果孩子一个将 dpiAware/ness 设置为 false/unaware 的清单是否有任何区别。
  • @dxiv 否 - 没有区别;我尝试添加一个清单,它只是被兼容性标志覆盖
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多