Creating dpi aware C# clickonce application with WinForms - c#

In our C# clickonce application we want to get the user's screen size (width, height). At first everything worked fine with
int width = Screen.FromControl(this).Bounds.Width;
int height= Screen.FromControl(this).Bounds.Height;
Later on I noticed that on our Windows 8.1 laptop the values returned are 1.25 times less than the real dimensions of the screen. That's when I noticed we have a DPI problem with certain Windows versions on high resolution screens.
I know that moving on to WPF would be a good option, but we are in need of a quick and dirty fix. After searching by Google I found several approaches as described here and I decided to go with this solution. After all, even the MSDN Blog entries suggest to add the following snippet to the app.manifest:
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
Unfortunately I do not understand how and where to add this code. My manifest (automatically generated by Visual Studio) looks like this:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
</application>
</compatibility>
</asmv1:assembly>
Note that I have removed commented parts to make the app manifest look smaller here. I have tried adding the snippet from above before </asm1:assembly> on the last line. Whenever I tried this, I get an exception before my application starts:
An unhandled exception of type 'System.ArgumentNullException' occurred in mscorlib.dll.
Additional information: Value cannot be null.
Oddly, someone else on stackoverflow.com suggested to uncheck Enable clickonce security settings in the app settings. This made the application start again and it worked on my laptop as expected: The app was upscaled and the text sharp. Also, I was able to get the correct screen size in pixels through my code.
Of course disabling the security settings is not an option if you want to deploy an application. So how can I fix this problem in order to get what I want? What am I missing? I am totally lost at this point.
Trying to start fresh:
Opened Visual Studio (2013 Pro)
New Windows Forms application called "Test"
Enabled "ClickOnce security settings"
Edited the manifest file again as suggest on other posts like here
Clicked on Start (or Build)
The following error appears. I don't know how to get more information about the error, becuase there is none...

Maybe it is too late for answer, but according to the answer of the same problem
Project Options > Debug > Enable the Visual Studio hosting process(disable it run app later enable it again)

Related

Windows Form Design Change Upon Publish [duplicate]

