TimeSpan.FromMilliseconds rounding!

Today’s fairly brutal gotcha: TimeSpan.FromMilliseconds accepts a double but internally rounds the value to a long before converting to ticks (multiplying by 10000).

For example, using C# interactive in VS2017:

> TimeSpan.FromMilliseconds(1.5)
[00:00:00.0020000]

> TimeSpan.FromMilliseconds(1234.5678)
[00:00:01.2350000]

Using .FromTicks works as expected:


> TimeSpan.FromTicks(15000)
[00:00:00.0015000]

To be fair this is the documented behavior:

The value parameter is converted to ticks, and that number of ticks is used to initialize the new TimeSpan. Therefore, value will only be considered accurate to the nearest millisecond.

But really, it isn’t expected since the input is a double!

This all came to light because a camera system I’m involved with started overexposing –  the integration time was programmed as 2ms instead of the desired 1.5ms. Hmmph!

So a little alternative:

> TimeSpan TimeSpanFromMillisecondsEx(double ms) =>
    TimeSpan.FromTicks((long)(ms * 10000.0))

> TimeSpanFromMillisecondsEx(1.5)
[00:00:00.0015000]

 

Note: the FromMilliseconds method delegates to an internal Interval method, passing the milliseconds value and 1 as the scale:


private static TimeSpan Interval(double value, int scale)
{
    if (double.IsNaN(value))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_CannotBeNaN"));
    }
    double num = value * scale;
    double num2 = num + ((value >= 0.0) ? 0.5 : -0.5);
    if ((num2 > 922337203685477) || (num2 = 0.0) ? 0.5 : -0.5);
    if ((num2 > 922337203685477) || (num2 < -922337203685477))
    {
        throw new OverflowException(Environment.GetResourceString("Overflow_TimeSpanTooLong"));
    }
    return new TimeSpan(((long) num2) * 0x2710L);
}

 

 

Advertisements

VS2017 and NuGet for C++/CLI

At the time of writing it still isn’t possible to use the NuGet package manager for C++/CLI projects. My workaround is to:

  1. Add a new C# class library project to the solution.
  2. Add any NuGet packages to this new project.
  3. Configure the C# project so it always builds in Release configuration.
  4. Use the Build Dependencies dialog to ensure that the new C# project is built before the C++/CLI project.
  5. Add to the C++/CLI project a reference to the NuGet packages by using the output folder of the C# project.

Example

Create a new solution with a C++/CLI class library…

Add a C# class library (.Net Framework), delete Class1.cs, then go to the solution’s NuGet package manager:

2018-09-05 12_19_13-.png

Install the Newtonsoft.Json package for the C# project:2018-09-05 12_29_01-Solution3 - Microsoft Visual Studio.png

Change the C# build configuration so that the Release configuration builds for both Debug and Release:2018-09-05 12_31_24-Configuration Manager.png

Then delete the unused Debug configuration:2018-09-05 12_31_42-Configuration Manager.png

2018-09-05 12_32_14-Configuration Manager.png

Make C++/CLI project dependent on the C# project:2018-09-05 12_34_09-Solution3 - Microsoft Visual Studio.png

