MZ-Tools Articles Series: HOWTO: Get the solution configurations / platforms from a Visual Studio add-in

Long time ago I wrote about the convoluted build configuration automation model (EnvDTE/EnvDTE80) and its diagram. Since questions about this keep appearing in the MSDN VSX Forum, I am going to write some articles about how to get/modify/add solution/project configurations/platforms. 

The first one is about how to get the information of the Configuration Manager from a Visual  Studio add-in:

HOWTO: Get the solution configurations / platforms from a Visual Studio add-in
http://www.mztools.com/articles/2013/MZ2013005.aspx

Book review: The Art of Unit Testing, 2nd edition (Roy Osherove)

After buying and reading the book Dependency Injection in .NET (Mark Seemann), I was about to buy The Art of Unit Testing (Roy Osherove), when I learned that the second edition will be available in a couple of months. I contacted Roy and Manning Publications Co were kind enough of providing me a complimentary copy of the Early Access Edition of The Art of Unit Testing, Second Edition, which I have read avidly in the last few days.

I was interested in the book because while I had worked with automated testing for the version 7.0 of my MZ-Tools add-in, I was not sure if I was doing it properly and I wanted to learn about integration testing / unit testing, the difference between fakes, mocks and stubs and the best practices. After reading the book, there is no doubt that Roy knows the stuff, and explains everything to make it clear:

– Part 1 explains the basics of unit testing and a first unit test.

– Part 2 explains the three kinds of testing: result testing, state testing and interaction testing, and how stubs are used for result / state testing and mocks are used for interaction testing. The last chapter of this part (and the first chapter of the next part) explains isolation (mocking) frameworks (as well as appendix B). It seems that not all isolation frameworks are created equal (constrained vs unconstrained) and the book explains quite well how they differ.

– Part 3 has one chapter to dig deeper into isolation frameworks and two chapters that I was very interested in: test hierarchies/organization and the pillars of good unit tests. The book puts an enormous effort in the importance of writing tests that are 1) Trustworthy 2) Maintainable and 3) Readable, and I couldn’t agree more because I have written tests that don’t follow those principles… this part of the book provides tons of good practices to the point of almost reaching perfectionism.

– Part 4 has two chapters: one devoted to integrating unit testing into the organization and other to working with legacy code (lacking unit testing). It is sad that books have to have such chapters because many developers and managers don’t see the value of automated testing, thinking only about the short term costs and not about the QA in the long term. But since this is the reality, this part can help you a lot in that case.

I have enjoyed the book a lot. It seems that as part of his consulting job, Roy has seen tons of bad
practices (as any team leader has seen with any kind of code, sadly) and this edition is a new attempt to explain developers how to become artists of unit testing. If they fail, it won’t be because of this excellent book.

Book review: Dependency Injection in .NET (Mark Seemann)

After hearing about Microsoft Unity from the .NET architects at my current company (my daily job), I bought the book Dependency Injection in .NET, by Mark Seemann some weeks ago to learn dependency injection and Inversion of Control (IoC) containers, just for curiosity because I thought it wouldn’t apply to my MZ-Tools add-in, or to Visual Studio extensions. I couldn’t be more wrong. I think this is the book that more profoundly has changed my mindset about creating software , because the concepts of programming against interfaces and loose coupling (explained in part 1 of the book) are one of the most important things that you need to master as a developer to create maintainable software, as now I have realized. Dependency Injection (DI) is the means to achieve loose coupling. The second part of the book explains DI patterns, anti-patterns and refactorings. The third part explains the three dimensions of DI: object composition, object lifetime and interception. The fourth part explains several DI containers of the many ones available for .NET. As the book explains, DI containers are optional, but even if you don’t use them, the software will benefit a lot from a loose coupled design.

How does this relate to developing Visual Studio add-ins? After reading the book I have realized that in my case in at least three aspects, and I wish I had read the book before:

1) Visual Studio add-ins hold a tight coupling with some dependencies such as the EnvDTE.dll, EnvDTE80.dll and VSLangProj.dll assemblies, that provide the automation model for add-ins. In all likelihood, all the features of your add-in depend on EnvDTE.Solution, EnvDTE.Project, EnvDTE.EditPoint, etc. Imagine now that you have to migrate your add-in to a Visual Studio package (SDK), because Microsoft plans to remove add-ins. It would be much easier if the features of your add-in would depend only on interfaces such as ISolution, IProject, IEditPoint that are implemented by classes that encapsulate the automation model for add-ins (EnvDTE.Solution, EnvDTE.Project), and later by classes that encapsulate the SDK services of packages (IVsSolution, IVsProject).

2) A loose coupled design and dependency injection allows to use unit testing more easily. Automated testing for add-ins is hard. So far I had done integration testing (with my own test runner), which while it is automated, it is slow and can’t be integrated easily with continuous integration (CI). Now I want to use unit testing too (because of the fast speed) through stubs, but since I haven’t used dependency injection I am finding problems to achieve a clean approach.

3) MZ-Tools 8.0 will support Visual Studio, VB6 and VBA as hosts. I am encapsulating the very different automation models with concrete classes such as SolutionEx, ProjectEx, etc. using partial classes and conditional compilation. But after reading the book I have realized that it would be better to use either interfaces or abstract classes.

I will try to find time to write a series of posts with code about using loose coupled design and dependency injection developing add-ins for Microsoft IDEs. Stay tuned.

Microsoft “expecting to remove add-ins from Visual Studio in a future version”. Will they be in Visual Studio 2013 announced today?

According to the answers to my last two bugs reported yesterday about add-ins on Microsoft Connect:

“Addins are an old technology that we are advising customers to move away
from. We expect to remove this from the product in a future version.”

Macros were gone in Visual Studio 2012, and it seems that add-ins will be gone in “a future version”. Coincidentally, Visual Studio 2013 has been announced today (you can read the announcement in Brian Harry’s blog and Somasegar’s blog). Now the intriguing question is for those of us with a heavy investment in add-ins such as MZ-Tools is: will VS 2013 support add-ins or will we be forced to migrate to packages (SDK)?

MZ-Tools Articles Series: BUG: Error ocurred in add-in wizard if add-in project created inside solution folder

Don’t you like when you find two bugs in a row? Apart from this other bug, I also found this one using the add-in wizard of Visual Studio, and again the curious part is that it worked in Visual Studio 2005, but was broken in Visual Studio 2008 and the bug persists.

I have reported to Microsoft Connect:

Error occurred in add-in wizard if add-in project created inside solution folder:
https://connect.microsoft.com/VisualStudio/feedback/details/789324/error-ocurred-in-add-in-wizard-if-add-in-project-created-inside-solution-folder

and I have documented in the MZ-Tools Series articles:

BUG: Error occurred in add-in wizard if add-in project created inside solution folder:
http://www.mztools.com/articles/2013/MZ2013004.aspx

MZ-Tools Articles Series: BUG: Checkbox to create CommandBar disabled in add-in wizard if name contains ‘.’

I have created tons of add-ins in the last years using the add-in wizard of Visual Studio, and the other day I wanted to use a project name with a ‘.’ dot character in the name. I noticed this bug that I have reported to Microsoft Connect:

Checkbox to create CommandBar disabled in add-in wizard if name contains “.”
https://connect.microsoft.com/VisualStudio/feedback/details/789323/checkbox-to-create-commandbar-disabled-in-add-in-wizard-if-name-contains

and I have documented in the MZ-Tools Series articles:

BUG: Checkbox to create CommandBar disabled in add-in wizard if name contains ‘.’
http://www.mztools.com/articles/2013/MZ2013003.aspx

The curious part is that it worked in Visual Studio 2005, but was broken in Visual Studio 2008 and the bug persists.

MZ-Tools Articles Series: HOWTO: Get the full browse URL of an .aspx page

