11 November 2024

Windows API - Set the icon of a window created with P/Invoke

This actually turned out to be very easy. Just load the icon as you would in .net.
var icon = new Icon(GetResourceStream("Cards.ico"));

GetResourceStream is a custom method of mine to load the icon file from the embedded resources.

To create the window, you already defined a window class struct somewhere.
var windowClass = new WindowClassEx();
All you have to do, is pass the icon's internal handle to this structure.
windowClass.Icon = icon.Handle;
And make sure the icon object is not destroyed while the window is open.

Windows will look for a small icon for the title bar in Icon when IconSmall is not set.

29 January 2024

GIT - avoid merge-commits

GIT inserts commits named merge branch '{name}' when there was a deviation from the branch. They can be reunited with a rebase command.
git pull --rebase

12 October 2023

GIT - rename a branch

Here's how to rename a GIT branch from Windows Explorer. This assumes GIT is installed on the computer.

  • Enter git branch -m "{new name}".
  • Enter git push origin :"{old name}" "{new name}".
  • Enter git push origin -u "{new name}".

22 September 2023

GIT - commit changes

Here's how to commit changes to GIT from Windows Explorer when the IDE doesn't have built-in support for GIT. This assumes GIT is installed on the computer.

  • In Explorer, navigate to the root folder of the project and choose File > Open command prompt.
  • Alternatively, run the command prompt; enter {drive letter}: unless the project is on the C drive; then enter cd "{full path to project root}".
  • Enter git add . to add new files.
  • Enter git commit -m "{description of the commit}".
  • Enter git push.

04 August 2023

MFA - Generate time-based one-time passwords (TOTP)

I had to implement MFA for a web application. I needed to generate a key the user could save in an authenticator app. My application had to use this key to generate a code to validate the authenticator codes the user would enter.

Generate the key

Generate a truly random sequence of bytes and convert them to base32. I'm using the default SHA1 algorithm to generate keys of twenty characters.

const string BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

using (var gen = new RNGCryptoServiceProvider()) //Use a cryptographically secure provider!
{
    byte[] bytes = new byte[HMACSHA1.Create().HashSize / 8];
    gen.GetBytes(bytes); //Fills the array with 20 bytes
    
    byte[] base32 = new byte[bytes.Length];
    double d = (double)byte.MaxValue / (double)BASE32_CHARS.Length;
    
    for (int i = 0; i < bytes.Length; i++)
    {
        double c = (double)bytes[i];
        int j = (int)Math.Floor(c / d); //If c is 255, j is 32, which is out of bounds!
        base32[i] = (byte)BASE32_CHARS[j < BASE32_CHARS.Length ? j : BASE32_CHARS.Length - 1]; //Scale from 255 to # of possible chars
    }
    
    return Encoding.ASCII.GetString(base32);
}

Generate a code

First calculate the number of intervals that passed since the reference time. This time is usually the unix epoch of 1 january 1970 0:00:00 UTC. Then decode the base32 key and use it to hash the interval counter. Finally use this hash to generate a code like an authenticator app would.

const uint INTERVAL = 30; //The default of 30 seconds
const uint CODE_LENGTH = 6; //The default of 6 digits

double seconds = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
ulong counter = (ulong)Math.Floor(seconds / INTERVAL);
byte[] counterBytes = BitConverter.GetBytes(counter);
Array.Reverse(counterBytes); //Must be big-endian while .net is little-endian

var hmac = HMACSHA1.Create();
hmac.Key = DecodeBase32(key);
hmac.ComputeHash(counterBytes);

int offset = hmac.Hash[hmac.Hash.Length - 1] & 0xf;
int bin = (hmac.Hash[offset + 0] & 0x7f) << 24 |
          (hmac.Hash[offset + 1] & 0xff) << 16 |
          (hmac.Hash[offset + 2] & 0xff) << 8 |
          (hmac.Hash[offset + 3] & 0xff);

return bin % (int)Math.Pow(10, CODE_LENGTH);

DecodeBase32(string value):

var base32 = BASE32_CHARS.Select((c, i) => new { c, i }).ToDictionary(ch => ch.c, ch => ch.i); //Each char and it's 0–31 index
string bits = string.Concat(value.Select(c => Convert.ToString(base32[c], 2).PadLeft(5, '0'))); //A string of 0's en 1's
return Enumerable.Range(0, bits.Length / 8).Select(i => Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();

02 August 2023

Visual Studio - flickering scroll bar when editing certain file types

I got a new laptop and installed Visual Studio 2022 on it. When editing sql and aspx files on the secondary monitor, I could not scroll down or right. The scrollbar just flickers when I hovered over it. With Visual Studio opened on the main monitor, scrolling works fine. It turns out this is an issue with Visual Studio rendering in combination with the main monitor scaled above 100 percent. There are two solutions for it.

Disable the Visual Studio option Environment > General > Optimize rendering for screens with different pixel densities and restart Visual Studio
This solves the scrolling issue, but causes text on all panels to appear a bit blurry.
Set Windows option System > Display > Scale to 100 percent.
This also solves the scrolling issue, but now your main monitor is not at the (for me at least) recommended 125 percent.

Windows 8-11 - start something automatically on start-up

For my work, I want a bat-file to run when Windows starts up. This starts up a local database server with my test database I use for all my development.

Startup folder

To do this, launch Explorer and go to %AppData%\Microsoft\Windows\Start Menu\Programs\Startup. Paste a shortcut to the file you want to run in this folder.

Run a command

Alternatively, you can run a command via Windows' Task Scheduler. Create a new task and set it for Windows 8 or 10. Add a trigger and set it to at log in. Add an action and enter the command including any arguments.