Extension for Specflow in visual studio - c#

I have a set of tests using specflow on Visual Studio, some of them have steps that looks like:
Given the data in file /foo/bar/data.txt
I would like to implement a Visual Studio extension so I can click on /foo/bar/data.txt and get the file opened.
I had a vague idea of using something like a Visual Studio text adorn, but I really don't know if there is a simpler way. Moreover, I'm looking for a solution that works in Visual Studio 2013 and above, and adorns are not supported in older versions as far as I know. Any ideas?

If you prefix the file path with file:// it will become a clickable link. Replace spaces with "%20" as you would with any URL.
I know that's not the answer to the question you are asking, but maybe you don't need to implement an extension?

One possible solution is to create a new menu entry with a Visual Studio Add-in, this way when you click in a line, and choose this menu option, you can execute an action (read and parse the line and open the file). This can be done as follows:
File->New Project->Other Types -> Extensibility -> Visual Studio Add-in, and the implement IDTCommandTarget
Commands2 commands = (Commands2)_applicationObject.Commands;
object[] contextGUIDS = new object[] { };
CommandBars cmdBars = (CommandBars)(_applicationObject.CommandBars);
CommandBar vsBarProject = cmdBars["Code Window"];
scenarioCommand = commands.AddNamedCommand2(_addInInstance, "OpenScenario", "Open scenario", "Open scenario data", true);
scenarioCommand.AddControl(vsBarProject);
Then in the Exec method, just read the line, get the file path, and:
Process.Start(resource)
And of course, just show the menu option if is a specFlow file in the QueryStatus method:
dynamic docName = _applicationObject.ActiveDocument.FullName;
if (CmdName == OpenScenarioCmd && !((string)docName).EndsWith(".feature"))
{
StatusOption = (vsCommandStatus)vsCommandStatus.vsCommandStatusInvisible;
}
else if (CmdName == OpenScenarioCmd)
{
StatusOption = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
}
It's not perfect, because you have to show a menu, but it works.

Related

Edit current visual studio document/file without write/save

I am working on a visual studio extension where I have to edit the current code open in the code pane.
Here is how my file edit code goes:
DTE dTE = Package.GetGlobalService(typeof(DTE)) as DTE;
TextDocument activeDoc = dTE.ActiveDocument.Object() as TextDocument;
string text =
activeDoc.CreateEditPoint(activeDoc.StartPoint).GetText(activeDoc.EndPoint);
string editted = Manipulate(text);
//File.WriteAllText("File Address", editted); // I don't want to use this
I want to edit the current opened document such that the user will be able to use ctrl+z to revert any changes the extension makes.
CreateEditPoint returns EnvDTE.EditPoint. You can use, for example, EditPoint.Insert or EditPoint.ReplaceText methods to change the document.

VSIX extension - closing windows that do not seem to have vsWindowKind constants

