Visual Studio 2010 Macro to add copyright at the top of a file


Today I thought I would create a simple macro to add a copyright message to the top of a C# source file, then remove and sort the usings.

The macro takes a quite simple approach: just create a file called ‘copyright.txt’ and place it at the root (or solution) level of your project. Then when you are editing C# code, run the macro and it will remove and sort ‘using’ statements, and insert your copyright text at the top of your source code.

The result is as follows:

Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.IO
Imports System.Diagnostics

Public Module BtlModule
    Public Function GetFileContents(ByVal FullPath As String, _
       Optional ByRef ErrInfo As String = "") As String

        Dim strContents As String
        Dim objReader As StreamReader
        Try
            objReader = New StreamReader(FullPath)
            strContents = objReader.ReadToEnd()
            objReader.Close()
            Return strContents
        Catch Ex As Exception
            ErrInfo = Ex.Message
        End Try
    End Function

    Sub InsertCopyright()
        Dim solutionDir As String = System.IO.Path.GetDirectoryName(DTE.Solution.FullName())
        Dim copyright As String = GetFileContents(solutionDir + "\\copyright.txt")
        DTE.ActiveDocument.Selection.StartOfDocument()
        DTE.ActiveDocument.Selection.LineUp()
        DTE.ActiveDocument.Selection.Insert(copyright)
        DTE.ActiveDocument.Selection.NewLine()
        DTE.ExecuteCommand("Edit.RemoveAndSort")
    End Sub
End Module

The only requirement is that you have a ‘copyright.txt’ file at the same level as your .sln. An improvement would be to check that the first line doesn’t already start with a comment, and include the word ‘copyright’.

Lastly, wire up the macro command to your toolbar as follows at http://msdn.microsoft.com/en-us/library/3dy74ad1.aspx

Assigning a Macro to a Toolbar Button

1. Choose Customize from the Tools menu.
2. Choose the Commands tab.
3. Click the Toolbar radio button and select the target toolbar from the drop down list.
4. Click the Add Command… button.
5. Select Macros in the Categories list.
6. Select the desired macro from the Commands list, and then click OK.
7. Click Modify Selection and choose the appropriate commands to modify the appearance of the button, such as renaming it, assigning an image to it, and so on.

TPL: Starting tasks

One question you should ask yourself when starting to use the TPL, is whether to use Task.Start(), or Task.Factory.StartNew(). Fortunately, there’s a helpful post by Stephen Toub that answers this.

The answer? Use Task.Factory.StartNew().

Directly quoting:

However, if you use Task.Factory.StartNew, we know that the task will have already been scheduled by the time we hand the task reference back to your code, which means it’s no longer possible for threads to race to call Start, because every call to Start will fail. As such, for StartNew we can avoid that additional synchronization cost and take a faster path for scheduling the task.

Please read his post, it’s very informative.

Task Parallel Library and the ThreadPool

For my benefit I thought I’d take a very quick look at ThreadPool and TPL (here,and here). We’ll take the Fibonacci example we often see in the web as our example.

Source code is here.

Starting a set of calculations using the ThreadPool is quite trivial:

        private void ButtonStart_Click(object sender, RoutedEventArgs e)
        {
            Random r = new Random();

            // Configure and launch threads using ThreadPool:
            messages.Add("launching " + FibonacciCalculations.ToString() + " user work items into the threadpool...");
            for (int i = 0; i < FibonacciCalculations; i++)
            {
                Fibonacci f = new Fibonacci(r.Next(20, 40));
                f.CalculationCompleted += new Fibonacci.CalculationCompletedEventHandler(fibonacci_CalculationCompleted);
                ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
            }
        }

Using Parallel.ForEach is also reasonably trivial, we just need to collect up all the calculations we are going to make into an IEnumerable<> collection, then iterate across them using Parallel.ForEach:

        private void ButtonStartTaskParallel_Click(object sender, RoutedEventArgs e)
        {
            List fibArray = new List();
            Random r = new Random();

            messages.Add("launching " + FibonacciCalculations.ToString() + " tasks via Parallel.ForEach");
            for (int i = 0; i < FibonacciCalculations; i++)
            {
                Fibonacci f = new Fibonacci(r.Next(20, 40));
                f.CalculationCompleted += new Fibonacci.CalculationCompletedEventHandler(fibonacci_CalculationCompleted);
                fibArray.Add(f);
            }

            Parallel.ForEach(fibArray,
                obj =>
                {
                    obj.Calculate();
                });

            //  We’re on the gui thread, and so block until all tasks have complete
        }

