Visual Studio Extension: Get Package from adornment - c#

I'm developing a Visual Studio Extension, made up of:
A menu and series of commands
A tools window
One or more textview adornments
A custom implementation of AysncPackage
Now, while the Tools Window and the commands are either wired up by, or have a handle on, the AsyncPackage for my extension, what I cannot figure out is HOW I get a handle to the self-same AsyncPackage from one or more of my text adornments.
For example, my Tools Window extends ToolWindowPane, which has a hook to the Package via the Package's ProvideToolWindow attribute. My commands are constructed inside the Package itself, so passing a handle to the AsyncPackage is simple enough.
What I cannot work out is HOW you get a reference to this AsyncPackage inside any of my TextAdornments.
Any help?

This was a tricky one! You must get the IVsShell to retrieve a package based on a GUID you associate with your Package, and then cast it to your interface (or the base interface of IPackage)
private IMyPackageInterface _myPackage;
//let's get our hands on that package
var vsShell = (IVsShell) ServiceProvider.GlobalProvider.GetService(typeof(IVsShell));
if (vsShell == null)
{
throw new NullReferenceException();
}
if (vsShell.IsPackageLoaded(PackageGuid, out var myPossiblePackage)
== Microsoft.VisualStudio.VSConstants.S_OK) {
_myPackage = (IMyPackageInterface)myPossiblePackage;

Related

How to get "Include Paths" property of Microsoft Macro Assembler in Visual Studio by a plugin?

I'm workng to get include path resolved by some VS plugin (asm-dude in fact). Include path in microsoft macro assembler looks like this:
includepath
Include file resolve part in asm-dude lies in: https://github.com/HJLebbink/asm-dude/blob/vxix2022-B/VS/CSHARP/asm-dude-vsix/Tools/LabelGraph.cs#L602
Anyway, at the beginning I think I just need to get the value of IncludePath property, and then other things can be done in a minute. But after reading some docs I realized I'm in a mess. It seems that VS prevents me to get names of all properties, but I can only get the value by the name.
Codes I write are like:
DTE dte = Package.GetGlobalService(typeof(SDTE)) as DTE;
Projects projects = dte.Solution.Projects;
if (projects.Count != 0)
{
VCProject project = (VCProject)projects.Item(1).Object;
VCConfiguration cfg = project.ActiveConfiguration;
if (cfg != null)
{
string includePathStr = cfg.GetEvaluatedPropertyValue("IncludePaths");
}
}
but in vein, it gets include path of msvc, not MASM
I cast Project to VCProject because it's a VC project. Although I can iterate properties of a non-VCProject's configuration, but it doesn't seem to work on VCProject, because it doesn't have a (at least not public) member named properties. All these docs tell me that I can only get its value by name, but the problem is I don't know its name. Or I'm completely wrong? I must admit that I'm new to VS plugins.
refs I used so far:
https://learn.microsoft.com/en-us/previous-versions/dn655034(v=vs.140)?redirectedfrom=MSDN
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.vcprojectengine.vcconfiguration?view=visualstudiosdk-2022

Change VS option by using the Settings Store: finding the right CollectionPath?

I need to set the value of a Visual Studio option found in Visual Studio -> Tools -> Options -> Text Editor -> JavaScript/TypeScript -> EsLint but I can't seem to find the CollectionPath for this option.
GetSubCollectionNames("Text Editor"); yield a number of results, while GetSubCollectionNames("Text Editor\\JavaScript"); yield 0 results.
TL;DR
How would one go about finding the right CollectionPath for the option pictured in the image below?
This is what I'm using currently.
[ImportingConstructor]
internal VSOptions([Import] SVsServiceProvider serviceProvider)
{
var settingsManager = new ShellSettingsManager(serviceProvider);
_writableSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings)
?? throw new Exception(nameof(settingsManager));
var textEditorSubCollections = _writableSettingsStore.GetSubCollectionNames("Text Editor");
var javaScriptSubCollections = _writableSettingsStore.GetSubCollectionNames("Text Editor\\JavaScript");
// TODO: set option value when we have the right CollectionPath
}
The WritabelSettingsStore class used to extend Visual Studio common settings in Visual Studio. You could use GetPropertyNames("Text Editor\JavaScript") to list all writabel settings for JavaScript, where you will find not all Properties under JavaScript sub collections are listed.
The EsLint is not common Visual Studio Settings. It is third part tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.
So we could not change it directly with WritableSettingsStore class. You need to know how the EsLint added in Visual Studio and then modify its configuration file for Visual Studio.

VS SDK ContentType does not work

