File type associations in Windows 10

Ever since Windows 3.1, the association between a file type (like png, or txt) and an application has been done through a few keys in the Windows Registry, as explained in the documentation on MSDN.

HKEY_CLASSES_ROOT
    .jpg
        (Default) = Bearly.jpg
    .Bearly.jpg
       (Default) = BearlyPhotoViewer
    BearlyPhotoViewer
       (Default) = "Bearly.exe" "%1"

But starting with Windows 8 and continuing in Windows 10, this is not enough anymore. Windows now allows the user to associate a file type with a certain application only via the built-in GUI. The above registry keys, although still necessary, are not enough anymore to achieve this association.

The key is a special hash value in:

HKEY_CURRENT_USER
    Software\Microsof t\Windows\CurrentVersion\Explorer\FileExts
        .jpg
            UserChoice
                "Hash"="p3ahKz450J2="
                "ProgId"="Bearly.jpg"

that is computed and set when the the user selects a program in the “Open with…” window.

The hash is computed from the following values:

extension = ".jpg"
userSID = "S-1-5-21-463486358-3398762107-1964875780-1001"
progId = "Bearly.jpg"
keyTimeStamp = "01d3442a29887400"; timestamp of the UserChoice key
experience = "User Choice set via Windows User Experience {D18B6DD5-6124-4341-9318-804003BAFA0B}"
hash = Base64(MicrosoftHash(MD5(toLower(extension, sid, progid, regdate, experience))))

For computing the actual hash, there is a SetUserFTA command line tool or another open source implementation on github that also shows how to extract the experience string from Shell32.dll.

Having more of a WPF background, it’s hard for me to understand why in HTML/CSS it’s so difficult to create full-screen UIs. In WPF, with a relative small number of layouts, it’s easy to arrange and align anything anywhere. Align a panel to the bottom of the screen, centering panels inside other panels or overlapping panels is easy to implement and easy to understand.

Creating full-screen UIs in HTML has always been complicated. But the show continues even today when IE is just a medieval story and there are different systems (flexbox, grid) that are supposed to make things easier.

Seasoned HTML designers argue that it’s not hard to create these layouts, but rather people complaining simply don’t understand well enough how CSS works. That’s were I have to disagree: it’s not just that it’s hard to use, but rather it’s unintuitively designed. When you have a parent-child relation between two panels, the way they align is driven not only by the attributes set directly on them, but also on other controls (siblings of the child, or even worse totally unrelated controls).

This make creating UIs in HTML so much more complicated than in WPF (or even in Android…). In fact, it is so complicated that it has got the unofficial (but well deserved) name of the Holy Grail layout. And even if you succeed doing this Holy Grail by carefully (and frustrating) setting style attributes on different divs, good luck hosting a Holy Grail inside a Holy Grail layout.

The concrete case I was working on, was a (simple) Google maps style layout like this:

Of course, I didn’t wanted to hardcode any heights or widths or magins, the title bar, toolbar and status bar should resize themselves to their content. And the left side panel, I wanted to have the scroll inside it not on the right of the page.

Here’s the html for the above layout:

and the CSS:

This is the simplest form I could get with.

I’m putting these here because I’m very sure I’m going to need them at some point in the fugure ūüôā Also available for jamming on codepen.io.

Easy CD with GitHub Workflows

When working on small utilities / tools kind of projects that you upload somewhere for others to be able to quickly get them, more often than not it becomes difficult to re-upload after you add a new feature, especially if some time has passed by since the last upload.

Here GitHub workflows come to help. Every time you push something to a specific branch, GitHub can trigger an action to run a small script that can compile your application, run unit tests, publish it and upload it to the desired download site.

One of my simplest workflows looks like this:

name: .NET Core
on:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: windows-latest
    steps:
    - name: Display the path
      run: echo $PWD
      shell: bash
    - uses: actions/checkout@v2
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: '3.1.100'
    - name: Publishing
      run: dotnet publish --configuration Release --self-contained:false
    - name: Installing lftp
      run: choco install lftp
    - name: Uploading to ftp
      run: lftp ${{ secrets.FTP_SERVER }} -u ${{ secrets.FTP_USERNAME }},${{ secrets.FTP_PASSWORD }} -e "set ftp:ssl-allow no; set ssl:verify-certificate no; mirror --reverse --continue --dereference -x ^\.git/$ ScreenZoomPlus\\bin\\Release\\netcoreapp3.1\\win-x86\\publish ScreenZoomPlus; quit"