However, doing this blocks the gui thread as the Parallel.ForEach blocks until all tasks have completed. We can wrap the Parallel.ForEach in a Task, which we then start asynchronously, returning control to the gui thread, whilst the calculations continue in the background:

            var task = new Task(() =>
            {
                Parallel.ForEach(fibArray,
                    obj =>
                    {
                        obj.Calculate();
                    });
                fibonacci_CalculationCompleted(this, new TEventArgs("all tasks completed"));
            });

            task.Start();

The benefits of TPL vs. ThreadPool are discussed here.

C# is not C++

I have to occasionally remind myself that C# is not C++. I spent some time tracking down an errant thread that kept my application hanging around long after the main window terminated.

The code is using a dummy window to present a top-most dialog so that notifications don’t get hidden behind other desktop windows:

void Callback()
{
            Window dummyWindow = new Window();
            dummyWindow.Topmost = true;
            MessageBox.Show(dummyWindow, "hello", "hello");
            //dummyWindow.Close();
}

The key is the commented out line. In C++ things go out of scope, in C# they can hang around. They can hang around even longer if they have their own threads inside them (for the message pump).

Mercurial on a QNAP NAS

I spent some time today getting my QNAP NAS to serve mercurial repositories. My main motivation for this is that I like to create cheap copies of my projects and tinker around, then push them back to the main repository containing only the pertinent changes. I could, of course, have done this with Subversion but I like the challenge. And of course, prefer mercurial.

The steps involved seem to be poorly documented across the web, so the following is a fuller (though still rough) list of what I had to do to get things working. Your mileage may vary, as the saying goes.

  • ssh to your NAS, and use ipkg:
ipkg install py26-mercurial
  • create your repository area, e.g.:
mkdir -p /share/Public/repositories/mercurial
  • cd into this folder and create a shell script called reset_permissions.sh to reset permissions:
chgrp -R everyone *
chmod go+wx *
chmod go+wx */.hg
chmod -R g+rw *
  • Find and edit your apache.conf file, e.g. in /etc/config/apache/apache.conf, and add:
ScriptAlias /cgi-bin/ /share/Qweb/cgi-bin/
<Directory "/share/Qweb/cgi-bin">
 AllowOverride None
 Options ExecCGI
 SetHandler cgi-script
 AddHandler cgi-script .cgi .pl .py
 Order allow,deny
 Allow from all
</Directory>
  • Also add at the bottom:
Include /etc/config/apache/hg/main.conf
  • Create and edit: /etc/config/apache/hg/main.conf, with:
ScriptAliasMatch        ^/hg(.*)        /share/Qweb/cgi-bin/hgweb.cgi$1
<Directory  /share/Qweb/cgi-bin/> Options ExecCGI FollowSymLinks
 AllowOverride None
</Directory>
  • Create and edit: /share/Qweb/cgi-bin/hgweb.cgi
#!/usr/bin/env python
#
# An example hgweb CGI script, edit as necessary
# See also http://mercurial.selenic.com/wiki/PublishingRepositories
# Path to repo or hgweb config to serve (see 'hg help hgweb')

config = "/share/Public/repositories/mercurial/hgrc"
# Uncomment and adjust if Mercurial is not installed system-wide:1
#import sys; sys.path.insert(0, "/share/MD0_DATA/.qpkg/Optware/lib/python2.6/site-packages")
# Uncomment to send python tracebacks to the browser if an error occurs:

import cgitb; cgitb.enable()
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb import hgweb, wsgicgi
application = hgweb(config)
wsgicgi.launch(application)
  • Create and edit /share/Public/repositories/mercurial/hgrc:
[hooks]
changegroup = hg update >&2
[web]
allow_push = *
push_ssl = false
[collections]
/share/Public/repositories/mercurial = /share/Public/repositories/mercurial
  • Restart apache:
/etc/init.d/Qthttpd.sh restart

The last issue to address is that you can’t actually create remote repositories via http, so you need to do the following step each time for a new repository:

mkdir -p /share/Public/repositories/mercurial/repo1
cd /share/Public/repositories/mercurial/repo1
hg init
cd ..
reset_permissions.sh

and you should be done.

You should now be able to see http://nas/hg and a list of repositories (in this case just ‘repo1′).

If you have an existing repository on your local desktop, create it with the same name on the NAS, following the steps above, then edit your local .hg/hgrc file to contain:

[paths]
default=http://nas/hg/repo1

Then hg push, and your repository should be safely stored on your NAS.