I wrote some years ago HOWTO: Open the Web Browser and navigate to a page from a Visual Studio add-in or macro (http://www.mztools.com/articles/2008/MZ2008012.aspx). The other day someone asked in the MSDN VSX forum how to show an .aspx page in the browser programmatically, which is easy if you can get the full browse URL of the .aspx page. It happens that the ProjectItem class of Web Site projects and Web Application projects has different ways of getting / composing the browse URL, so I have written an article with sample code about this:

HOWTO: Get the full browse URL of an .aspx page
http://www.mztools.com/articles/2013/MZ2013002.aspx

Debugging .NET Framework working only “sometimes”

I am these days (well, nights) debugging an extremely difficult issue with the ImageList control and I had that idea that debugging the .NET Framework (source step) would help a lot. That feature was introduced in VS 2008 and my feeling these years when I tested it from time to time was that sometimes it worked, sometimes it didn’t. Yesterday that I needed it badly I searched the web and I discovered that I was not alone. There are tons of issues and workarounds about it. I tried all them to no avail.

Finally someone from Microsoft posted here (only a few weeks ago after all these years!) that the root cause is out-of-date PDBs, and that it is going to happen each time that Microsoft releases a new build of an assembly, which is not only in service packs but also any security patch. Since there is cadence between the release of the assembly and the release of the PDB (that has been up to 1 year in the past!), this feature is basically broken, bad designed.

The alternative, suggested strongly by that guy, is to use .NET Reflector, a paid tool which for developers of Visual Studio extensions is even more useful to debug Visual Studio assemblies (not just .NET Framework assemblies) as I explained in this guest post on their blog.

Msaddndr.dll file officially not installed by Microsoft Office 2013

As I posted back in November, the setup of an add-in for the VBA editor of Office 2013 written with VB6 could fail with the following error:

“Unable to register DLL/OCX:RegSvr32 failed with exit code 0x5”

I mentioned that the cause was that the file Msaddndr.dll is no longer installed by Office 2013 and today I have found that Microsoft wrote an official Knowledge Base (KB) article stating it a month later:

A custom add-in that uses interfaces in the Msaddndr.dll file does not work in Office 2013
http://support.microsoft.com/kb/2792179

The workaround is, of course, that your setup installs that file. BTW, I got yesterday a bug report from a user of my MZ-Tools 3.0 for VBA with that same error but using a MZTools3VBASetup.exe that already (supposedly) installed the file. It happened that the system already had that file installed, but an old version, and the setup only installed it if not present, so it was not replaced by the newest version. So, when applying this workaround, ensure that your setup installs the file if not present, or if it is an older version, because it seems that there are at least two versions of Msaddndr.dll out there.

Windows PowerShell scripts to register a .NET-based add-in for a COM-based host application

Before Visual Studio 2005 introduced XML-based registration for add-ins with an .AddIn file (which enabled X-Copy deployment), add-ins for Microsoft applications required two steps to be registered:

  • To register the add-in dll as ActiveX (COM) component
  • To register the add-in dll as add-in for the host application through some registry entries

This is still true for COM-based add-ins for Visual Studio (any version) and for other hosts such as Microsoft Office or its VBA editor which only support COM-based add-ins.

Some months ago I wrote how to create a COM add-in for the VBA editor of Office using .NET, which is almost the only way to create an add-in for the VBA editor of Office 64-bit, since it doesn’t support 32-bit COM add-ins.

I am working since some months ago on a .NET-based version of my MZ-Tools add-in for the VBA editor of Office 32/64-bit and I always wanted a single script to perform the two steps above. This was a nice excuse to learn Windows PowerShell, so I bought a book and after reading some chapters to get the concepts today I decided to create the scripts that call regasm.exe to register the .Net assembly for COM-Interop and create the registry entries for the add-in to be recognized by the VBA editor:

1) This is the content of a file named Functions.ps1 which contains reusable functions:

# To run .ps1 scripts you need to execute first: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Regasm32 = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm.exe'
$Regasm64 = 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe'

function Register-Assembly32([string]$Assembly, [string]$RegistryKey, [string]$FriendlyName)
{
   Execute-Command -RegAsm $Regasm32  -Arguments '/codebase' -Assembly $Assembly
   Register-AddIn -RegistryKey $RegistryKey -FriendlyName $FriendlyName
}

function Register-Assembly64([string]$Assembly, [string]$RegistryKey, [string]$FriendlyName)
{
   Execute-Command -RegAsm $Regasm64 -Arguments '/codebase' -Assembly $Assembly
   Register-AddIn -RegistryKey $RegistryKey -FriendlyName $FriendlyName
}