(Note: I use the above for this dependency rather than adding a reference to the project to avoid copying the unused C# project to the C++/CLI’s output folders.)

Build the solution.

Add a reference to the Newtonsoft library by using the Browse option in the Add References dialog and locating the C# project’s bin/Release folder:

2018-09-05 12_38_57-Select the files to reference....png

Build the solution again. The Newtonsoft library will now be copied to the C++/CLI build folder:

2018-09-05 12_40_59-Debug.png

First test: add some code to the C++/CLI class to demonstrate basic JSON serialisation:

#pragma once

using namespace System;

namespace CppCliDemo {

	using namespace Newtonsoft::Json;

	public ref class Class1
	{
	private:

		String^ test = "I am the walrus";

	public:

		property String^ Test
		{
			String^ get() { return this->test; }
			void set(String^ value) { this->test = value; }
		}

		String^ SerialiseToJson()
		{
			auto json = JsonConvert::SerializeObject(this, Formatting::Indented);
			return json;
		}
	};
}

Then add a simple C# console app, reference just the C++/CLI project, and test the class:2018-09-05 12_50_22-Reference Manager - CSharpConsoleTest.png

static void Main(string[] args)
{
var test = new CppCliDemo.Class1();
var json = test.SerialiseToJson();
Console.Write(json);
}

 

The output – nicely formatted JSON 🙂

2018-09-05 12_51_48-C__Users_Jon_Source_Repos_Solution3_CSharpConsoleTest_bin_Debug_CSharpConsoleTes.png

Second test, make sure a clean rebuild works as expected:

  1. Close the solution
  2. Manually delete all binaries and downloaded packages
  3. Re-open solution and build
  4. Verify that the build order is:
    1. CSharpNuGetHelper
    2. CppCliDemo
    3. CSharpConsoleTest (my console test demo app)
  5. Run the console app and verify the serialisation works as before

 

 

Associate VS2017 with JSON files

Double-clicking a JSON file to try and open it in Visual Studio 2017 Professional doesn’t work; VS2015 worked fine. This link explains how to fix for the Community edition. The same principle applies for VS2017.

Using regedt32 first find the Visual Studio magic number:

Key: Computer\HKEY_CLASSES_ROOT\.json\OpenWithProgids
Value: VisualStudio.json.a8eb385c

2017-10-19 08_32_54-Registry Editor

 

Then find the associated shell key and create a new sub-key ‘Command’ with the path to devenv.exe as the default value:

Key: Computer\HKEY_CLASSES_ROOT\VisualStudio.json.a8eb385c\shell\Open\Command
Value: "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe"

2017-10-19 08_34_27-Registry Editor

 

Right-clicking a JSON file and selected Open with now looks like this:

2017-10-19 08_37_22-Sphere

 

Raspberry Pi Desktop virtual machine

This weekend I discovered that there is a Linux distribution, Debian Jessie, that now has the Raspberry Pi Desktop, download from here.

So I installed it as a virtual machine on my Windows 10 PC using VMWare Professsional Pro 14. The only difficulty was getting VMWare Tools working to allow automatic screen resizing and file sharing. Found some good info on the VMWare communities site (search for vmware tools debian jessie). From this thread there is a great perl script to help install VMWare Tools. The only modification I made was to delete –default from the line that runs the VMWare installer, without which the script will suggest an alternative option and abandon the installation.

I made a YouTube video of my virtual machine installation and VMWare tools configuration:

 

The script for VMWare tools:

#!/bin/bash 
 
sudo apt-get update 
sudo apt-get upgrade 
echo "Do go and mount your cdrom from the VMware menu" 
echo "press any key to continue" 
read -n 1 -s 
mount /dev/cdrom 
cd /media/cdrom0 
cp VMwareTools-*.tar.gz /tmp 
cd /tmp 
tar xvzf VMwareTools-*.tar.gz 
cd vmware-tools-distrib/ 
sudo apt-get install --no-install-recommends libglib2.0-0 
sudo apt-get install --no-install-recommends build-essential 
sudo apt-get install --no-install-recommends gcc-4.3 linux-headers-`uname -r` 
sudo ./vmware-install.pl 
 
sudo /etc/init.d/networking stop 
sudo rmmod pcnet32 
sudo rmmod vmxnet 
sudo modprobe vmxnet 
sudo /etc/init.d/networking start

 

 

 

VMWare Windows 10 expand/partition problem

Intro

I had a Windows 10 VM, managed using VMWare Workstation Pro 12. The VM was originally created with the default 60GB hard disk.

I needed to expand the disk, so I shutdown the VM, removed all snapshots, expanded the virtual HD to 120GB, and rebooted the VM. The plan was to use Windows 10’s disk management tool to expand the original partition and merge in the new partition.

But the recovery partition was sandwiched between the original and new partitions, and couldn’t be deleted using the Disk Management tool:

Untitled picture.png

I found the basics of how to fix this on the VMWare knowledge base. I’m adding my procedure here because it includes some useful screenshots.

Steps

I ran diskpart to work with partitions. (I ran as admin, but don’t think it was required.)

1Untitled picture

From the DISKPART shell, I then used the following to select and then remove the unwanted partition:

DISKPART> list volume

Volume ### Ltr Label Fs Type Size Status Info
 ---------- --- ----------- ----- ---------- ------- --------- --------
* Volume 0 D DVD-ROM 0 B No Media
 Volume 1 C NTFS Partition 59 GB Healthy System
 Volume 2 NTFS Partition 450 MB Healthy Hidden

DISKPART> select volume 2

Volume 2 is the selected volume.

DISKPART> delete partition override

DiskPart successfully deleted the selected partition.

The Disk Management window showed the new partition layout:

2Untitled picture.png

Next, I right-clicked on the C: partition and chose ‘Extend Volume’:

4.png

567

At last, a single 120GB partition.

8

🙂

 

C# TimeSpan TypeConverter and UITypeEditor

Code for this post is on GitHub.

I have an application that presents various TimeSpan properties to a user. The default string conversion isn’t great, in fact for anything other than hh:mm:ss it isn’t intuitive.

A TimeSpan of 1 day, 2 minutes, 3 hours, 4 seconds, and 5 milliseconds is shown in the example below:

Dev10.png

After a little noodling I found some articles that helped me put together something better (at least for me!).

The first feature is the presentation of a TimeSpan instance as a string:

dev10

The second feature is the ability to convert back from a string. For example, entering a value of 1h, 5s:

Dev10.png

… becomes…

Dev10.png

And finally, the property can present an interactive editor via a dropdown:

Dev10.png

Here’s an example of how the new classes are used as attributes on a TimeSpan:

[TypeConverter(typeof(TimeSpanStringConverter))]
[Editor(typeof(TimeSpanUIEditor), typeof(UITypeEditor))]
[DefaultValue(typeof(TimeSpan), "1.02:03:04.005")]
[DisplayName("Custom 1")]
public TimeSpan A { get; set; } = new TimeSpan(1, 2, 3, 4, 5);

VS2015 Update 2 VC.DB git mayhem

So today, after updating Visual Studio 2015 to Update 2, I was committing some changes to a project. Nestled amongst my own changes, deleted files, and new files, was a new VS2015 file, AOX3.VC.db (AOX3 is the name of my solution). This file is the new database engine and replaces (I believe) the SDF file. In Update 1 this was an experimental feature, but as of update 2 it’s official:

The new SQLite-based database engine is now being used by default.

I inadvertently added the file to my local git repository and then committed the changes.(I did the same thing on a couple of other projects, and made several more modifications and commits afterward).

The problem is, this file shouldn’t be in git, especially because it is around 150MB !

I only realised I had a problem when I tried to sync to my online (remote) repository, hosted by VSTS – luckily the attempt failed. The Synchronization panel had the following error message:

Failed to push to the remote repository. See the Output window for more details.

The output window had the following details:

Error encountered while pushing to the remote repository: Error while copying content to a stream.

Inner Exception:

Unable to read data from the transport connection: The connection was closed.

After a bit of googling I found I had to resort to the nuclear option to fix the problem.. deleting the file from the local git commit history.

Here’s what I did:

1. In VS2015 find the first commit that included the file. To do this I went to the Sync panel on the Team Explorer page and found the outgoing commit, then double-clicked it to see the commit details:

 

Screen Shot 2016-03-30 at 20.25.24.png

Screen Shot 2016-03-30 at 20.27.43.png

2. Note the parent commit ID of the first commit that included the new file (shown above, 645faa8c), then close VS2015.

3. Run a git bash shell in the solution folder. Then use the filter-branch command to delete the file from the last two commits. This required specifying a range of commits from the parent of the first commit all the way up the HEAD (the latest commit). This means noting the parent commit ID of the first commit that included the new file – as shown in the above screenshot. Here’s the git session:

jon@DESKTOP-0J37S2C MINGW64 /c/dev/Projects/Amber/AOX3 (dev_jon)
$ git filter-branch --tree-filter 'rm -f AOX3.VC.db' 645faa8c..HEAD
Rewrite 2fa87507296744092c2ac8b0c300b8c5973276ef (1/2) (0 seconds passed, remain
Rewrite 2917e9beea5ec0f546538345e33bd01586d359fb (2/2) (15 seconds passed, remaining 0 predicted)
Ref 'refs/heads/dev_jon' was rewritten

4. Open VS2015 and check the commits.. now the added/modified database file has disappeared from the list of changes:

Screen Shot 2016-03-30 at 20.35.52.png

5. I then edited my .gitignore file and added *.VC.db, then committed this mod and finally checked everything synchronized.. all worked as expected !

 

I guess the moral of the story is: don’t be flippant when adding new files, especially those you don’t recognize as your own. As the filter-branch documentation states:

This occurs fairly commonly. Someone accidentally commits a huge binary file with a thoughtless git add ., and you want to remove it everywhere.

This thoughtless programmer signing off, time to sleep 😉