I've created a simple Winforms application in C#. When I run the application on a machine with high DPI settings (e.g. 150%), the application gets scaled up. So far so good!
But instead of rendering the fonts with a higher font size, all texts are just scaled up, too. That of course leads to very blurry text (on all controls like buttons etc.).
Shouldn't windows take care of rendering the texts correctly? For example my application's title bar is rendered crisp & clear.
Once you go past 100% (or 125% with the "XP-style DPI scaling" checkbox ticked), Windows by default takes over the scaling of your UI. It does so by having your app render its output to a bitmap and drawing that bitmap to the screen. The rescaling of that bitmap makes the text inevitably look fuzzy. A feature called "DPI virtualization", it keeps old programs usable on high resolution monitors.
You have to explicitly let it know that you can handle higher DPI settings by adding the <dpiAware> element to your manifest. The MSDN page is here but it isn't complete since it is omitting the UAC settings. Project + Add New Item, pick "Application Manifest File". Edit the manifest text or copy/paste this:
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
You can also pinvoke SetProcessDPIAware() in your Main() method, necessary for example if you deploy with ClickOnce:
[STAThread]
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // Edit as needed
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
UPDATE, this common need is finally a bit easier if you use VS2015 Update 1 or higher. The added manifest already has the relevant directive, just remove the comments.
Keyword for search so I can find this post back: dpiAware
Applications can be developed in two different mode.
The first one is to declare our application to be non-DPI-aware (not declaring anything will default to this). In this case the operating system will render our application under the expected 96 DPI and then will do to the bitmap scaling that we discussed before. The result will be a blurry looking application, but with a correct layout.
The second option is to declare the application as DPI-aware. In this case the OS will not do any scaling and will let your application render according to the original DPI of the screen. In case of a per-monitor-DPI environment, your application will be rendered with the highest DPI of all the screens, then this bitmap will be scaled down to the proper size for each monitor. Downscaling results in a better viewing experience than upscaling but you might still notice some fuzziness.
If you want to avoid that, you must declare your application as per-monitor-DPI-aware. Then you must detect when your application is dragged across different monitors and render according to the DPI of the current one.
Declaring the DPI awareness is done in a manifest file.
refer the following link stackoverflow
Using .NET Framework 4.7 and Windows 10 Creators Update (1703) or newer you must do the following things to configure high DPI support for your Windows Form application:
Declare compatibility with Windows 10.
To do this, add the following to your manifest file:
<compatibility xmlns="urn:schemas-microsoft.com:compatibility.v1">
<application>
<!-- Windows 10 compatibility -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
Enable per-monitor DPI awareness in the app.config file.
Windows Forms introduces a new System.Windows.Forms.ApplicationConfigurationSection element to support new features and customizations added starting with the .NET Framework 4.7. To take advantage of the new features that support high DPI, add the following to your application configuration file.
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
Important
In previous versions of the .NET Framework, you used the manifest to add high DPI support. This approach is no longer recommended, since it overrides settings defined on the app.config file.
Call the static EnableVisualStyles method.
This should be the first method call in your application entry point. For example:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
The advantage of this is the support for dynamic DPI scenarios in which the user changes the DPI or scale factor after a Windows Forms application has been launched.
Source: High DPI support in Windows Forms
None of these suggestions worked for me but, something happened after I removed the Form.Font = new ... from the Form.Design.cs, the form started to re-scale properly, it works if the Font is defined in the constructor or not at all. Why? somebody else may be able to explained, I just can talk about the changed I made and took me a few minutes to figured out it was the root cause for the form I was working on. Hope it helps.
Since at least Visual Studio 2017 you just have to add a manifest file and uncomment this section:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
This is not an answer. This is my work around. None of the above answers or comments worked for me. I also searched for and tried other methods.
I have been using Visual Studio.NET with C# and Windows.Forms since it was originally released. Until VS 2022 and Windows 11 this year, setting the scale mode seemed to work fine. For some reason, some of my Form.Height values get reduced at run time. No problems so far with Form.Width being changed. For me, this problem started April 1, 2022 - so I first thought it was an April Fool's prank!
Anyway, I have given up trying solutions for now and decided it is more practical for me to just set the Form.Size in the constructor code.
I observe the Designer UI uses Size which it converts to ClientSize in its generated code as follows:
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.ClientSize = new System.Drawing.Size(744, 109);
this.ControlBox = false;
this.DoubleBuffered = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
My workaround in my Form's constructor looks like:
/// <summary>
/// Constructor
/// </summary>
public MyForm()
{
// In the designer, MyForm.Size was entered and displayed as 760, 148
InitializeComponent();
// At runtime, MyForm.Size is changed to 760, 111
// I will Reset this form's Size here so I can get full height again.
this.Size = new Size(760, 148);
}
Platform:
Windows 11 Professional
Microsoft Visual Studio Professional 2022
Version 17.1.6
VisualStudio.17.Release/17.1.6+32421.90
Microsoft .NET Framework version 4.8.04161
C# Tools 4.1.0-5.22165.10+e555772db77ca828b02b4bd547c318387f11d01f
HDMI 1920x1080 video (100% or no scaling)

How to make a C# Windows Forms app , converted for the Windows Store, start with Windows

I have created a Windows Forms C# app called "Desktop Web Tiles", that creates a panel with four websites that run with Microsoft Edge.
https://www.microsoft.com/en-us/p/desktop-web-tiles/9pmp8f1nqcj7?activetab=pivot:overviewtab
I converted the app with Desktop Bridge for Windows Store and published it. The only problem is I cannot make the Windows Store app run at startup for the end user. Looking around I found this link:
https://blogs.windows.com/windowsdeveloper/2017/08/01/configure-app-start-log/#V6oroyVxClAEehF6.97
It says to use the "windows.startupTask" Extension in my app manifest to make the app autostartup. The problem is I don't know much about handling the app manifest and I am stuck. It is essential for my app to start with windows, because it is fundamental for its usage. I would appreciate your help.
The problem is I don't know much about handling the app manifest and I am stuck.
If you used Desktop Bridge you will find Package.appxmanifest file where in the Windows Application Packaging Project, Then double click appxmanifest file - > press F7 view code-> Add the following to appxmanifest file.
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="uap mp rescap desktop">
......
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
.....
<Extensions>
<desktop:Extension
Category="windows.startupTask"
Executable="DesktopApp\DesktopApp.exe"
EntryPoint="Windows.FullTrustApplication">
<desktop:StartupTask
TaskId="MyStartupId"
Enabled="false"
DisplayName="TestWinFormApp" />
</desktop:Extension>
</Extensions>
</Application>
</Applications>
Run your app and enable app's startup in the startup list. For detail steps please refer provided blog. For better understanding I share appxmanifest here.