(the file goes inside the repository, in the .github\workflows\name-of-the-file.yaml)

The file is kind of self descriptive (but there is also plenty of documentation):

The workflow is triggered every time something is pushed on the master branch. Usually, on my hobby-projects, I work on a dev branch and when I’m happy with what I did, I push everything to the master branch. Then the GitHub action kicks in.

Everything is run in like a VM environment, nothing is preinstalled, so first step is to make sure .Net core is there. Then dotnet publish is called to build and create the final executable with all the dependencies.

The tricky part was to upload the exe file to FTP. For that I install lftp (through Chocolatey) and lftp is able to upload to a FTP server.

Some variables (secrets.FTP_SERVER, FTP_USERNAME and FTP_PASSWORD) are then used in order not to keep the sensitive data in plain text in the repositories (modern CI/CD). These variables are defined in the Settings > Secrets section of the GitHub repository.

My git commands

1.

git commit --amend --date=now --no-edit

to change the date of the last (local) commit. –no-edit for not modifying the commit message, otherwise it will open a text editor to enter new commit message.

2.

git commit --amend -m '#572: Fixed crash'

to change the message of the last (local) commit.

3.

git merge feature/CoolFeature --no-ff

merge branch ‘feature/CoolFeature’ without fast-forwarding current branch

4.

git merge feature/CoolFeature --squash -m '#573: CoolFeature'

will combine all the commits of ‘feature/CoolFeature’ into one single commit and merge that commit to current branch.

Smoother log4net integration in .Net applications

Part 1

Many developers I’ve seen and many blogs on internet use the following line to declare a Logger in a class:

private static readonly log4net.ILog Log = 
    log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Although it might bring some advantages in some cases (inheritance), most of the time it’s not really necessary to obtain the surrounding Type by calling reflection, so I generally prefer to use:

private static readonly log4net.ILog Log = 
    log4net.LogManager.GetLogger(typeof(MyClass));

where MyClass is the class I’m adding this as a member;

This is a bit prone to Copy/Paste mistakes when this line is taken from one class and pasted in another, and you forget to change the name of the class. So, to overcome this, I’ve made Visual Studio code snippet:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>log</Title>
      <Author>[USERNAME]</Author>
      <Description>
      </Description>
      <HelpUrl>
      </HelpUrl>
      <Shortcut>log</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="true">
          <ID>className</ID>
          <ToolTip>The full name of the type will be used as the name of the logger to retrieve.</ToolTip>
          <Default>
          </Default>
          <Function>ClassName()</Function>
        </Literal>
      </Declarations>
      <Code Language="csharp" Delimiter="$"><![CDATA[private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof($className$));]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Put this into a file named log.snippet and save it to your Documents\Visual Studio 2017\Code Snippets\Visual C#\My Code Snippets\ folder and when you will write log in Visual Studio and press TAB twice, the line will be inserted with the name of the class correctly updated.

 

Part 2

There is an online, unofficial but complete, schema that can be used to have IntelliSense when editing the log4net.config file. You can download it here: http://csharptest.net/downloads/schema/log4net.xsd.

Custom window movement and resize in WPF

Windows can be moved on the screen by dragging their title bar; they can be resized by dragging their borders. But what if our window needs no title bar / borders (or they are custom drawn)? (aka WindowStyle="None").

Introducing MoveResizeBehavior, a WPF custom behavior that can be added to any FrameworkElement will provide move and resize functionality for its parent window.

<Border DockPanel.Dock="Top" Height="11" Margin="7"
        b:MoveResizeBehaviour.ResizeWindow="Top"/>
<Border DockPanel.Dock="Bottom" Height="11" Margin="7" 
        b:MoveResizeBehaviour.ResizeWindow="Bottom"/>
<Border DockPanel.Dock="Right" Width="11" Margin="7,0" 
        b:MoveResizeBehaviour.ResizeWindow="Right"/>
