I'm currently developing my first VS extension, which needs to provide some options to the user. Following https://msdn.microsoft.com/en-us/library/bb166195.aspx, it was rather easy to come up with my own options page. However, I have not yet found out how to read my options.
The solution structure of my extension is as follows:
MySolution
MyProject (generates a DLL from C# code)
MyProjectVSIX
Following the tutorial cited above, I have added a VS Package
to my VSIX project and configured it as described. As a result, my options page with my options is shown under Tools/Options. Nice! Here's my DialogPage
implementation:
public class OptionPageGrid : DialogPage
{
private bool myOption = false;
[Category(Options.CATEGORY_NAME)]
[DisplayName("My option")]
[Description("Description of my option.")]
public bool MyOption
{
get { return myOption; }
set { myOption = value; }
}
}
And here's the head of my Package class:
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] [Guid(MyOptionsPage.PackageGuidString)]
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")]
[ProvideOptionPage(typeof(OptionPageGrid), Options.CATEGORY_NAME, Options.PAGE_NAME, 0, 0, true)]
public sealed class MyOptionsPage : Package, IOptions
{
...
However, I now want to read those options, and I want to do it from MyProject (which does not have a dependency on MyProjectVSIX). And this is where I'm kind of lost. My first attempt was to let my Package
implement an IOptions
interface, and to let it register itself by calling a static method Options.Register(IOptions)
from the Package
's constructor. This works (i.e., the breakpoint in Register()
is hit), but when I try to read options, the static IOptions
instance is still null. My assumption is that this is due to the fact that the code is executed from different processes (which is beyond my control).
After some more googling, I tried to get an instance of the DTE
object (which would allow me to read my options if I correctly understood), but to no success. I've tried several variants, including the one described at https://msdn.microsoft.com/en-us/library/ee834473.aspx and
DTE Dte = Package.GetGlobalService(typeof(DTE)) as DTE;
I always end up with a null reference.
Finally, since the tutorial suggested to access the options through the instance of Package
, I tried to figure out how to obtain such an instance of my VS Package
through some kind of registry (which I could than cast to IOptions
), but again without luck.
Can anybody please point me to the right direction? Or is it even impossible to access VS options from a non-VSIX project?
Update: I have done some more research, and one piece of information was missing: My extension is a Unit Test Adapter. This seems to imply that the test discovery code as well as the test execution code are run from different processes, i.e., my assumption was right.
I have in the meantime managed to access the DTE
object of the VS instance I'm running in (I will post that with my complete solution as soon as my problem is solved), but still have problems accessing the options. In fact, the following code (copied from here: https://msdn.microsoft.com/en-us/library/ms165641.aspx) works nicely:
Properties txtEdCS = DTEProvider.DTE.get_Properties("TextEditor", "CSharp");
Property prop = null;
string msg = null;
foreach (EnvDTE.Property temp in txtEdCS)
{
prop = temp;
msg += ("PROP NAME: " + prop.Name + " VALUE: " + prop.Value) + "\n";
}
MessageBox.Show(msg);
However, if I change the above as follows:
Properties txtEdCS = DTEProvider.DTE.get_Properties(CATEGORY_NAME, PAGE_NAME);
Now the code crashes. Weirdly enough, I can see my property category and page in the registry under HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0Exp_Config\AutomationProperties\My Test Adapter\General
. Searching for my properties shows them under HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\14.0Exp\ApplicationPrivateSettings\MyProjectVSIX\OptionPageGrid
(mabye because I added
OptionPageGrid Page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
Page.SaveSettingsToStorage();
to the Package
's Initialize()
method (as Matze suggested), maybe because I haven't looked there before :-) ).
So how to read my properties?
If you want to read the options from within your package, you can just ask for an OptionPageGrid
instance via the GetDialogPage
method of the VSPackage
. For instance:
var options = (OptionGridPage)this.package.GetDialogPage(typeof(OptionGridPage));
bool b = options.MyOption;
In case you want access the options from within another application (or an assembly which can be used without having the runtime environment of Visual Studio), you can try to read those settings right from the Windows registry, but the registry keys and values may not be present unless the options have been written by the IDE
or your package. You can force persistence of the options by calling the SaveSettingsToStorage
method from within your package, for instance on the first load:
options.SaveSettingsToStorage();
The settings will be stored under the following key:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\12.0\DialogPage
whereby 12.0
indicates the version of Visual Studio. Under this key you´ll find a bunch of sub-keys whose names are the full names of the DialogPage
component types. Each key contains the property values; in your case you should find a REG_SZ
value named MyOption
having either True
or False
as it´s data value.
My assumption is that this is due to the fact that the code is executed from different processes
Unless you're very explicitly writing stuff otherwise, all VS extensibility code runs in a single AppDomain under devenv.exe. If you're seeing it come up null, that means either your registration code didn't run, or didn't do what you thought it did.
You have a few options here:
Package.GetGlobalService
for your own service type. This has the major caveat that GetGlobalService has a bunch of gotchas; I avoid that method in general due to the challenges involved with it.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With