【发布时间】:2020-09-11 23:04:40
【问题描述】:
我有一个服务,它使用CreateProcessAsUser 将可执行文件启动到用户会话中,并在STARTUPINFO 参数中指定桌面。效果很好。
我的可执行文件没有显示,也没有调用任何与 DPI 相关的 API。
当我通过双击或通过 cmd.exe 手动启动可执行文件时,任务管理器正确地将 DPI 感知显示为“不知道”。
但是,当我的可执行文件由服务启动时,任务管理器将 DPI Awareness 显示为“每个监视器” - 事实上,它的行为就是这样。
Setting the default DPI awareness for a process 说:
有两种主要方法可以指定进程的默认 DPI 感知:
- 通过应用程序清单设置
- 通过 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_EVENT、set breakpoints,恢复其正常执行,看看您是否为他们接收任何EXCEPTION_DEBUG_EVENT(EXCEPTION_BREAKPOINT)。 -
真正从第一条指令调试过程没问题。如果有用于调试的二进制文件
-
我使用 JIT 调试器直接停在
mainCRTStartup。从 cmd.exe 执行时,我的 DPI 感知为“不知道”。当使用CreateProcessAsUser从服务启动时,我的 DPI 感知为“每个监视器”。