Presumably these steps will work for other server configurations, subject to changing some of the paths in some of the steps.

[Update - fixed some typos, and moved the cgi-bin location to the raid section of the NAS where the rest of the web pages are hosted from.]

Jira/Postgresql/Subversion

If you’re a freelancer or hobbyist you’ll probably want to get your development environment up and running rather quickly.  The following is a quick 5 minute (!) install of Jira (a bug tracking system) onto a Windows 7 PC with Postgresql, and integrating it into Subversion.  The Subversion part of this post is entirely optional (especially since more and more people prefer DVCS).  I am not going to write anything here about setting up Subversion, Mercurial, git, or your VCS of choice.  This is generally quite simple, and described elsewhere.

Why?

Why Jira?  For one thing, I use it at work.  For another, it has a free 3-user license.  For most freelancers, and home hobbyists, that’s 2 more than you need.  And lastly, Atlassian claim ‘legendary service‘.  In short, their products work out of the box with next-to-zero configuration.  Jira is as simple or complex as you want it to be.  It will also manage release notes for you in a simple way.  Jira manages issues, to-dos, tasks and bugs, so it becomes a single place to manage all of these things.  Lastly, if you or your N-person company expands, Jira is scalable, though I doubt that is going to be a consideration for many people.

Why Postgresql?  Why not?  I’m not so keen on MySQL these days, especially with the change of ownership.  However ‘YMMV’, as the saying goes.

Installation

Let’s start.  For simplicity set all usernames and passwords when prompted to ‘admin’ and ‘admin’.  Disclaimer:  since the aim of this is to run it on your desktop PC on your home network, I haven’t made any security considerations during these instructions.

  • Download and install latest postgresql.  Accept all default settings.
  • Download and install Jira.  Accept all default settings.
  • Jira should probably start after it has installed, again, accept all default settings.  These will be discarded once you connect to the Postgresql database:  Jira initially runs against an in-memory database for evaluation purposes after installation.  When finished, stop it (via the start menu entry).
  • Go to here:  http://confluence.atlassian.com/display/JIRA/Connecting+JIRA+to+PostgreSQL to read up on how to integrate with Postgresql, or just continue with the following instructions:
  • Start pgadmin.  Then Tools->Connect (your password should be ‘admin’).
  • Create a login role called’ jirauser’.

  • Create a database in Databases called ‘jiradb’ with default Encoding UTF-8, and owner jirauser.
  • Modify permissions on C:\Program Files\Atlassian to allow users (or the the user you run Jira as), to give ‘modify’ permissions to all files and folders.
  • Now run AS ADMINISTRATOR (by right clicking on it in explorer, for example):  C:\Program Files\Atlassian\JIRA 4.1.2\bin\config.bat.
  • Set your postgresql settings from earlier, save the settings and close the config application.
  • Restart Jira, and follow the config wizard.
  • Jira should now be working.

Integration with Subversion

The details are here:  http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-bugtracker.html

Simply put, go to the trunk of your repository and add the ‘bugtraq’ property.  Then using TortoiseSVN to view logs allows you to click on a log message and go directly to your issue.  For a project in jira called ‘TEST’ the following properties *should* work:

bugtraq:append = false
bugtraq:label = Jira Issue {PREFIX}-
bugtraq:logregex = TEST-(\d+)
bugtraq:message = TEST-%BUGID%
bugtraq:number = true
bugtraq:url = http://localhost:8080/browse/TEST-%BUGID%

The only other thing to do, which is a little more lengthy, is to put a web server on top of your repository (such as viewvc) and connect that to Jira.   Download the Subversion Jira plugin from here, then restart Jira, go to administration, plugins, and set the ‘linkformat’ properties to point to your viewvc instance.

You will now have ‘two-way’ connectivity between your bug tracker (Jira) and your VCS (Subversion).

More Mercurial – Remote Repositories

I’ve spent some more time tinkering with Mercurial, and essentially wanted the master repository to behave a bit more like Subversion. I know this is a Bad Thing, but I want to be able to effectively commit, i.e. push, my changes back to the master repository without having to manually update it and commit it. The answer is rather simple but does seem to be that well publicised, probably because either everyone knows how to do this (e.g. hosted services), or no-one does this.

The solution is simply to add some hooks to your Mercurial set up as described here and here.

To summarise:

To act on changesets of a push/pull/unbundle, put this in .hg/hgrc:

[hooks]
changegroup = hg update >&2

This goes in .hg/hgrc on the remote repository. Output has to be redirected to stderr (or /dev/null), because stdout is used for the data stream.

