MZ-Tools Articles Series: PRB: Window.Close doesn’t save changes if requested for .sql files in non-database projects

My new article is to document a bug that a customer of my MZ-Tools add-in reported some days ago, and that is caused by a bug (or problem) in the automation model (EnvDTE). It happens in the following scenario:

  • Using the latest versions of Visual Studio (it doesn’t happen with old versions such as VS 2005, 2008)
  • You add a .sql file to a project that doesn’t support .sql files, for example to a C# project. The problem doesn’t happen with projects that support .sql files such as database projects.
  • If you open the project item to get its (invisible) window, get its text document, modify it and close the window saving the changes, the changes are not persisted to disk.

You have the details and code to reproduce the problem here:

PRB: Window.Close doesn’t save changes if requested for .sql files in non-database projects
http://www.mztools.com/articles/2014/MZ2014027.aspx

I am not sure if this is a bug or not, because the project doesn’t support .sql files. There is an easy workaround, though. You can call:

window.Document.Save(“”);
window.Close(EnvDTE.vsSaveChanges.vsSaveChangesNo);

instead of:

window.Close(EnvDTE.vsSaveChanges.vsSaveChangesYes);

New templates sections

Sayed Ibrahim tweeted me about TemplateBuilder (a NuGet package which can be used to easily create item and project templates for Visual Studio) and SideWaffle Template Pack (a Visual Studio extension that provides “The ultimate web developer template pack”) so I have added new sections for templates with download URLs and videos:

Download > Templates
http://www.visualstudioextensibility.com/downloads/templates/

Videos > Templates
http://www.visualstudioextensibility.com/videos/templates/

MZ-Tools Articles Series: BUG: TextChanges CommandFlag not honored for toolbars in Visual Studio packages

In my MZ-Tools package I use dynamic localization to avoid the official way to localize .vsct files. So, I use the TextChanges CommandFlag for UI items and I set the text at run-time using the BeforeQueryStatus event handler. While this works fine for most UI items, alas, it doesn’t work for toolbars. I have documented it here:

BUG: TextChanges CommandFlag not honored for toolbars in Visual Studio packages
http://www.mztools.com/articles/2014/MZ2014026.aspx

and this is the Microsoft Connect bug report:

“TextChanges” CommandFlag not honored for toolbars in Visual Studio packages (VS SDK)
https://connect.microsoft.com/VisualStudio/feedbackdetail/view/966908

MZ-Tools Articles Series: HOWTO: Pass parameters programmatically to a command from a Visual Studio add-in

A question in the VSX forum has intrigued me enough to test a creative solution: to intercept a command execution to re-execute it with an input parameter that you can retrieve when the execution finishes. This can be useful in a scenario where a command can be executed asynchronously twice and you want to know which/when each execution is finished:

HOWTO: Pass parameters programmatically to a command from a Visual Studio add-in
http://www.mztools.com/articles/2014/MZ2014025.aspx

Issues with command names in Visual Studio packages

When creating a Visual Studio add-in, you had full control of the full name of its commands (command prefix + command short name, such as “MyAddIn.MyCommand”), as I explained in the article HOWTO: Create command names without ‘.Connect’ in Visual Studio add-ins. So, when I created my MZ-Tools add-in for Visual Studio, each version used a command prefix such as “MZTools6” or “MZTools7”, and I could provide that information to the end user to customize the keyboard shortcuts, for example:

keyboardshortcuts

Another nice consequence was that, given a Visual Studio version, two versions of the add-in (for example one purchased, next one evaluating) could be loaded at the same time without collisions of add-in command full names, because each one used a different command prefix.

With packages, you lack the control over the command prefix, as I explained in INFO: How a Visual Studio package command is named. So, the commands of a package cannot be named “MyPackage.MyCommand”. And it is perfectly possible that two packages (or two versions of the same package loaded side by side) create two commands with the same full name as in this example:

TwoCommands

This is possible because Visual Studio commands (as everything else in Visual Studio) are identified by Guids and Ids and not by names (the EnvDTE.Command interface exposes those two properties).

Therefore, given that a collision of command full names is not really a collision internally in Visual Studio (only in the user interface level), so far so good. But if your add-in assumes that its commands have unique full names (because the command prefix is unique for add-ins) and uses code like this:

EnvDTE.Command command = dte.Commands.Item("MyAddIn.MyCommand");

that will cause problems when migrating to a package:

EnvDTE.Command command = dte.Commands.Item("Tools.MyCommand");

You see, the command full name now uses “Tools” (for example) instead of “MyAddIn”. If you have two versions of your package loaded side by side, that call can return the command of the wrong package version. A similar problem to getting the correct CommandBar as explained in HOWTO: Get a CommandBar by Guid and Id rather than by name from a Visual Studio add-in.

The same can happen if you execute a command by name:

dte.ExecuteCommand("Tools.MyCommand");

The solution is to stop using command full names in the code to identify commands, and to use the command Guid / Id instead:

In my MZ-Tools extension I use a lot of command stuff, so I have to review/change several areas of the product as part of the migration to a package. Also, the user can create commands for each code template of the Code Library feature (notice the optional Command Name field):

codelibrary

In the code of the add-in, that is done using the EnvDTE80.Commands2.AddNamedCommand2 method. Although you can use automation (EnvDTE) from a package, you can’t use that method because its first parameter is of the type EnvDTE.AddIn. I guess that a package must use the AddNamedCommand methods of the IVsProfferCommands interface. I will post and provide a sample once I try it.

MZ-Tools Articles Series: HOWTO: Get solution events from a Visual Studio package

Continuing with the series of articles to show how to do things in a native way in a Visual Studio package instead of using the automation model (EnvDTE), in this new article I show how to get the solution events using the IVsSolutionEvents interface. As I expected, it is more difficult than using the automation model, with more code, and even requires you to use a cookie!:

HOWTO: Get solution events from a Visual Studio package
http://www.mztools.com/articles/2014/MZ2014024.aspx

The MSDN documentation broken links to “PAVE Visual Studio Extension Deployment”

MSDN documentation about VSX has improved a lot in the past years and now you have HOWTO examples, walkthroughs, etc. However, it seems to me that it still needs improvement in some areas such as navigation and attention to the details. For example, if you read the topics on VSIX deployment, you will find links to a subject “PAVE Visual Studio Extension Deployment.”:

PAVE

Apart that nobody knows what “PAVE” means, it happens that the links are broken and you get “We’re sorry—the topic that you requested is no longer available.”:

PAVEBroken

However, if you select Visual Studio 2010 in the Other Versions dropdown you get the content:

PAVEVS2010

And the lack of attention or care that I mentioned: this was reported months ago and nobody has fixed it:

PAVECommunityAddition