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}"); }


Get new/changed files from WPD-device, e.g. Android. Enhanced version of Christophe Geers’ PortableDevices

I stumbled upon this nice project by Christophe Geers.

And edited and enhanced it to a tool that works a bit like an advanced REPLACE /UPDATE  to a tree on the PC based on the name of the device and the drives it exposes.

It is an efficient way to get changed & new files from a device to a PC.

Update: Now supports Exclude also.

It works with a WPD connected device, e.g. an Android device USB-connected in MTP or PTP mode.

Here an example of some of the tree generated

Most backup tools does NOT allow you to do an incremental backup, but they DO allow you to deselect e.g. images. So use this tool to do the incremental backup of the huge WPD-exposed stuff like the images/videos/music, and let your backup tool do backups of all the rest – and in more finite time than a total backup of everything every time – thus making it a bliss to take backups much more often….

Continue reading “Get new/changed files from WPD-device, e.g. Android. Enhanced version of Christophe Geers’ PortableDevices”

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