16 August 2025

Python - Execute a query with pyodbc

To work with a database via ODBC, first install the PyOdbc package and import it. The following simple query shows how to execute a select query and return data:
import pyodbc

def get_user(username) -> int:   
    with pyodbc.connect("Server=(LocalDB)\Test; Integrated Security=true; Driver={ODBC Driver 17 for SQL Server}") as conn:
        with conn.execute("SELECT id FROM Users WHERE username=?", username) as cursor:
            rows = cursor.fetchall()
    
    if len(rows) <= 0:
        return
    
    return rows[0].id

print(f"user ID: {get_user("EGS")}")

24 June 2025

.NET - Read/write a binary file line by line

To read a text file, you can use a StreamReader, but to read a binary file, you need a BinaryReader.This is how you use it:

if (File.Exists(FILENAME))
{
    using (var stream = new FileStream(FILENAME, FileMode.Open))
    using (var reader = new BinaryReader(stream))
    {
        if (stream.Length <= 0) return; //The file is empty.
        int i = reader.ReadInt32();
        string s = reader.ReadString();
    }
}

Writing is similar:

using (var stream = new FileStream(SaveFilePath, FileMode.Create))
using (var writer = new BinaryWriter(stream))
{
    writer.Write(305);
    writer.Write("EGS");
}

The file will be automatically created if it doesn't exist yet.

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();