意外处理 DPI 感知

Process unexpectedly DPI aware

我有一项服务可以将可执行文件启动到具有 CreateProcessAsUser 的用户会话中,在 STARTUPINFO 参数中指定桌面。效果不错。

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

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

但是,当服务启动我的可执行文件时,任务管理器将 DPI 感知显示为“每个监视器”- 事实上,它的行为也是如此。

Setting the default DPI awareness for a process 说:

There are two main methods to specify the default DPI awareness of a process:

  1. through an application manifest setting
  2. programmatically through an API call

这两件事我都没有做。

我确认使用 mt.exe 未显示 .exe。我在以下设置函数断点:

没有断点;然而,当从该服务启动时,我只能在我已经进入 main 时附加我的调试器 - 并且似乎 DPI 感知已经在此时设置。

还有其他地方可以设置 DPI 感知吗?

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


编辑:

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


编辑:

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

__COMPAT_LAYER=HighDpiAware

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

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

我的服务是 运行SYSTEM。当我调用 CreateProcessAsUser 时,在这种情况下,可执行文件也是 运行 作为 SYSTEM。我为 lpEnvironment 参数传递了 nullptrMSDN 是这样说的:

A pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

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

__COMPAT_LAYER=HighDpiAware

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

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

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