In the last eleven articles we went around the most important basic aspects for VSX development. I guess things treated there are enough to start VSPackage development and are good fundamentals to build later development on. I know there are also important topics not yet treated (e.g. Package Load Keys, deployment and installation issues, option pages, custom editors, project hierarchy, document windows, and many more).
I got feedbacks on articles and majority of them confirmed that it’s time to make further steps. Before going on, let me to parallel software development and diving...
Not just my “nickname” is DeepDiver. I am really a fan of undersea diving. Here in Hungary we have only lakes with very limited visibility. For novice divers it’s not a fun to dive in those lakes. If you are a beginner and you dive with a dive master knowing the lake even the visibility is low while you can follow him (or her) and you see what and how to do, you feel yourself comfortable. If you dive in a sea where the visibility is much better than in a lake, you feel yourself smart and “powerful” even without a dive master. However, when going back to a lake you can lose your self-confidence. Your way out from that situation is to learn and practice while you become (like) a dive master (or an instructor): this is a proof of your diving skills.

Right now I am a dive master. The way to this certification led through courses where we always practiced together with other candidates. We learnt many theoretical basics (physics, physiology), practical skills (routine tasks, self-rescuing, emergency procedures, etc). In diving we have a buddy-system: while diving buddies control and help each other. Now I feel comfortable in the cold lakes of Hungary as well as under the surface of the Red Sea. If you would ask which one I prefer I could tell that I like both for different reasons: Red Sea because of its spectacular world, Hungarian lakes because of their calmness and the challenge they mean.
Why am I telling this to you? I feel myself a dive master in .NET programming but a beginner in VSX development. However, I would like to be a master of both. To achieve this I know I have to learn and practice a lot: I guess it is much easier in buddy-system. So, if you think, be my “virtual” buddy on this way!
In this article I intend to make a step further. Instead of creating newer packages in every article I decided — feedbacks inspired me — create a new package to serve “How To” demonstration purposes and to add application samples of what we learn together. I want not simply adding samples but also refactor the code in order to create reusable managed code to make VSX development easier.
Creating the VsxLibrary and HowToPackage
In Part #10 I created a small class library called VsxToolset. That time I thought that it can be a good foundation for further development of a real toolset (or even a framework) for VSX development. I declared a few objectives on how to proceed:
Toolset types must reduce noise. I want to create types in order to make it much simpler accessing COM interop types behind the VS IDE and their methods. I would like to reduce the number of lines to be written, strengthen the type-safety, and using the power of managed code. A good example for this is the simplification of ActivityLog handling presented in Part #10.
Concepts should be turned into real types. The object model behind VS IDE is matured and proven. The implementation of this model uses COM technology that — since it has a bit different mindset — is not comfortable for .NET developers. I would like to use the concept behind the VS IDE services and types and turn into a .NET implementation where the features of the .NET type system and the C# (even 3.0) language can be used. A good example is OutputWindow and OutputWindowPane in Part #10.
Declarative approach where possible. There are many possibilities to use declarative programming style for those we use imperative approach in VS IDE. Attributes, reflection and the metadata-aware behavior of .NET provides as a set of techniques to turn imperative code into declarative code in many areas. An example of this is the OutputPaneDefinition type with the decorating attributes in Part #10.
Continuous documentation. I like frameworks that makes building my software easier and more efficient, however I hate when finding out how to use framework features fully consumes the time I expected to save. I want to avoid this situation, so I plan to do the following tasks in parallel with the toolset development:
Fully commented code to help understanding it.
Samples for all feature groups.
Publishing articles describing and explaining feature groups and their application in real tasks.
I started creating a (right now) small framework from the previous VsxTools class library and renamed it to VsxLibrary. Simultaneously I created the HowToPackage sample in order to have a package demonstrating the concepts of VSX I intend to treat in my future articles. To make the source code available I put it on the LearnVSXNow project site on CodePlex.
In this article I will give you a brief overview about VsxLibrary and HowToPackage.
Solution structure
When you download the source code, you have the following folder structure:
| Folder |
Content |
| PackageStartupSamples |
Home of the solution file (PackageStartupSamples.sln) for the samples in Part #2-#11. I shall not add new samples to this solution. I plan to update it if necessary (e.g. new VS SDK versions come out) and of course I fix bugs.
|
| DiveDeeper.VsxLibrary |
This folder is the home of the VsxLibrary (built from the former VsxTools). The solution contains only for the library itself and its unit tests.
|
| DiveDeeper.HowToPackage |
The HowToPackage is a VSPackage about to build for demonstration and tutorial purposes. The solution contains the package code with unit and integration test projects. I also added the VsxLibrary as a linked project to this solution.
|
Creating the initial code
I used the already well-known technique to create the HowToPackage: the VSPackage wizard. As an initial package, I created a simple menu command and a tool window. The wizard did not create types and constants with the names I really liked, so I renamed them using the refactoring functions of VS. I also removed the majority of comments the wizard added.
I created the VsxLibrary from scratch to define a new folder structure based on the service areas provided by the VS IDE. For example I moved the Output Window and Output Window panes related functionality into the OutputWindow folder, message box related functions into the VsUIShell folder (this service provides those functions).
An overview of the VsxLibrary
As I mentioned before VsxLibrary has been created from the previous VsxToolset class library. In the next articles I will continuously extend this library with new types, so I would like to give you an overview of the few types already in the library.
Utility types
VsxLibrary applies declarative style wherever it is possible and efficient. One key to declarations is the intensive use of attributes. I have created a few abstract types to help attribute creation. They are BoolAttribute, StringAttribute, Int32Attribute and UInt32Attribute. They encapsulate only one property called Value having the type as in the name of the attribute. For example, BoolAttribute is defined as follows:
public abstract class BoolAttribute: Attribute
{
private readonly bool _Value;
protected BoolAttribute(bool value)
{
_Value = value;
}
public bool Value
{
get { return _Value; }
}
}
All the other attribute types use this very simple pattern with the appropriate encapsulated type. As you now, generics cannot be used for System.Attribute derived types, so we have to repeat the same pattern for all bas attribute types.
With these base types we need only a few lines to declare attributes having exactly one property (and many attributes are this kind):
[AttributeUsage(AttributeTargets.Class)]
public sealed class PaneNameAttribute: StringAttribute
{
public PaneNameAttribute(string value) : base(value)
{
}
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class InitiallyVisibleAttribute: BoolAttribute
{
public InitiallyVisibleAttribute(bool value): base(value)
{
}
}
As VsxLibrary development goes on, other base attribute types will be created.
Another example of utility types is the VsxConverter static class. There are many constant values and enumerations having the same semantics with different implementation in the .NET Base Class Library and in the VSX shell interop libraries. One good example is the DialogResult enumeration in the System.Windows.Forms namespace that has the same meaning and the integer values 1 to 7 in functions representing return values from dialogs. Another example is the MessageBoxButtons enumeration for Windows forms applications. VS Shell has the OLEMSGBUTTON enumeration for the same purpose.
I guess it would be very comfortable for .NET developers to use only one well-know type instead of a few alternative types with the same meaning. I prefer using the types (enumerations, constants, etc.) I am familiar with from the base class library.
To make the transition easier, I created the VsxConverter static class dedicated to conversion methods between BCL types and VS Shell types. Now it has only a few methods (but soon will have much more) with really simple tasks, just as the following code extract illustrates:
public static OLEMSGBUTTON ConvertToOleMsgButton(MessageBoxButtons buttons)
{
switch (buttons)
{
case MessageBoxButtons.AbortRetryIgnore:
return OLEMSGBUTTON.OLEMSGBUTTON_ABORTRETRYIGNORE;
case MessageBoxButtons.OKCancel:
return OLEMSGBUTTON.OLEMSGBUTTON_OKCANCEL;
case MessageBoxButtons.RetryCancel:
return OLEMSGBUTTON.OLEMSGBUTTON_RETRYCANCEL;
case MessageBoxButtons.YesNo:
return OLEMSGBUTTON.OLEMSGBUTTON_YESNO;
case MessageBoxButtons.YesNoCancel:
return OLEMSGBUTTON.OLEMSGBUTTON_YESNOCANCEL;
default:
return OLEMSGBUTTON.OLEMSGBUTTON_OK;
}
}
I know during the development of VsxLibrary I will need many more utility types. As I identify them I will present them in the corresponding articles.
Wrapping around the SVsUIShell service
Another good example of why it worth to develop VsxLibrary is the SVsUIShell service providing a few dozen of methods. Some of them like FindToolWindow and CreateToolWindow have already been encapsulated in Managed Package Framework types (these methods can be accessed through the Package class).
When we created a package with a simple menu command (in Part #3), it also created code to display a message box:
IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
Guid clsid = Guid.Empty;
int result;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(
uiShell.ShowMessageBox(
0,
ref clsid,
"SimpleCommand",
string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()",
this.ToString()),
string.Empty,
0,
OLEMSGBUTTON.OLEMSGBUTTON_OK,
OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
OLEMSGICON.OLEMSGICON_INFO,
0, // false
out result));
This code is simple but tiring. I created a static wrapper class VsUIShell to make it simple. Displaying the message box with the same message is above is so simple (just like in Windows forms applications):
VsUIShell.ShowMessageBox(
string.Format(CultureInfo.CurrentCulture,
"Inside {0}.MenuItemCallback()", this),
"SimpleCommand);
The pattern I used to wrap the original ShowMessageBox method is quite simple. I created a private method inside the VsUIShell class to call to ShowMessageBox method with .NET BCL types instead of VS Shell related enumerations:
private static DialogResult ShowMessageBoxInternal(string title, string message,
string helpFile, uint helpTopic, MessageBoxButtons buttons,
MessageBoxDefaultButton defButton, MessageBoxIcon icon, bool sysAlert)
{
Guid clsid = Guid.Empty;
int result;
ErrorHandler.ThrowOnFailure(UIShell.ShowMessageBox(
0,
ref clsid,
title,
message,
helpFile,
helpTopic,
VsxConverter.ConvertToOleMsgButton(buttons),
VsxConverter.ConvertToOleMsgDefButton(defButton),
VsxConverter.ConvertToOleMsgIcon(icon),
sysAlert ? 1 : 0,
out result));
return VsxConverter.Win32ResultToDialogResult(result);
}
A created a few public method overloads for the ShowMessageBox to make is similar to the MessageBox.Show methods.
Where we are?
In this article I created a new sample solution called HowToPackage in order to use it for VSX demonstration purposes. Instead of creating a new VSPackage every time I want to describe a part of VSX or a feature of a service I plan to continuously extend this package. As I pointed in Part #9 and #10 using VSX can be made much easier by transforming it to a .NET-style using the features of CLR (like metadata, attributes, generics, etc.) and the C# language (like extension methods, LINQ, etc.). While working on the HowToPackage sample I also started to create a small framework called VsxLibrary.
In the next articles I will treat newer details of VSX.
Posted
Feb 12 2008, 06:47 PM
by
inovak