Can I pass an argument/switch/parameter to a VSPackage MenuCommand? - visual-studio

I was hoping someone here might be able to help me out with this. I'm not the most experienced programmer but I'm making progress on a project.
I've got a need to programmatically interact with Visual Studio. Some success has been had using EnvDTE Interop stuff, but it seems that some of what I need to do needs to be done inside VS so I'm attempting to utilize a VSPackage MenuCommand to do various things. Sorry the vagueness.
I'm currently successfully creating a custom MenuCommand with a VSPackage extension, and also am able to trigger that MenuCommand programmatically from another application using the DTE.
What I'm wondering is: is it possible to define a MenuCommand that CAN take arguments passed along to it from the triggering external application?
Using the VS Package Template in Visual Studio 2012 using the Menu Command option, all my code lives inside this method:
private void MenuItemCallback(object sender, EventArgs e)
{
// my code...
}
There is obviously a lot of other auto-generated code plumbing this all together, but all MY code lives in this method. Is there a way to alter this method so that it will allow parameters to be passed to it? What other changes must I make to the other files to declare/register this differently-functioning method once I do so (if I can)?
For example:
static void Main(string[] args)
{
Type visualStudioType = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
DTE dte = Activator.CreateInstance(visualStudioType) as DTE;
dte.MainWindow.Visible = true;
dte.ExecuteCommand("myCommand");
}
This works. But what I'd like to do is change that last command to:
dte.ExecuteCommand("myCommand", "myArguments");
When I attempt to do something like this, I receive the following exception:
"Command \"myCommand\" does not accept arguments or switches."
Sorry if I'm not being clear. Any help would be greatly appreciated.

Commands created from add-ins accept parameters by default.
Commands created from packages need to specify the <CommandFlag>AllowParams</CommandFlag> when defining the command in the .vsct file. See: http://msdn.microsoft.com/en-us/library/bb491716.aspx
And see also this thread:
IOleComandTarget::exec for commands with parameters
https://social.msdn.microsoft.com/Forums/en-US/134983e8-049c-40e1-a212-312fa637698b/iolecomandtargetexec-for-commands-with-parameters?forum=vsx
Then, it should work, either using dte.ExecuteCommand or dte.Commands.Raise(...). See:
HOWTO: Pass parameters programmatically to a command from a Visual Studio add-in
http://www.visualstudioextensibility.com/articles/add-ins/

Related

Is there a keyboard shortcut to enable/disable "Common Language Runtime Exceptions" in Visual Studio exception settings?

I find myself enabling and disabling the "Common Language Runtime Exceptions" checkbox in Exception Settings with considerable regularity. I'm tired of having to open the window every time. Is there a keyboard shortcut?
EDIT: as the answer as of June 2020 appears to be "no", I've requested a feature here: https://developercommunity.visualstudio.com/idea/1073035/keyboard-shortcut-to-enabledisable-the-common-runt.html
Is there a keyboard shortcut to enable/disable “Common Language
Runtime Exceptions” in Visual Studio exception settings?
I think there is no such quick shortcut to do that.
Actually, the shortcut for the Exception window is Ctrl+Alt+E, you can call such window by that.
However, VS only has a shortcut key to open a window, and there is no shortcut key to enable or disable an exception, and there are many different types of exceptions in the exception window. So it can be a bit difficult.
So you should use shortcut Ctrl+Alt+E to open Exception and then set the exception manually.
Besides, if you still want that feature to have a keyboard shortcut to enable/disable Common Language Runtime Exceptions, you can suggest this feature on our User Voice Forum.
After that, you can share the link with us here and anyone who is interested in this feature will vote it so that it will get more attention from Microsoft.
It is managed by the DebuggerServiceHelper class in VSDebugCoreUI.dll:
ExceptionSettingsBatchOperation{_operationDepth=3} DebuggerServiceHelper.BeginExceptionBatchOperation()
DebuggerServiceHelper.UpdateException(EXCEPTION_INFO150{bstrProgramName=null, bstrExceptionName="Common Language Runtime Exceptions", dwCode=0, dwState=16418})
ExceptionSettingsBatchOperation.EndBatchOperation()
But these are all internal classes and not easily accessible from external code.
Another approach is to find this WPF CheckBox on screen (by the TextBlock following it with the given Text property) and click it programmatically.
I really wish Exception Breaker worked for later versions of Visual Studio.
In combination with this answer to a similar question, I was able to get something to work. It is not ideal, but you might give this a try.
Note: I am using Visual Studio 2019
Tool required
The free version of the Visual Commander extension that allows Visual Studio macros in later versions.
Note: I tried (a little) to use the Macros for Visual Studio extension, but with no luck
Steps
Using Visual Commander, add a new command with the code below, save and compile.
Run with one of:
Run directly from the Visual Commander UI
Modify a toolbar and add the Extensions/Command01 command to it
Add a Keyboard shortcut via Options and select VCmd.Command01
Code
Notes:
I tried toggling the <All Common Language Runtime Exceptions not in this list> item, but did not have luck with it.
I tried looping through all of the Exceptions in the group but it was really slow (i.e. 15 seconds :-( ) so I picked the most important exceptions for my project.
I was unsuccessful finding a away to toggle the parent Common Language Runtime Exceptions, but if you find it, please leave a comment.
using EnvDTE;
using EnvDTE80; // DTE2 type
using EnvDTE90; // Debugger3
public class M : VisualCommanderExt.ICommand
{
public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
{
var lDebugger = DTE.Debugger as Debugger3;
var lExceptionSettings = lDebugger.ExceptionGroups.Item("Common Language Runtime Exceptions");
// Use this Exception as the master toggle
bool lExceptionsEnabledToSet = !lExceptionSettings.Item("System.ArgumentException").BreakWhenThrown;
// 2 examples
lExceptionSettings.SetBreakWhenThrown(lExceptionsEnabledToSet, lExceptionSettings.Item("System.ArgumentException"));
lExceptionSettings.SetBreakWhenThrown(lExceptionsEnabledToSet, lExceptionSettings.Item("System.OutOfMemoryException"));
// This does not work to set the whole group on/off:
//lExceptionSettings.SetBreakWhenThrown(true, lExceptionSettings.Item("<All Common Language Runtime Exceptions not in this list>"));
// This is really slow
//foreach (var lExceptionSetting in lExceptionSettings)
//{
// lExceptionSettings.SetBreakWhenThrown(lExceptionsEnabledToSet, lExceptionSetting as ExceptionSetting);
//}
}
}

How to debug multiple projects within a Visual Studio 2010 solution

I know that I can attach a currently executing process during a debug session. However, I have not found yet how to debug a process that is launched from the Startup project. I have this process being launched with a few parameters, and I would like to step in its initialization, and verify that the arguments that are being passed are correct. In other words, I would like to step into the startup process, and then, after the new process is launched make that the debugger stops in its first breakpoint.
Can someone show me how to configure this scenario using Visual Studio 2010?
Thanks!
Your question isn't completely clear...but, one way is to insert;
System.Diagnostics.Debugger.Break();
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Debugger.Break();
}
}
}
A screen will pop-up and you can attach debugger:
Click Debug
Select instance of VS2010 you'd like to use (for example, use the one that has your solution open).
If this isn't what you're looking for, please provide additional details

