意外处理 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:
- through an application manifest setting
- programmatically through an API call
这两件事我都没有做。
我确认使用 mt.exe 未显示 .exe。我在以下设置函数断点:
- user32.dll!SetProcessDpiAwarenessContext
- user32.dll!SetThreadDpiAwarenessContext
- shcore.dll!SetProcessDpiAwareness
没有断点;然而,当从该服务启动时,我只能在我已经进入 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
参数传递了 nullptr
。 MSDN 是这样说的:
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
。
我有一项服务可以将可执行文件启动到具有 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:
- through an application manifest setting
- programmatically through an API call
这两件事我都没有做。
我确认使用 mt.exe 未显示 .exe。我在以下设置函数断点:
- user32.dll!SetProcessDpiAwarenessContext
- user32.dll!SetThreadDpiAwarenessContext
- shcore.dll!SetProcessDpiAwareness
没有断点;然而,当从该服务启动时,我只能在我已经进入 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
参数传递了 nullptr
。 MSDN 是这样说的:
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
。