Windows Forms高DPI缩放适配问题求助:单独运行EXE时缩放方案失效
Let's break down your problem: you've configured high-DPI scaling for your WinForms app, but it only works in Visual Studio debug mode or when the EXE is placed alongside its manifest and config files. When running the EXE alone (without those files) or dynamically loading Monitor.dll to launch a form, the scaling breaks entirely. Here are targeted troubleshooting steps to fix this:
1. Embed Manifest and Config Files Into Your EXE/DLL
The root issue here is that your scaling settings are tied to external files, not baked into your executable. When you run the EXE alone, it can't find those files, so the scaling rules don't apply.
- For the Manifest: In Visual Studio, right-click your project → Properties → Application. Under "Manifest", select "Embed manifest with default settings" and edit the manifest to include proper DPI awareness tags. For modern per-monitor scaling, add:
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> </windowsSettings> </application> - For the Config File: If your scaling relies on
app.config, go to project properties → Build → Output, and configure the config to be embedded as a resource. Alternatively, you can load the config dynamically in code usingConfigurationManager.OpenExeConfiguration.
If you're dynamically loading Monitor.dll, make sure the DLL itself has the embedded manifest/config, not just the main EXE.
2. Set DPI Awareness Via Code (No External Files Needed)
If embedding the manifest isn't working, you can force DPI awareness directly in your code using Windows APIs. This bypasses the need for external manifest files entirely.
Add these declarations to your VB.NET code, and call the setup method before creating any forms or threads:
Imports System.Runtime.InteropServices Imports System.Diagnostics Public Module DpiHelper <DllImport("shcore.dll", SetLastError:=True)> Private Function SetProcessDpiAwareness(awareness As Integer) As Integer End Function Public Sub EnablePerMonitorDpi() ' 2 = PROCESS_PER_MONITOR_DPI_AWARE (Windows 10 1607+) SetProcessDpiAwareness(2) End Sub End Module
Then, in your main program's entry point (or right before starting the Monitor thread), call:
DpiHelper.EnablePerMonitorDpi()
3. Fix Context for Dynamically Loaded DLLs
When you load Monitor.dll using Assembly.Load(File.ReadAllBytes(...)), the DLL runs in the context of your main EXE's working directory—not the DLL's own directory. This means it can't find any manifest/config files in its folder.
Adjust your loading code to switch the working directory temporarily:
Private Sub ShowMonitor() Dim dllPath = "path to folder with DLL files\Monitor.dll" Dim originalWorkingDir = Environment.CurrentDirectory Try ' Switch to the DLL's directory Environment.CurrentDirectory = Path.GetDirectoryName(dllPath) Dim frMonitor As Assembly = Assembly.Load(File.ReadAllBytes(dllPath)) Dim oType As Type = frMonitor.GetType("Monitor.frmMonitor") Dim pControl As Object = Activator.CreateInstance(oType) Application.Run(pControl) Finally ' Restore original working directory Environment.CurrentDirectory = originalWorkingDir End Try End Sub
4. Verify DPI Awareness Status
To confirm if your DPI settings are actually taking effect, add code to check the current process's DPI awareness level. This helps you rule out whether the issue is with applying the setting or something else.
Add this API declaration and check method:
<DllImport("shcore.dll", SetLastError:=True)> Private Function GetProcessDpiAwareness(hProcess As IntPtr, ByRef awareness As Integer) As Integer End Function Public Sub CheckDpiAwareness() Dim awarenessLevel As Integer GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, awarenessLevel) ' Interpret the result: ' 0 = DPI unaware ' 1 = System DPI aware ' 2 = Per-monitor DPI aware Debug.WriteLine($"Current DPI Awareness Level: {awarenessLevel}") End Sub
Call CheckDpiAwareness() right after launching your app. If it returns 0 when running the EXE alone, your DPI settings aren't being applied—go back to steps 1 or 2 to fix that.
5. Ensure Main EXE Has Proper DPI Settings
Remember that DPI awareness is a process-level setting. Even though you're launching the Monitor form from a DLL, the main EXE's DPI configuration will affect all threads and forms in the process. Make sure your main EXE has the correct manifest or code-based DPI setup first.
内容的提问来源于stack exchange,提问作者Sphinx

