TheNextman
TheNextman

Reputation: 12566

Process unexpectedly DPI aware

I have a service that launches an executable into a user session with CreateProcessAsUser, specifying the desktop in the STARTUPINFO parameter. It works well.

My executable is not manifested, nor does it call any DPI-related API.

When I launch my executable manually by double-clicking or via cmd.exe, Task Manager correctly shows the DPI Awareness as "Unaware".

However, when my executable is launched by the service, Task Manager shows DPI Awareness as "Per Monitor" - and indeed, it behaves as such.

Setting the default DPI awareness for a process says:

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

I am doing neither of these things.

I confirmed that the .exe is not manifested by using mt.exe. I set function breakpoints on the following:

No breakpoint is hit; however when launched from the service, I can only attach my debugger once I'm already inside main - and it seems that the DPI awareness is already set at that point.

Is there anywhere else the DPI awareness can be getting set?

This is a hybrid rust / C application - there is no (for example) .NET dependency referenced.


EDIT:

Using the JIT debugger, I can break at mainCRTStartup and see the DPI Awareness is already "PerMonitor" at that point. Calling SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE) or SetProcessDpiAwareness(PROCESS_DPI_UNAWARE) have no effect.


EDIT:

When launched from my service with CreateProcessAsUser; the executable has this environment variable:

__COMPAT_LAYER=HighDpiAware

The environment passed to CreateProcessAsUser is created by calling:

CreateEnvironmentBlock with my user handle. The rest of the environment is as expected. Where is this coming from? There are no compatibility options set on the executable when I inspect it's properties in explorer...

Upvotes: 3

Views: 1236

Answers (1)

TheNextman
TheNextman

Reputation: 12566

My service is running as SYSTEM. When I call CreateProcessAsUser, in this case, the executable is also run as SYSTEM. I pass nullptr for the lpEnvironment parameter. MSDN says this:

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.

However, when I inspect the environment of my executable, I see:

__COMPAT_LAYER=HighDpiAware

This is forcing per-monitor DPI awareness. This is mysterious because, indeed - the AppCompatFlag is set for that executable in the registry for S-1-5-18 (SYSTEM), but I don't know how or where this value is coming from.

The variable is not set on my service (which also runs as SYSTEM) - presumably services don't get the AppCompat environment? But why does my child process have it, despite supposedly inheriting the environment of it's parent? I suppose these compatability flags must have special handling.

Anyway, the answer to my question is: remove HighDpiAware from the __COMPAT_LAYER environment variable.

Upvotes: 3

Related Questions