The EASY way to make a .Net 8.0 WinForms app per monitor DPI aware

As posted in a rather old post, many apps have problems with windows scaling.

See these screen-dumps from Windows lengthy guide that was found here

With previous versions of .Net Framework this have been somewhat cumbersome, see my post here.

But with .Net 8.0 WinForms (well also 7.0 and 6.0), and Windows 11 (or newer 10), it is now fairly simple, as long as you follow a few rules, that can be relatively easy applied copying existing Framework projects. I experimented with VS 17.8 on Win 11 23H2.

Continue reading “The EASY way to make a .Net 8.0 WinForms app per monitor DPI aware”

Numeric facts on fractions, that few are aware of.

Assume a fraction k/m, with 0≤k≤m and look at its digits written out

  1. The fraction has a finite number of digits (less m) OR is a repeated sequence with at the most m-1 digits per group
  2. A repeated sequence will have at the most n-1 zeroes next to each other, if the number m is below 10ⁿ
  3. Interesting digit-structure of the sequence times m, with many 9’s (base minus 1) .

Continue reading “Numeric facts on fractions, that few are aware of.”

Partition backup, unlocked Android phones, through Recovery.

Have you ever wanted to backup entire partitions of your Android phone?
Well it actually is quite easy for an unlocked device – Does NOT need to be rooted.
ADD: This requires the presence of a recovery boot option! E.g. from LineageOS

(The above image is ‘borrowed’ from here)

Continue reading “Partition backup, unlocked Android phones, through Recovery.”

The EASY way to make a C# Windows.forms app really per monitor DPI aware

For .Net 8.0 WinForms apps go HERE (Also 7.0 and 6.0)

The below is for .Net Framework, latest being 4.8.

As posted in another post, many apps have problems with windows scaling.

See these screen-dumps from Windows lengthy guide that was found here

UPDATE 2020. After Windows “Creators update”, they made things slightly more complicated, sorry…

Here is a reasonably minimalistic approach. You will often just need code like this:

    public partial class Form1 : Form {
         public Form1() {
             InitializeComponent();
             DPI_Per_Monitor.TryEnableDPIAware(this, SetUserFonts);
         }
         void SetUserFonts(float scaleFactorX, float scaleFactorY) {
            var OldFont = Font;
            Font = new Font(OldFont.FontFamily, 11f * scaleFactorX, OldFont.Style, GraphicsUnit.Pixel);
            Refresh();
            OldFont.Dispose();
         }
         protected override void DefWndProc(ref Message m) {
             DPI_Per_Monitor.Check_WM_DPICHANGED(SetUserFonts,m, this.Handle);
             base.DefWndProc(ref m);
         }
     }

You will need to obey a few rules, but often it can be implemented in existing code in minutes!

Continue reading “The EASY way to make a C# Windows.forms app really per monitor DPI aware”

Save and restore positions of windows, WindowsPosSaveNRestore

WindowsPosSaveNRestore is a tool to save the position of windows for later restore

This is primarily useful if you frequently change display configuration, say add/remove external monitor(s) e.g. by docking, or turning a device with autorotate active.

Windows also has the bug that it sometimes cram all open windows (and icons [+]) on the primary screen on sleep.

Continue reading “Save and restore positions of windows, WindowsPosSaveNRestore”

Windows oddity: Schtasks.exe falsely reported error. Workaround.

If you run a command like this it works fine to any remote machine

    schtasks.exe /query /s SomePC /U MyAccount /P XXXXX

If you try to let it point back to your own machine you get an error-message

    ERROR: User credentials are not allowed on the local machine.

BUT this is actually FALSE!!! I found a workaround though..

Continue reading “Windows oddity: Schtasks.exe falsely reported error. Workaround.”

C# Set volume example

It took me quite some digging to find a clean way to set the standard default volume without external libs. So here the result.

If you do not want the console output, remove the writeline, and change the project from Console to Windows App.

I suggest using it as a Scheduled Task triggered by connect to user session and/or similar.

It is composed of a couple of bits and pieces combined/reduced primarily from these three.

https://stackoverflow.com/questions/31928429

https://stackoverflow.com/questions/36625576

https://social.msdn.microsoft.com/Forums/expression/en-US/90c6405d-44f6-48ce-82aa-c48a9b09dfb4

using System;
using System.Runtime.InteropServices;

namespace SetAudioLevel {
    class Program {