<Border DockPanel.Dock="Left" Width="11" Margin="7,0" 
        b:MoveResizeBehaviour.ResizeWindow="Left"/>
<Border Height="43" VerticalAlignment="Top" 
        b:MoveResizeBehaviour.MoveWindow="True"/>

where

xmlns:b="clr-namespace:AndreiPana.WPF.Utilities"

ResizeWindow can take one of the following values: None, Left, TopLeft, Top, TopRight, Right, BottomRight, Bottom, BottomLeft, while the MoveWindow can be either True or False.

Internally, the behaviors attach to the MouseDown event, so the FrameworkElements on which they will be set better not process themselves MouseDown, otherwise it might interfere with the behaviors.

A simple and small test project showing the functionality is available on Github but, for convenience, here’s the MoveResizeBehavior.cs file that you can copy/paste to any WPF project and used it as it is:

VisualStudio Output Window Error highlighter

In Visual Studio 2015, the Output Window contains plain text, with no colorizing or highlighting of any kind. This makes it hard to spot some errors in the multitude of output text, for example WPF’s binding errors.

I have long wanted an extension to highlight this kind of errors, so I decided to write one for myself. Very simple, it just puts in red all the lines containing “Error” so that now I can see if I miss any binding error in WPF, definitely saving me a lot of time.

OutputColorizerVSX_Screenshot

Download the extension:

To install it, just run the vsix file and the VSIX Installer will come up and do the job.

Xaml design-time DataContext

System.Windows.Data Error: 40 : BindingExpression path error: 'Emial' property not found on 'object' ''Customer' (HashCode=49475561)'. BindingExpression:Path=Emial; DataItem='Customer' (HashCode=49475561); target element is 'Label' (Name=''); target property is 'Content' (type 'Object')

This is one of the most frustrating binding errors that happen while writing bindings in xaml. Sometimes, if not careful enough, it might easily get lost in the Visual Studio output window. To reduce the number of such errors and to design the UI more easily, one may benefit of the support of auto-completion while writing xaml bindings in Visual Studio.

To add a design time DataContext:

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Sample.ViewModels"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        Title="MainWindow" Height="350" Width="525"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type=vm:Customer, IsDesignTimeCreatable=True}">
    <Grid>
        <StackPanel>
            <Label Content="{Binding Emial}" />
        </StackPanel>
    </Grid>
</Window>

Lines 6 and 9 are the ones that do the trick. The Visual Studio designer will use this DataContext object at design time.
Lines 5 and 8 are also needed to instruct the real xaml compiler to ignore this DataContext attribute.

Although I didn’t find any official documentation over the DesignInstance, this extension supports three parameters:

Type – this is the type of the object you want to use as a DataContext at design time (in my case here, I have a simple Customer view-model that has some Name, Address and Email properties).

IsDesignTimeCreatable Рif this is true the designer will simply instantiate the type and use it; if it is  false the designer will generate a type with the same properties as the one specified and instantiate that type.

To be “design time creatable” the type must have a constructor with no parameters. If it has, the designer can instantiate it and use it. If the type does not have a default constructor, the designer doesn’t know what parameters to pass to the other constructors so here is where IsDesignTimeCreatable = false helps.

The drawback of using IsDesignTimeCreatable = false is that any properties set in the original type are not visible in the dummy type created and instantiated.

There are some workarounds for using IsDesignTimeCreatable = true like adding a parameterless constructor (perhaps in a derived class and using that class instead), but it all depends on the exact scenario.

CreateList Рif true the designer will create a collection of your type and that can be used for bindings to the ItemsSource properties, for example or in another place where a collection is expected.

Now Intellisense shows auto-completion for DataContext members:

xaml-datacontext-designtime

Intellisense documentation for Unity3D API in Visual Studio

By default, Unity3D 4.6 does not ship with XML documentation for the Unity API, therefore Visual Studio is unable to display documentation in Intellisense.

To fix this, download the file UnityEngine.xml¬†(right-click, Save As…) and copy it to the following Unity folder:

c:\Program Files (x86)\Unity\Editor\Data\Managed\

(Path may be different if Unity was installed in another location than the default one)

folder

Before:

after

After:

before

Note that administrator permission might be required to write to Program Files.