Category: VSIP
31/01/06
Be careful when installing VS add-ins in localized Windows versions
When installing add-ins for Visual Studio, a number of different paths can be used. One of them is C:\Documents and Settings\All Users\Application Data\Microsoft\MSEnvShared\Addins - in a default installation of a US English Windows. Obviously a proper installer would use Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) to make sure the path is correct for the current system and for the current language. For example, for a German system the result would be C:\Dokumente und Einstellungen\Alle Benutzer\Anwendungsdaten\Microsoft\MSEnvShared\Addins.
Now, the funny thing is that a part of the path is stored by Visual Studio verbatim. To be precise, VS stores the path as %ALLUSERSPROFILE%\Application Data\Microsoft\MSEnvShared\Addins, as you can see in VS using Tools/Options/Add-in/Macros Security.

Obviously they forgot that the Application Data part wouldn't be called that in a localized version of Windows. So if you want to install your add-in into that path, you should make sure you fiddle around with it to create a mixed-language version, which fits the template used in the VS settings.
04/09/05
Accessing project properties from a VS macro
I saw this question on a newsgroup: How do you access the properties of a project via the EnvDTE VS extensibility interface? It's really quite simple, like in this code:
Sub AccessProject()
Dim proj As Project
proj = DTE.Solution.Projects.Item(1)
Dim prop As [Property]
For Each prop In proj.Properties
Debug.Print("Project property " & prop.Name & " = " & prop.Value)
Next
Dim projItem As ProjectItem
For Each projItem In proj.ProjectItems
Debug.Print("Project item " & projItem.Name)
Next
End Sub
This will simply print out all the project properties and items it finds. The sample accesses only the first entry in the solution's Projects list - you can directly access other specific members in a similar way, of course, and it's also possible to find the currently active project(s) via the DTE.ActiveSolutionProjects:
Dim projects as System.Array = DTE.ActiveSolutionProjects Dim proj as Project For Each proj In projects Debug.Print(proj.Name) Next
03/09/05
VSIP 2005: Tracking the active VS window
In a VSPackage using the Managed Package Framework (MPF), how do you track the active editor pane in VS?
To start with, I create a new VSPackage project (New project -> Other project types -> Extensibility -> Visual Studio Integration Package) and have the wizard create a C# based project with a tool window for me. From the standard button click (to keep things under control easily), I run the following initialization code:
DTE dte = (DTE) GetService(typeof(DTE));
Window outputWindow = (Window) dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
outputWindow.Visible = true;
outputPane = ((OutputWindow) outputWindow.Object).OutputWindowPanes.Add("Active window tracking");
outputPane.Activate( );
IVsMonitorSelection monitorSelection = (IVsMonitorSelection) GetService(typeof(SVsShellMonitorSelection));
monitorSelection.AdviseSelectionEvents(this, out myCookie);
Two different things are being done here:
- An output pane is installed into the VS output window, titled Active window tracking, that I can use throughout my package to output debug information. The output pane is stored in a field of type
OutputWindowPane, to be used later. - The last two lines query the
IVsMonitorSelectionservice from the VS shell, and install my class as an event receiver for event pertaining to selections. A selection in VS can be for any type of object that the IDE deals with, so windows are one such type. The cookie that's returned by the call toAdviseSelectionEventsisn't important for us, it's stored away in a field ofuinttype.
Now the class has to implement the interface IVsSelectionEvents to be able to receive notifications about selections. The three methods of the interface are implemented here:
int IVsSelectionEvents.OnElementValueChanged(uint elementid, object varValueOld, object varValueNew) {
if (elementid == (uint) VSConstants.VSSELELEMID.SEID_WindowFrame) {
string oldCaption = GetWindowFrameCaption((IVsWindowFrame) varValueOld);
string newCaption = GetWindowFrameCaption((IVsWindowFrame) varValueNew);
LogWindowChange(oldCaption, newCaption);
}
return VSConstants.S_OK;
}
int IVsSelectionEvents.OnSelectionChanged(IVsHierarchy pHierOld, uint itemidOld, IVsMultiItemSelect
pMISOld, ISelectionContainer pSCOld, IVsHierarchy pHierNew, uint itemidNew, IVsMultiItemSelect
pMISNew, ISelectionContainer pSCNew) {
return VSConstants.S_OK;
}
int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) {
return VSConstants.S_OK;
}
As you can see, the only method of interest to me is the OnElementValueChanged method, in which I evaluate the elementid to make sure that the given element is indeed a WindowFrame and I extract the window caption for demonstration purposes, which is then shown in the output window I installed in the beginning. Here are the missing helper functions:
void Log(string text ) {
if (outputPane != null)
outputPane.OutputString(text + Environment.NewLine);
}
void LogWindowChange(string oldCaption, string newCaption) {
Log("Focus changed from '" + oldCaption + "' to '" + newCaption + "'");
}
string GetWindowFrameCaption(IVsWindowFrame frame) {
object result = null;
if (frame != null)
frame.GetProperty((int) __VSFPROPID.VSFPROPID_Caption, out result);
return (string) result;
}
Have fun!
02/09/05
VSIP 2005: Managed VSPackages
VSIP 2005 has been available a while, but I hadn't found the time to look into it. Now I did and I must say I'm impressed, especially by the new managed classes in the Environment SDK. For example, it's now possible to create a custom editor for Visual Studio completely in C#, and creating a tool window in managed code is really a matter of a few lines. Great work, I'll have to have a much closer look at this managed stuff!