Application displays correctly on a 150% scaled monitor but not on a 100% one

I am currently developing an application in c# with .NET Framework 4.7
I have a problem with DPI scaling. On my computer I have two monitors, one with 150% scaling and another one with 100%. I added this code in my app manifest file:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
And it works perfectly fine.
i take the exe file and all its dependecies, take it to another computer who as only one screen with 100% scaling and the application doesn't look as it should do.
I hope you guys have a solution for me I am struggling since two days with this problem...
Well, like every time I post my problem I figure out the solution a few moments later.
I removed the manifest file from the application and changed the AutoScaleMode propertie to Dpi instead of Font for every form in my application.
And now it works like a charm.

UAC prompting on startup program with "asInvoker" on the "requestedExecutionLevel"

I am developing a very simple C# Windows Application (it only displays a message box saying "UACtest") that I want it to run at startup without prompting UAC.
For that I created a registry key for it under HKCU, and in the machine that I compiled it (Windows 8 64-bit using Visual Studio 2013) it runs at startup without promping UAC, as expected.
However, if I export the executable to a Windows 7 machine and do exactly the same thing, a UAC prompt is shown at startup.
Please note that the manifest of the executable has "asInvoker" on the "requestedExecutionLevel", the whole manifest is this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly
Also when I directly double click the executable, it never prompts UAC neither on Windows 7 32-bit or in the Windows 8 64-bit, the UAC prompting problem is only at startup.
I also tried to compile the executable on the Windows 7 32-bit machine (to maybe bypass some compatibility issues) and a strange thing happened, in that machine now UAC is not prompted at startup as expected, however, when I make the test on another machine (Windows 7 64-bit under Virtual Box) it prompted UAC at startup.
This has now really puzzled me, can someone please tell me a way to compile it so that it never prompts UAC at startup on all versions of Windows?
The project properties I used on Visual Studio 2013 are the default ones, except:
*Target framework: 2.0
*Platform target: x86
And the UAC settings on all machines where the default one: "Notify me only when applications try to make changes on my computer (default)"
Moving the executable has caused the destination system to mark the file as coming from a different system, and as a result the destination system will block execution at startup (in case the executable maliciously added itself to the startup).
Removing the block should fix the issue, it can however be avoided altogether if the executable is added to the system by an installer.
How to set up an installer is however a different question.
The problem was the Zone Identifier, which was set to 3, as for all files downloaded from internet.
If anyone else have this problem, just delete the Zone Identifier, for example with this tool:
http://jameskovacs.com/2005/04/11/zonestripper-updated/
And now the program should run at startup without prompting UAC.

Shell Context Menus

I am currently running a Windows 7 x64 machine.
I have written the following code to add a context menu on right click:
RegistryKey rKey = Registry.ClassesRoot.OpenSubKey("Directory\\Background\\shell", true);
String[] names = rKey.GetSubKeyNames();
foreach (String s in names)
{
System.Windows.Forms.MessageBox.Show(s);
}
RegistryKey newKey = rKey.CreateSubKey("Your Application");
RegistryKey newSubKey = newKey.CreateSubKey("command");
newSubKey.SetValue("", "C:\\Windows\\System32\\notepad.exe");
newSubKey.Close();
newKey.Close();
rKey.Close();
If I repeat the procedure directly on the registry, it works, but not via this.
I am also able to access the registry, as I have added a snippet that tells lists all subkeys that I require, but simply does not add one.
I have tested your code and it is well & good. Looks like you dont have access rights to open the registry from the code. Just follow these simple steps:
Close your Visual studio. Then Open it again as Run As Administrator mode. This one you can do by Right clicking on the Visual Studio link and choose Run As Administrator option.
Open your code and run it from there.
If you want to directly run the program from the Exe then Right click on Exe & choose Run As Administrator option.
If you don't want to do Run As Administrator, then follow these steps:
Add a new file to you project called App.manifest; by adding a new File from Project.
Add following data to that file, rest it will do the magic.
Just replace your application name with MyApplication.app. The important part is the section. Rest is auto generated.
xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator"
uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</asmv1:assembly>

Categories

Resources