        [ComImport]
        [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IMMDeviceEnumerator {
            void _VtblGap1_1();
            int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice ppDevice);
        }
        private static class MMDeviceEnumeratorFactory {
            public static IMMDeviceEnumerator CreateInstance() {
                return (IMMDeviceEnumerator)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"))); // a MMDeviceEnumerator
            }
        }
        [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IMMDevice {
            int Activate([MarshalAs(UnmanagedType.LPStruct)] Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
        }

        [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IAudioEndpointVolume
        {
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify(/* [in] */__in IAudioEndpointVolumeCallback *pNotify) = 0;
            int RegisterControlChangeNotify(IntPtr pNotify);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify(/* [in] */ __in IAudioEndpointVolumeCallback *pNotify) = 0;
            int UnregisterControlChangeNotify(IntPtr pNotify);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelCount(/* [out] */ __out UINT *pnChannelCount) = 0;
            int GetChannelCount(ref uint pnChannelCount);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel( /* [in] */ __in float fLevelDB,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
            int SetMasterVolumeLevel(float fLevelDB, Guid pguidEventContext);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar( /* [in] */ __in float fLevel,/* [unique][in] */ LPCGUID pguidEventContext) = 0;
            int SetMasterVolumeLevelScalar(float fLevel, Guid pguidEventContext);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel(/* [out] */ __out float *pfLevelDB) = 0;
            int GetMasterVolumeLevel(ref float pfLevelDB);
            //virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar( /* [out] */ __out float *pfLevel) = 0;
            int GetMasterVolumeLevelScalar(ref float pfLevel);
        }

        static void Main(string[] args) {
            int Level = 20;
            if (args.Length == 1) { int.TryParse(args[0], out Level); }

            try {
                IMMDeviceEnumerator deviceEnumerator = MMDeviceEnumeratorFactory.CreateInstance();
                IMMDevice speakers;
                const int eRender = 0;
                const int eMultimedia = 1;
                deviceEnumerator.GetDefaultAudioEndpoint(eRender, eMultimedia, out speakers);

                object aepv_obj;
                speakers.Activate(typeof(IAudioEndpointVolume).GUID, 0, IntPtr.Zero, out aepv_obj);
                IAudioEndpointVolume aepv = (IAudioEndpointVolume)aepv_obj;
                Guid ZeroGuid = new Guid();
                int res = aepv.SetMasterVolumeLevelScalar(Level / 100f, ZeroGuid);

                Console.WriteLine($"Audio set for {Level}%");
                //Console.Beep();
            } catch (Exception ex) { Console.WriteLine($"**Could not set audio level** {ex.Message}"); }
        }
    }
}

.

Android vs WPD bug. Wrong filesizes reported

I stumbled upon a strange bug in what Android can report to e.g. Windows trough the MTP/WPD interface.

Under some circumstances it reports a VERY wrong file size, but if you by WPD open a stream and copy the file until it sends no more bytes, it returns the correct full content.

Continue reading “Android vs WPD bug. Wrong filesizes reported”

Displaying images. Colour management, sRGB and ICC. And when something fails.

Update This post started as description of a problem with displaying some files in FireFox and Chrome, but has been transformed to a more general post about sRGB, ICC, CMS and what happens if the browser gets it wrong…

It all started when I detected that most colours in some web-files got severely distorted when displayed in FireFox and Chrome on my system. Both JPG and PNG files were affected

colourchart_1_2_cmp

If you see the first one of these two squares blue_1 and blue_1_removed_srgb substantially different from the second clear blue, your CMS system have similar issues…
The first one is supposed to be a standard blue, the second is blue LEDs on your monitor only.

Continue reading “Displaying images. Colour management, sRGB and ICC. And when something fails.”

Working with numbers in Q with large nominator/denominator in C#

A nerdy idea:

A C# class that quicly can supply a lot of primes (here limited to about the largest prime about 50G – as arrays with over 2G entries are not currently supported without splitting the arrays)

A struct that supports basic arithmetic for large accurately represented numbers in Q,  by factorization into primes.

A test program that tries to find solutions for a!b!=c! with 1<a<b<c

Continue reading “Working with numbers in Q with large nominator/denominator in C#”

PhotoView with Delete&Transfer of matched files, e.g. RAW

This is a plain PhotoViewer with just TWO special function:

The ability to show more EXIF info than most and to delete or transfer matching partner files on request also, according to user defined masks.

E.g. Also handle RAW or cropped variant of a file named with predefined syntax.

PhotoView_Dump

Settings for position, size, splitter positions, last used folders… can be saved in users registry.

Download zip: PhotoView.Zip

This is a ‘work in progress’, so expect bugs might be present, and that things can still change quite a bit. (Last modified 2018-09-30)

Continue reading “PhotoView with Delete&Transfer of matched files, e.g. RAW”

Eye resolution test

I have made a simple test image to test the resolution of your eyes on a phone, phablet, tablet, laptop or PC!

The most common result is it is pointless to go beyond around 1/12000 of the viewing distance

Be SURE it is shown in the screens native resolution. e.g. 960 pixels should fill half a FullHD display. (or use one of the added ones with your screens resolution)

Be SURE that your browser or your windows settings doesn’t do any scaling/zooming/smoothing, i.e. one pixel in the image is one pixel on the display. (If in doubt take a magnifying glass -or macro camera- and look closely on the screen, it should be like the mock-up later in this post)

ResolutionTestText_qFHD

 

It is the point where the single line pair is indistinguishable from the double line we are looking for (that is: where it looks like one continuous thick line)

You will most likely find the finest resolution using the red or green figure.

Use any prescribed glasses that you normally would for the distance – we are testing resolution, not focusing ability.

NOTE: If you got a PenTile display, usually the green will do fine! Have a look at this on different subpixel arrangements. Several pixel arrangement exists out there, that could have similar issues…

Continue reading “Eye resolution test”