I am trying to include a custom language support for Visual Studio.
To start with, I need to have GoToDefinition support. And I am struggling to get the context menu to include this command.
I have defined a ContentTypeDefinition and have included the FileExtensionToContentTypeDefinition such as:
internal sealed class GaugeFileContentType
{
[Export]
[Name("Gauge")]
[BaseDefinition("code")]
internal static ContentTypeDefinition GaugeContentTypeDefinition = null;
[Export]
[FileExtension(".spec")]
[ContentType("Gauge")]
internal static FileExtensionToContentTypeDefinition GaugeFileExtensionDefinition = null;
}
Now, despite this, on debugging, I see that DTE.ActiveDocument.Type is text, despite me adding the [BaseDefinition('code')] attribute. What am I missing here?
Are the above definitions enough to tell Visual Studio to bring up Context menu for code?
I am using Visual Studio 2013 Ultimate.
After a few days of head banging, I managed to figure out a way.
I was using the Experimental Instance for debugging, and it did not clean and reinstall the extension, and thus Visual Studio continued to treat the ContentType as 'Plain Text', since that was what I had originally.
When I build a VSIX and installed, opened the same file in a new instance of Visual Studio, it brought up the right context menu.
However, it brought out more than what I wanted (i.e Run Unit Tests from Resharper). So I did some more digging up.
In order to ensure that Visual Studio can handle a command, it checks for it by calling IOleCommandTarget.QueryStatus method.
All I had to do was set the CommandFlag as (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED and return VSConstants.S_OK when the cmdId is VSConstants.VSStd97CmdID.GotoDefn.
The final method looks like this:
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
if ((VSConstants.VSStd97CmdID)prgCmds[0].cmdID == VSConstants.VSStd97CmdID.GotoDefn)
{
prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED;
return VSConstants.S_OK;
}
return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
}

Rename classes using Visual Studio Project Template

I have created a Visual Studio template using this link: http://msdn.microsoft.com/en-us/library/ms185301.aspx.
I am able to create a dialog where the user enters a custom message and it gets displayed:
namespace TemplateProject
{
class WriteMessage
{
static void Main(string[] args)
{
Console.WriteLine("$custommessage$");
}
}
}
What I want to do it allow the user to rename the class names so I want to do something like:
But you see I'm getting errors of "Unexpected character $"
How can I do this?
EDIT
I see from this link: http://msdn.microsoft.com/en-us/library/eehb4faa(v=vs.110).aspx that
To enable parameter substitution in templates:
In the .vstemplate file of the template, locate the ProjectItem element that corresponds to the item for which you want to enable parameter replacement.
Set the ReplaceParameters attribute of the ProjectItem element to true.
BUT above I have not yet generated the template yet as I am still defining the classes. I understnad that the above step needs to be done in order to get the parameter substitution enabled for a File-->New Project scenario.
It looks like you have your template file as a cs file, which is causing Visual Studio to attempt to build it directly.
From what I can tell you should create a functioning Project, export it, and then modify the resulting template to add any replacements you need.

How do you get the current solution directory from a VSPackage?

Following is how you would get the current solution directory from an add-in:
_applicationObject = (DTE2)application; // retrieved from OnConnection method
string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName);
How would you do this via a VSPackage?
I'm migrating a visual studio add-in to a VSPackage as I'm intending to add some user controls that require a deeper integration with the IDE.
I found some good references on the relative merits of add-ins vs integration packages such as:
http://nayyeri.net/visual-studio-addin-vs-integration-package-part-1
And some good tutorials on msdn on VSPackages such as:
http://msdn.microsoft.com/en-us/library/cc138589.aspx
I haven't found a good reference yet (on msdn or otherwise) on how the higher level interfaces in add-ins (such as DTE) map to lower level interfaces in VSPackages.
Any good references out there to help with general mapping from add-in interfaces to VSPackage interfaces?
I found the answer to the specific question. The VisualStudio.DTE object can be retrieved via the GetService() method as follows:
// Get an instance of the currently running Visual Studio IDE
DTE dte = (DTE)GetService(typeof(DTE));
string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName);
You can get a DTE object from one of these functions:
public static DTE GetCurrentDTE(IServiceProvider provider)
{
/*ENVDTE. */DTE vs = (DTE)provider.GetService(typeof(DTE));
if (vs == null) throw new InvalidOperationException("DTE not found.");
return vs;
}
public static DTE GetCurrentDTE()
{
return GetCurrentDTE(/* Microsoft.VisualStudio.Shell. */ServiceProvider.GlobalProvider);
}
After that, you can get active Solution from DTE.Solution and Solution path from DTE.Solution.Path property.
If using the IVsSolution interface, you can use GetSolutionInfo to obtain the path of the solution, the solution filename, and the solution user options (SUO) filename:
this.solution.GetSolutionInfo(
out string solutionDirectory,
out string solutionFile,
out string userOptsFile);

Categories