Using GitHub Copilot to help write legacy code (a VSTO Plugin)

GitHub Copilot can be super helpful when writing or maintaining legacy code that a developer has little or no experience in. Example of creating a VSTO plugin

I've found GitHub Copilot (GHCP) to be really helpful in a whole load of situations. One recent customer request was around a VSTO plugin.

VSTO, or to give it's full name, Visual Studio Tools for Office is still heavily used to keep the Office plugin ecosystem going, but it's now very old, so skills are likely to be dwindling.

The Requirements

During an Outlook Plugin startup, I want it to go off and do some background processing (for example, to configure some LDAP mailboxes) but in a way that does not block the startup method. If the plugin's startup gets blocked, Outlook will automatically disable the plugin! That's not what we want! I also want it to popup a message that might give me more instructions or notify me that the background processing is complete.

Getting Ready

I'm going to be using GitHub Copilot Chat to build and outlook plugin. I'll be using Visual Studio 2022 (VS) , VSTO and VS is configured to allow creation of Office/SharePoint development. To do this, open the visual studio installer, modify your version and select the office/SharePoint choice like in this image;

Image shows a how to install the Office/Sharepoint Development feature in Visual Studio installer.

I will also need to GHCP Chat extension to be installed, which is available from the extensions dialogue in VS. (Note, GHCP Chat is part of GitHub Copilot, so most people will need a paid for license. There are some people that can get it for free, see here for more details).

Once I start VS, I will be creating a new project in C# of the type "Outlook VSTO plugin"

Choosing to create a new project of the type Outlook VSTO Add in

The Code

Out of the box, the VSTO addin solution just has two events in it;

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
    }

    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
        // Note: Outlook no longer raises this event. If you have code that 
        //    must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
    }

We are only interested in Startup. Lets start to chat to GHCP Chat!

I ask "i need to execute a non-blocking process during startup. How can I do this?" and GitHub Copilot chat responds.

I want to mimic a process that takes a while to complete.

I ask Github copilot "add some code to task.run that will loop for 5 seconds and then stop" and it responds with suitable code.

This is good, but VS is showing me there's an error (red underlined Task).

Image showing Task.Run is underlined in red showing an error.
Image showing Task.Run is underlined in red showing an error.
I ask why there is an error. Chat replied that I need to add System.Threading.Tasks using directive.
Image asks to create a popup message that will self close after 5 seconds

This is helpful, but notice the new code it's written removed the existing while loop. That's not what we want. I need to modify my prompt slightly;

Image asks copilot to modify the code it created to include the existing while loop it had already written, but forgot about when it was creating the new code.

This is amazing. If I now run the solution, Outlook will start and after 5 seconds the notification will be shown. I've included the bottom right of my screen so you can see where the placement is.

Images shows the solution running, and the notification window pops out in the notification area of windows.

Remembering that this is a Copilot and NOT an autopilot, I as the developer need to still be using my head as well. I can see in the code that both the notifyIcon and Timer objects have a dispose method. The code as it stands could have a memory leak if there was an exception during ShowPopupMessage. i ask Copilot how we can fix this (notice the spelling mistake in my question).

I ask copilot how I can guarantee that the Dispose methods will be called, or a memory leak will occur.

I think I may want to limit what is being passed in to the method, otherwise a user will be able to max out the popup window with text and show it for far too long.

I ask copilot to raise errors if the input parameters are too large.

Right, the code might need a bit of tweaking (such as not allowing blank strings or a short delay such as 1 second, but we can do that later). What we need now is some tests. Notice how it offers to insert the tests into a new file.

I ask copilot to create tests, which it does, and then offers to save them into a new file.

Interestingly, the "Insert in a new file" did create a new file, but not as part of the solution. I ask why.

I ask copilot why it did not create a file in the solution itself. It responds by saying it does not have access to the file system, but show instructions on how to fix it.

Ok, so now I have the tests in a new file as part of the solution. There are quite a few errors though, so instead of using GHCP Chat, I know myself these are missing references. After fixing most of the errors, there are still some errors because creating an Addin is more complex, and GHCP may not understand that.

I tell it that the test code cannot be written like that, and it needs to be modified. It responds by saying the method should be static

Ok so I modify the ShowPopupMessage to be a static, and ask GHCP Chat to modify the tests

I ask copilot to modify the tests now that the Show Popup Message method is static.

Did you see it advised that making the method static may not be such a good idea, and suggested alternatives.

Now to run the tests. Oh, it won't....

The tests won't run so I ask copilot why. It says I need to install the MsTest adapter via nuget package manager.

Amazing. So now I've added the MStest.Adaptor via NuGet package manager. Lets try again.

Image shows that all the test s now run successfully.

Amazing.

Just in the matter of a few questions I've fully built my VSTO addin, does exactly what I want, with working tests. It took more time to do the screenshots and write this blog than it did to converse with GHCP chat and create a fully working solution. How much time can GitHub Copilot Chat save you when coding legacy code that you may never have used before?

You can get this code from my repo at https://github.com/dombat/Background-Working-Startup-Toast

I created a video to go with this https://youtu.be/Y6MZctuUW-g