Less is more

As I’ve spent much of my career using Visual Studio and its various incarnations, I’ve become quite used to using all the keyboard shortcuts to reduce the time I spend using the mouse.

As result of keyboard shortcuts, there are a lot of menu bars and windows on the screen that I just don’t need.  The image in this post is of Internet Explorer.  Web browsers have suffered from this problem for a long time as well:  if you look at the image, you will see that almost a third of the image is taken up by search bars and menus that are practically unused.

The same is true in Visual Studio.  The default settings are to give you just about every window possible (Output, Solution Explorer, etc.), in addition to lots of menu bars:  ‘Edit’ – is there a developer out there that doesn’t know Ctrl+C, Ctrl+V, Ctrl+X, Ctrl+Y, Ctrl+Z?  The amount of area for writing code seems to be 50% or less of the IDE window.

My settings are now:

  • No menu bars except for a custom one that changes build configuration (release/debug), and has ‘build’ and ‘rebuild’ solution.
  • One docked vertical window that contains the ‘Solution Explorer’.
  • One minimized docked horizontal window with tabs for Output and Find.
  • And one large window for editing code, as nature intended.

It isn’t just Visual Studio that suffers from this, take a look at Eclipse:

Once again, the code editor takes up about 50% of the available space.

There are benefits and drawbacks to increasing your editor size.  The drawbacks are that, perhaps, some of the windows and menu bars you are doing without, you need more than you realise. With more screen real estate for your editor you can view more of your code with less scrolling.  The other choice is that you can now increase the font size, making the coding easier on the eye (quite literally less strain whilst looking at your monitor).

On Auto-Updates

Despite my best googling efforts, I’ve yet to find any posting on designing an auto-update feature for my code, so in the traditions of NIH, I rolled my own.  It seems, ultimately, that the simplest solution is, well, the simplest solution.

Since I work on Windows, it is easy to get the current application’s name and version (provided you have set it and maintain it) from the resource file, either in .NET or Win32. So straight away you have your application name, and your current application version.   The next thing is to store the new version away somewhere. Going back to my comment about the simplest solution, parsing HTML is, to say the least, difficult. Putting updates on the web demand a web page, and hence HTML.

HTML can be tackled in a variety of ways, the worst of which is probably a regular expression, up to using something like http://htmlagilitypack.codeplex.com/. Either way, in HTML, you end up with a solution not dissimilar to:

<span class='name'> My App </span>
<span class='version'> My Version </span>

and parsing it relies on you trusting whoever edits the HTML to preserve the tags, classes and/or ids.

So back once again to ‘simple’. My solution is this: a text file containing comma separated values. Why? It is easy, it is human readable, and it is pretty near impossible to get wrong. When scanning it, you can just skip everything in there except your application information. It could contain a header, plus the information:

Name,Version,Installer
My App, 1.0, http://localhost/my_installer_1.0.msi

At this point someone reading this (yes, you!) will say: “but what about the web page?” Well, that is now fairly trivial with modern Javascript libraries. A little bit of jquery, and a little bit more, and you’re most of the way there. Making the installer a hyperlink is left as an exercise. Or you could simply then just maintain a static HTML page to go with the text file.

For C#, the code to get the file is remarkably trivial. For a blocking single-threaded web request:

System.Net.WebClient webClient = new System.Net.WebClient();
//  blocking...
webClient.DownloadFile(new System.Uri("http://localhost/updates.csv"), @"C:\updates.csv"));

Put this into the appropriate try catch block, and download to a file of your choosing.

On Version Naming.

What’s the difference between version 3.2 and version 3.12? For one thing, you might think 3.12 is later than version 3.2, but you would be wrong. A naive implementation of an auto-update system that checks versions would do this:

if (new_version > old_version) {  run_installer(); }

Except for two things:

1. You might have chosen new_version and old_version to be doubles. Then 3.2 is actually 3.20 which IS greater than 3.12 and your installer never gets run.

2. You might have been smarter and chosen new_version and old_version to be strings, so you could have 3.2a and 3.12b, but you would still be in trouble because a string comparison compares characters at a time, and once it gets to the ’1′ in 3.12, and the ’2′ in 3.2, it once again decides that 3.2 is greater that 3.12, and once again your installer doesn’t start.

So your run_installer clause ends up being:

if (new_version != old_version) { run_installer(); }

which has the side effect of allowing rollbacks to prior versions if you so choose (assuming of course that the MSI installers don’t prevent you from doing that).