visual studio extension (VSPackage) add items to Test Explorer context menu

I am writing an extension to Visual studio 2012 using VSPackage. I need to add a context menu entry to Test Explorer and on click of this menu item, I need to get the selected unit test(s). I tried to add an item using
((CommandBars)DTE.CommandBars)["Test Window Context Menu"].Controls.Add(Type: MsoControlType.msoControlButton);
and adding an event handler by subscribing to the event
DTE.Events.CommandBarEvents[command].Click
I succeeded in adding an item to Context menu but the Click event handler never gets fired. MSDN said, I needed to set the OnAction property of the command to a valid string value for the Click event handler to get fired. It didn't work either.
Then, I figured out I needed to add a command through the VSCT file in a VSPackage. However, I am not able to find the Test Window Context menu so that I can attach the command to it. Also, I need to get all the unit tests (TestCase objects) listed in the Test Explorer.
Any help is greatly appreciated!
Usually these are the files I look for Visual Studio shell GUIDs or command, context menu, group, etc IDs:
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Common\Inc\stdidcmd.h
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h
Actually they are included in the top of your newly created .vsct file (<Extern href="vsshlids.h" />). I guess you've already checked them. I did a quick search, but what I found for "Test" is just a test ribbon and a test dialog. Probably now that you're looking for. It might be still useful for someone finding this post.
You might also want try it brute force style:
Search your Program Files (x86)\Visual Studio [VERSION] for regexp: ^#define.*TEST.*$
This shall give you the defines containing TEST.
Also you might want to consider asking Microsoft directly.
I wrote some exploratory code to loop over commands in that context menu. I also played around with registering a priority command target and seeing what group GUID and command ID I got. The GUID for that context menu appears to be {1e198c22-5980-4e7e-92f3-f73168d1fb63}. You can probably use that to add a command via the .vsct file without using the DTE.CommandBars to add it dynamically.
Here's my experiment code which lists the GUID and command ID of the commands currently in that context menu, in case it helps anyone.
var bars = ((Microsoft.VisualStudio.CommandBars.CommandBars)DTE.CommandBars);
var teContextMenu = bars["Test Window Context Menu"];
var ctls = teContextMenu.Controls;
foreach (var ctl in ctls)
{
var cmdCtl = ctl as Microsoft.VisualStudio.CommandBars.CommandBarControl;
string guid; int id;
DTE.Commands.CommandInfo(ctl, out guid, out id);
Debug.WriteLine($"{cmdCtl?.accName} {guid} {id}");
}
This article on command routing was helpful to me:
https://learn.microsoft.com/en-us/visualstudio/extensibility/internals/command-routing-algorithm
My experimental priority command target, where I set a breakpoint to see what GUID and command IDs were sent, is registered as follows. The TestCommandInterceptor class is a bare-bones implementation of IOleCommandTarget.
var cmdService = GetService(typeof(SVsRegisterPriorityCommandTarget)) as IVsRegisterPriorityCommandTarget;
var target = new TestCommandInterceptor();
cmdService.RegisterPriorityCommandTarget(0, target, out _testCmdInterceptorRegistrationCookie);
I would still like to know the answer to the second part of this question about how to determine the selected tests.