function Unregister-Assembly32([string]$Assembly, [string]$RegistryKey)
{
   Execute-Command -RegAsm $Regasm32 -Arguments '/unregister' -Assembly $Assembly
   Unregister-AddIn -RegistryKey $RegistryKey
}

function Unregister-Assembly64([string]$Assembly, [string]$RegistryKey)
{
   Execute-Command -RegAsm $RegAsm64 -Arguments '/unregister' -Assembly $Assembly
   Unregister-AddIn -RegistryKey $RegistryKey
}

function Register-AddIn([string]$RegistryKey, [string]$FriendlyName)
{
   New-Item         -Path $RegistryKey -Force
   New-ItemProperty -Path $RegistryKey -Name Description  -PropertyType String -Value $FriendlyName
   New-ItemProperty -Path $RegistryKey -Name FriendlyName -PropertyType String -Value $FriendlyName
   New-ItemProperty -Path $RegistryKey -Name LoadBehavior -PropertyType DWord  -Value 3
}

function Unregister-AddIn([string]$RegistryKey)
{
   if (Test-Path -Path $RegistryKey)
   {
      Remove-Item -Path $RegistryKey
   }
}

function Execute-Command([string]$RegAsm, [string]$Arguments, [string]$Assembly)
{
   $psi = New-Object System.Diagnostics.ProcessStartInfo
   $psi.CreateNoWindow = $true
   $psi.UseShellExecute = $false
   $psi.RedirectStandardOutput = $true
   $psi.RedirectStandardError = $true
   $psi.FileName = $RegAsm
   $psi.Arguments = $Arguments + ' ' + $Assembly
   $process = New-Object System.Diagnostics.Process
   $process.StartInfo = $psi
   [void]$process.Start()
   $StandardOutput = $process.StandardOutput.ReadToEnd()
   $StandardError = $process.StandardError.ReadToEnd()
   $process.WaitForExit()
   [system.windows.forms.messagebox]::show($StandardOutput + $StandardError)
}

2) Then I have other scripts that include that script:

MyAddInVBA32Registration.ps1:

$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path
. (Join-Path $ScriptDirectory Functions.ps1)

$Assembly = (get-item Env:USERPROFILE).Value + 'Documents\MyAddIn\Exe\Debug\MyAddIn.dll'

Register-Assembly32 -Assembly $Assembly -RegistryKey 'HKCU:Software\Microsoft\VBA\VBE\6.0\AddIns\MyAddIn.Connect' -FriendlyName 'My Add-In'

MyAddInVBA64Registration.ps1:

$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path
. (Join-Path $ScriptDirectory Functions.ps1)

$Assembly = (get-item Env:USERP2ROFILE).Value + 'Documents\MyAddIn\Exe\Debug\MyAddIn.dll'

Register-Assembly64 -Assembly $Assembly -RegistryKey 'HKCU:Software\Microsoft\VBA\VBE\6.0\AddIns64\MyAddIn.Connect' -FriendlyName 'My Add-In'

MyAddInVBA32Unregistration.ps1:

$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path
. (Join-Path $ScriptDirectory Functions.ps1)

$Assembly = (get-item Env:USERPROFILE).Value + 'Documents\MyAddIn\Exe\Debug\MyAddIn.dll'

Unregister-Assembly32 -Assembly $Assembly -RegistryKey 'HKCU:Software\Microsoft\VBA\VBE\6.0\AddIns\MyAddIn.Connect'

MyAddInVBA64Unregistration.ps1:

$ScriptDirectory = Split-Path $MyInvocation.MyCommand.Path
. (Join-Path $ScriptDirectory Functions.ps1)

$Assembly = (get-item Env:USERPROFILE).Value + 'Documents\MyAddIn\Exe\Debug\MyAddIn.dll'

Unregister-Assembly64 -Assembly $Assembly -RegistryKey 'HKCU:Software\Microsoft\VBA\VBE\6.0\AddIns64\MyAddIn.Connect'

To run the scripts you need to enable PowerShell execution first and they need to be run with admin rights.

I am finding PowerShell with a learning curve harder than expected and with some “by-design” issues that makes it “tricky” in my opinion, but I hope to learn it in depth.

VS SDK, packages, add-ins, macros and more…