In my Visual Studio extension, I can close a window in the IDE by doing this:
var dte = (DTE)GetService(typeof(EnvDTE.DTE));
dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Close();
(That closes the output window)
There are windows which do not seem to have a "vsWindowKind" constant (all of which are listed here: https://msdn.microsoft.com/en-us/library/envdte.constants.aspx) - you can still close them if you know the GUID. For example:
dte.Windows.Item("{131369F2-062D-44A2-8671-91FF31EFB4F4}").Close();
closes the Team Explorer window (I found that GUID from another SO question: How do I run a TFS Work Item Query with Visual Studio Macros.
My question is, where can I find a complete list of IDE window GUIDs?
EDIT: so for VS2015 and below I can find a list of tool windows in the registry by doing the following:
var keyname = #"Software\Microsoft\VisualStudio\14.0_Config\ToolWindows";
using (var key = Registry.CurrentUser.OpenSubKey(keyname))
{
foreach (var subkey in key.GetSubKeyNames())
{
var fullkey = #"HKEY_CURRENT_USER\" + keyname + "\\" + subkey;
var name = (string)Registry.GetValue(fullkey, "Name", "");
if (!string.IsNullOrWhiteSpace(name))
{
Console.WriteLine($"{subkey} {name}");
}
}
}
However, there are no such entries for VS2017 (probably because it allows you to install multiple copies on the same PC).
Anyway, the documented list is still missing!
You can get the current window GUID with DTE.ActiveWindow.ObjectKind. This way you can build the list of IDE window GUIDs yourself.
Is this you're looking for? The vsWindowType Enumeration documentation.
https://msdn.microsoft.com/en-us/library/envdte.vswindowtype.aspx

Visual Studio Command for going to a specific item in source control explorer

Im looking for a way to automatically open Source Control Explorer from inside a plugincode.
So far I managed to open it by executing the command
View.TfsSourceControlExplorer
However, this does not seem to accept any arguments.
My goal here is to do something like this:
destination = "$/dev/framework/someFolder";
_dteObject.ExecuteCommand("View.TfsSourceControlExplorer", destination);
Which will them show me Source Control Explorer in the specified destination.
To anwser CSharpie's comment :
Also there seems to be a bug, if you call navigate to a file of the same directory as the explorer currently is in, everything will disappear.
I had the same problem, got two ways of solving this :
Truncate the filename from the path to only Navigate to folders.
Navigate to root first ("$/"), then navigate to the file you want.
Both works fine in VS2013.
And thanks for the "Application.DoEvent()" fix when the SourceControlExplorer's not opened.
Use the following code to show Source Control Explorer in the specified destination:
public void SelectFolder(string path)
{
dte.ExecuteCommand("View.TfsSourceControlExplorer");
Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExplorerExt explorer =
GetSourceControlExplorer();
if (explorer != null)
explorer.Navigate(path);
}
private Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExplorerExt GetSourceControlExplorer()
{
Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt versionControl =
dte.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") as
Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt;
if (versionControl == null)
return null;
return versionControl.Explorer;
}
I believe this is not possible. The source explorer detects the team project and drops you at the root of the team project node. $/myproject/ ..
Happy to be proven wrong on this one...

Send Custom Action Data via Command Line for Visual Studio Installer

I have a Visual Studio Installer that has a custom UI with one text box recovering a value that is set to QUEUEDIRECTORY property. Then I have a custom action (an Installer class) that passes in that property value with this line /queuedir="[QUEUEDIRECTORY]" - and the installer works great.
Now, I need to send that value via the command-line so that this installer can be run by system administrators all across the organization. So, I tried the following command line statements but it just doesn't work.
msiexec /i Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi QUEUEDIRECTORY="D:\temp"
Setup.msi queuedir="D:\temp"
msiexec /i Setup.msi queuedir="D:\temp"
Further, I can't seem to find anything online that doesn't feel like they hacked it because they just couldn't find the solution. I mean I've found some solutions where they are editing the MSI database and everything, but man that just doesn't seem like it's the right solution - especially since I'm using Visual Studio 2010 - Microsoft has surely made some enhancements since its initial release of this offering.
Here is one of the articles that appears would work but still really feels like a hack.
At any rate, I hope that you can help me out!
This is what I did to add command line only property values to my MSI in Visual Studio 2010. It's similar to the accepted answer, but less hacky. Create CommandLineSupport.js in setup project (.vdproj) directory, with the following code:
//This script adds command-line support for MSI installer
var msiOpenDatabaseModeTransact = 1;
if (WScript.Arguments.Length != 1)
{
WScript.StdErr.WriteLine(WScript.ScriptName + " file");
WScript.Quit(1);
}
WScript.Echo(WScript.Arguments(0));
var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
var sql
var view
try
{
sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"')";
view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();
}
catch(e)
{
WScript.StdErr.WriteLine(e);
WScript.Quit(1);
}
Then click on your Deployment Project in Visual Studio to view the Properties of the project, and set the PostBuildEvent to this:
cscript.exe "$(ProjectDir)CommandLineSupport.js" "$(BuiltOuputPath)"
Then set up the Delopyment Project with a Custom Action. Click on the Primary Output to get to the Custom Action Properties, and set the CustomActionData field to /MYPROPERTY="[MYPROPERTY]"
You can then access that property in your Custom Action installer class like this:
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string the_commandline_property_value = Context.Parameters["MYPROPERTY"].ToString();
}
In the end you can run the cmd. C:\>Setup.msi MYPROPERTY=VALUE
This doesn't require any messing about in Orca, or using any custom dialog controls like in the accepted answer. You don't have to modify the PostBuildEvent to have the correct .msi name either. Etc. Also can add as many properties as you wish like this:
INSERT INTO `Property` (`Property`, `Value`) VALUES ('MYPROPERTY', 'MYPROPERTY=\"\"'),('MYPROPERTY2', 'MYPROPERTY2=\"\"', ('MYPROPERTY3', 'MYPROPERTY3=\"\"')) ";
Have fun!
Alright, so I ended up going with the solution I linked to in the question. But let me put the script here for completeness. The first thing I needed to do was build a JS file that had the following code (I named it CommandLineSupport.js) and put it in the same directory as the .vdproj.
//This script adds command-line support for MSI build with Visual Studio 2008.
var msiOpenDatabaseModeTransact = 1;
if (WScript.Arguments.Length != 1)
{
WScript.StdErr.WriteLine(WScript.ScriptName + " file");
WScript.Quit(1);
}
WScript.Echo(WScript.Arguments(0));
var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
var sql
var view
try
{
//Update InstallUISequence to support command-line parameters in interactive mode.
sql = "UPDATE InstallUISequence SET Condition = 'QUEUEDIRECTORY=\"\"' WHERE Action = 'CustomTextA_SetProperty_EDIT1'";
view = database.OpenView(sql);
view.Execute();
view.Close();
//Update InstallExecuteSequence to support command line in passive or quiet mode.
sql = "UPDATE InstallExecuteSequence SET Condition = 'QUEUEDIRECTORY=\"\"' WHERE Action = 'CustomTextA_SetProperty_EDIT1'";
view = database.OpenView(sql);
view.Execute();
view.Close();
database.Commit();
}
catch(e)
{
WScript.StdErr.WriteLine(e);
WScript.Quit(1);
}
You of course would need to ensure that you're replacing the right Action by opening the MSI in Orca and matching that up to the Property on the custom dialog you created.
Next, now that I had the JS file working, I needed to add a PostBuildEvent to the .vdproj and you can do that by clicking on the setup project in Visual Studio and hitting F4. Then find the PostBuildEvent property and click the elipses. In that PostBuildEvent place this code:
cscript "$(ProjectDir)CommandLineSupport.js" "$(BuildOutputPath)Setup.msi"
Making sure to replace Setup.msi with the name of your MSI file.
Though I still feel like it's a hack ... because it is ... it works and will do the job for now. It's a small enough project that it's really not a big deal.
This is an old thread, but there's a simpler, working solution that still seems hard to find, hence why I'm posting it here.
In my scenario we're working with VS2013 (Community Ed.) and VS 2013 Installer Project extension. Our installer project has a custom UI step collecting two user texts and a custom action bound to Install\Start step that receives those texts.
We were able to make this work from GUI setup wizard, but not from command line. In the end, following this workaround, we were able to make also command line work, without any MSI file Orca editing.
The gist of the thing was to set a value for all needed custom dialog properties directly from Visual Studio, and such value should be in the form [YOUR_DIALOG_PROPERTY_NAME]. Also, it seems like such "public" properties must be named in all caps.
Here's the final setup:
Custom dialog properties
Note e.g. Edit1Property and Edit1Value.
Custom action properties
Note as property key used later in code can be named in camel case.
Custom action code
string companyId = Context.Parameters["companyId"];
string companyApiKey = Context.Parameters["companyApiKey"];
Command line
> setup.exe COMPANYID="Some ID" COMPANYAPIKEY="Some KEY" /q /l mylog.txt
HTH

Console.WriteLine does not show up in Output window

I have put some Console.WriteLine calls in to test, but they aren't appearing in the output box?
public static ArrayList myDeliveries = new ArrayList();
public mainForm(){
InitializeComponent();
}
private void mainForm_Load(object sender, EventArgs e){
if (!File.Exists("../../MealDeliveries.txt")){
MessageBox.Show("File not found!");
return;
}
using (StreamReader sr = new StreamReader("../../MealDeliveries.txt")){
//first line is delivery name
string strDeliveryName = sr.ReadLine();
Console.WriteLine("Test content");
while (strDeliveryName != null){
//other lines
Delivery d = new Delivery(
strDeliveryName,
sr.ReadLine(),
sr.ReadLine(),
sr.ReadLine(),
sr.ReadLine(),
sr.ReadLine(),
sr.ReadLine()
);
mainForm.myDeliveries.Add(d);
//check for further values
strDeliveryName = sr.ReadLine();
}
}
displayDeliveries();
}
private void displayDeliveries(){
lstDeliveryDetails.Items.Clear();
Console.WriteLine("Test content");
Console.WriteLine(mainForm.myDeliveries.Count);
foreach (Delivery d in mainForm.myDeliveries){
lstDeliveryDetails.Items.Add(d.DeliveryName);
}
}
Can anyone help??
Console outputs to the console window and Winforms applications do not show the console window. You should be able to use System.Diagnostics.Debug.WriteLine to send output to the output window in your IDE.
Edit: In regards to the problem, have you verified your mainForm_Load is actually being called? You could place a breakpoint at the beginning of mainForm_Load to see. If it is not being called, I suspect that mainForm_Load is not hooked up to the Load event.
Also, it is more efficient and generally better to override On{EventName} instead of subscribing to {EventName} from within derived classes (in your case overriding OnLoad instead of Load).
If you intend to use this output in production, then use the Trace class members. This makes the code portable, you can wire up different types of listeners and output to the console window, debug window, log file, or whatever else you like.
If this is just some temporary debugging code that you're using to verify that certain code is being executed or has the correct values, then use the Debug class as Zach suggests.
If you absolutely must use the console, then you can attach a console in the program's Main method.
If you want Console.WriteLine("example text") output to show up in the Debug Output window, temporarily change the Output type of your Application from Console Application to Windows Application.
From menus choose Project + Properties, and navigate to Output type: drop down, change to Windows Application then run your application
Of course you should change it back for building a console application intended to run outside of the IDE.
(tested with Visual Studio 2008 and 2010, expect it should work in latter versions too)
Using Console.WriteLine( "Test" ); is able to write log messages to the Output Window (View Menu --> Output) in Visual Studio for a Windows Forms/WPF project.
However, I encountered a case where it was not working and only System.Diagnostics.Debug.WriteLine( "Test" ); was working. I restarted Visual Studio and Console.WriteLine() started working again. Seems to be a Visual Studio bug.
If you are developing a command line application, you can also use Console.ReadLine() at the end of your code to wait for the 'Enter' keypress before closing the console window so that you can read your output. However, both the Trace and Debug answers posted above are better options.
Try to uncheck the CheckBox “Use Managed Compatibility Mode” in
Tools => Options => Debugging => General
It worked for me.
Try to uncheck the CheckBox “Redirect all Output Window text to the Immediate Window” in
Tools => Options => Debugging => General
I had it checked and everything was written in the Immediate Window and not in the Output Window
When issue happening on Mac VS 2017 (Which I faced).
Go to Project >> "Your Project name" options.
An option window will pop up
Go to RUN >> Default menu option
Tick the "Run on external console" option TRUE and say OK
Run your application code now.
Old Thread, But in VS 2015 Console.WriteLine does not Write to Output Window If "Enable the Visual Studio Hosting Process" does not Checked or its Disabled in Project Properties -> Debug tab

Categories