Custom Action not working - Visual Studio Setup Project

In the past we have used Advanced Installer to build our .msi installers for a particular project. Our yearly license for Advanced Installer has expired, so to avoid the renewal cost, and because I think the same can be accomplished with Visual Studio, I am attempting to use a Visual Studio 2010 Setup Project to build my .msi.
For the most part, the installer I have built with Visual Studio works fine. However, one thing we need the installer to do is run a couple of .reg files to add a large collection of settings to the registry (It may be worth noting that this is old software that is only being maintained and updated until it is replaced entirely in the near future. It is not practical to change our method of storing settings). With Advanced Installer, we were able to execute a .cmd file as an "Install" Custom Action that would run these .reg files that were also included in the installation. VS Setup Projects have Custom Actions, but it appears that here they are required to be either .dll or .exe files, so I must find an alternative to using a .bat or .cmd file.
First, I tried adding a Command Line project to my solution that consisted only of the following lines in the main() method:
using (Process registryInput = Process.Start("regedit.exe", "/s Settings1.reg"))
{
registryInput.WaitForExit();
}
using (Process registryInput= Process.Start("regedit.exe", "/s Settings2.reg"))
{
registryInput.WaitForExit();
}
I added the Primary Output of this project to the "Install" folder of the "Custom Actions" editor. Tried to run the installer, but the command line process never seemed to run and no registry settings were installed. If I manually ran the command line executable from the application directory where it was installed, it added the registry entries as intended - so the problem is not with the code I'm using to call the .reg files.
I turned to MSDN and changed my solution to be modeled after their Custom Actions Walkthrough. I created a Class Library project (and removed my Command Line project) and added an Installer Class. Instead of starting up a browser using Microsoft's website URL in the Commit() method as shown in their example, I added the code above to the Install() method. Here is what I ended up with:
[RunInstaller(true)]
public partial class Installer1 : System.Configuration.Install.Installer
{
public Installer1()
{
InitializeComponent();
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
using (Process registryInput = Process.Start("regedit.exe", "/s Settings1.reg"))
{
registryInput.WaitForExit();
}
using (Process registryInput = Process.Start("regedit.exe", "/s Settings2.reg"))
{
registryInput.WaitForExit();
}
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Rollback(IDictionary savedState)
{
base.Rollback(savedState);
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
}
}
I added the Primary Output of this new Class Library project to the "Install" folder of the "Custom Actions" editor. Still, when I run the installer, the code does not appear to be executed and my registry settings are not added. I have tried this installer both set to "Install for all users" and "This user only".
Any help to either get this Custom Action working or an alternative method to get a .reg file to run on install will be greatly appreciated. Thank you in advance.
I just ran across this same issue, re: the custom action not being picked up by the installer. The resolution was to run Visual Studio as an administrator.
Even though I'm a full admin on my machine without any restrictions (AFAIK), the installer would never pick up the custom actions. As soon as I closed down Visual Studio and then restarted as an administrator (right click > run as administrator), the custom actions were immediately picked up by the installer.
I banged my head on the keyboard for a bit on this one - and only after putting my custom installation actions in the Constructor of the Installer Class made it run.
I followed the tutorial I found here: http://msdn.microsoft.com/en-us/library/d9k65z2d(v=VS.100).aspx
See if this link helps, it helped me:
Visual Studio 2008 Installer, Custom Action. Breakpoint not firing
Basically, code after the
base.Install(stateSaver);
is not getting executed. So put the base.Install(stateSaver); as the last line in the method.
This may seem obvious but it caught me out for a while, so might as well post it.
I was just right-clicking on the installer project and then "Install" and "Uninstall". However, you have to rebuild the Installer project after changing the code! (and probably the project with the installer class as well)

Using EnvDTE.Solution - How to Remove Source Control Bindings

How do I use the EnvDTE.Solution API to remove TFS source control bindings from the solution file?
I know I can open the file in notepad and delete the GlobalSection portion, but I'm not sure if (or how) I can do this within the method below...
public void Export(Solution solution, TemplateInput model)
{
if(model.RemoveSourceControlBindings)
{
/* here */
}
}
I've found MSDN to be less than helpful with this API.
Don't know how, but I've seen it done with some regex magic
See:
Working Offline with TFS
Build Task to remove TFS bindings
Source here:
Wintellect.Build.Tasks.zip

Resources