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”

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

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()
            DPI_Per_Monitor.TryEnableDPIAware(this, SetUserFonts);

        void SetUserFonts(float scaleFactorX, float scaleFactorY) {
            Font = new Font(Font.FontFamily, 11f * scaleFactorX, GraphicsUnit.Pixel);
        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”

Disqus-comments, formatting

Here Is a small guide in Disqus-formatting, that I have ‘published’ several times on the old blog (with tiny variation).

UPDATE: Should in 2019 finally be more or less obsolete for wide enough windows!

Continue reading “Disqus-comments, formatting”

Windows, Oddity with Schtasks.exe, and falsely reported error.

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!!!

Continue reading “Windows, Oddity with Schtasks.exe, and falsely reported error.”

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.

using System;
using System.Runtime.InteropServices;

namespace SetAudioLevel {
    class Program {

        [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}%");
            } catch (Exception ex) { Console.WriteLine($"**Could not set audio level** {ex.Message}"); }


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


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.”

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.


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 zooming or 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)



It is the point where the single line pair is indistinguishable from the double line we are looking for (that is where it is 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”