I have a utility (grep) that gives me a list of filenames and a line numbers. After I have determined that devenv is the correct program to open a file, I would like to ensure that it is opened at the indicated line number. In emacs, this would be:
emacs +140 filename.c
I have found nothing like this for Visual Studio (devenv). The closest I have found is:
devenv /Command "Edit.Goto 140" filename.c
However, this makes a separate instance of devenv for each such file. I would rather have something that uses an existing instance.
These variations re-use an existing devenv, but don't go to the indicated line:
devenv /Command "Edit.Goto 140" /Edit filename.c
devenv /Command /Edit filename.c "Edit.Goto 140"
I thought that using multiple "/Command" arguments might do it, but I probably don't have the right one because I either get errors or no response at all (other than opening an empty devenv).
I could write a special macro for devenv, but I would like this utility to be used by others that don't have that macro. And I'm not clear on how to invoke that macro with the "/Command" option.
Any ideas?
Well, it doesn't appear that there is a way to do this as I wanted. Since it looks like I'll need to have dedicated code to start up Visual Studio, I've decided to use EnvDTE as shown below. Hopefully this will help somebody else.
#include "stdafx.h"
//-----------------------------------------------------------------------
// This code is blatently stolen from http://benbuck.com/archives/13
//
// This is from the blog of somebody called "BenBuck" for which there
// seems to be no information.
//-----------------------------------------------------------------------
// import EnvDTE
#pragma warning(disable : 4278)
#pragma warning(disable : 4146)
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
#pragma warning(default : 4146)
#pragma warning(default : 4278)
bool visual_studio_open_file(char const *filename, unsigned int line)
{
HRESULT result;
CLSID clsid;
result = ::CLSIDFromProgID(L"VisualStudio.DTE", &clsid);
if (FAILED(result))
return false;
CComPtr<IUnknown> punk;
result = ::GetActiveObject(clsid, NULL, &punk);
if (FAILED(result))
return false;
CComPtr<EnvDTE::_DTE> DTE;
DTE = punk;
CComPtr<EnvDTE::ItemOperations> item_ops;
result = DTE->get_ItemOperations(&item_ops);
if (FAILED(result))
return false;
CComBSTR bstrFileName(filename);
CComBSTR bstrKind(EnvDTE::vsViewKindTextView);
CComPtr<EnvDTE::Window> window;
result = item_ops->OpenFile(bstrFileName, bstrKind, &window);
if (FAILED(result))
return false;
CComPtr<EnvDTE::Document> doc;
result = DTE->get_ActiveDocument(&doc);
if (FAILED(result))
return false;
CComPtr<IDispatch> selection_dispatch;
result = doc->get_Selection(&selection_dispatch);
if (FAILED(result))
return false;
CComPtr<EnvDTE::TextSelection> selection;
result = selection_dispatch->QueryInterface(&selection);
if (FAILED(result))
return false;
result = selection->GotoLine(line, TRUE);
if (FAILED(result))
return false;
return true;
}
In this article To access this dialog box, open a document for editing, and then select Edit > Go To > Go To Line or press Ctrl+G.
ReadWrite, FileShare. None); with this stream, you can read until you get to the point where you want to make changes, then write. Keep in mind that you are writing bytes, not lines, so to overwrite a line you will need to write the same number of characters as the line you want to change.
Click the Debug | Step Into menu item or press the F11 key to step into any property or method for debugging. You can then continue the line by line execution by pressing F10 or continue ...
With VS2008 SP1, you can use the following command line to open a file at a specific line in an existing instance :
devenv /edit FILE_PATH /command "edit.goto FILE_LINE"
Source
Elaborating on Harold question and answer, I adapted the C++ solution (that I first adopted) to C#. It is much simpler (that is my first C# program!). One just need to create a project, add references to "envDTE" and "envDTE80" and drop the following code:
using System;
using System.Collections.Generic;
using System.Text;
namespace openStudioFileLine
{
class Program
{
[STAThread]
static void Main(string[] args)
{
try
{
String filename = args[0];
int fileline;
int.TryParse(args[1], out fileline);
EnvDTE80.DTE2 dte2;
dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
dte2.MainWindow.Activate();
EnvDTE.Window w = dte2.ItemOperations.OpenFile(filename, EnvDTE.Constants.vsViewKindTextView);
((EnvDTE.TextSelection)dte2.ActiveDocument.Selection).GotoLine(fileline, true);
}
catch (Exception e)
{
Console.Write(e.Message);
}
}
}
}
One then just calls openStudioFileLine path_to_file numberOfLine
.
Hope that may help !
Based on reder answer I have published repository with source, here is binary(.net2.0)
I also add support for multiple VS versions
usage: <version> <file path> <line number>
Visual Studio version value
VisualStudio 2002 2
VisualStudio 2003 3
VisualStudio 2005 5
VisualStudio 2008 8
VisualStudio 2010 10
VisualStudio 2012 12
VisualStudio 2013 13
Example using from GrepWin:
VisualStudioFileOpenTool.exe 12 %path% %line%
Pretty old thread, but it got me started so here's another example. This AutoHotkey function opens a file, and puts the cursor on a particular rowand column.
; http://msdn.microsoft.com/en-us/library/envdte.textselection.aspx
; http://msdn.microsoft.com/en-us/library/envdte.textselection.movetodisplaycolumn.aspx
VST_Goto(Filename, Row:=1, Col:=1) {
DTE := ComObjActive("VisualStudio.DTE.12.0")
DTE.ExecuteCommand("File.OpenFile", Filename)
DTE.ActiveDocument.Selection.MoveToDisplayColumn(Row, Col)
}
Call with:
VST_Goto("C:\Palabra\.NET\Addin\EscDoc\EscDoc.cs", 328, 40)
You could translate it pretty much line by line to VBScript or JScript.
Here is VBS variation of Harold's solution: link to .vbs script.
open-in-msvs.vbs full-path-to-file line column
Windows supports VBScript natively - no need for compilation or any additional interpreters.
These C# dependencies on project references are completely unecessary. Indeed much of the code here is overly verbose. All you need is this.
using System.Reflection;
using System.Runtime.InteropServices;
private static void OpenFileAtLine(string file, int line) {
object vs = Marshal.GetActiveObject("VisualStudio.DTE");
object ops = vs.GetType().InvokeMember("ItemOperations", BindingFlags.GetProperty, null, vs, null);
object window = ops.GetType().InvokeMember("OpenFile", BindingFlags.InvokeMethod, null, ops, new object[] { file });
object selection = window.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, window, null);
selection.GetType().InvokeMember("GotoLine", BindingFlags.InvokeMethod, null, selection, new object[] { line, true });
}
Simples eh?
This is my working C# solution for Visual Studio 2017 (15.9.7)
For other versions of VS just change the version number (i.e. "VisualStudio.DTE.14.0")
todo: Add Reference->Search 'envdte'->Check Checkbox for envdte->Click OK
using EnvDTE;
private static void OpenFileAtLine(string file, int line)
{
DTE dte = (DTE) Marshal.GetActiveObject("VisualStudio.DTE.15.0");
dte.MainWindow.Visible = true;
dte.ExecuteCommand("File.OpenFile", file);
dte.ExecuteCommand("Edit.GoTo", line.ToString());
}
For reference here is the ENVDE written in C# (using O2 Platform inside VisualStudio to get a reference to the live DTE object)
var visualStudio = new API_VisualStudio_2010();
var vsDTE = visualStudio.VsAddIn.VS_Dte;
//var document = (Document)vsDTE.ActiveDocument;
//var window = (Window)document.Windows.first();
var textSelection = (TextSelection)vsDTE.ActiveDocument.Selection;
var selectedLine = 1;
20.loop(100,()=>{
textSelection.GotoLine(selectedLine++);
textSelection.SelectLine();
});
return textSelection;
This code does a little animation where 20 lines are selected (with a 100ms interval)
The correct wingrep
command line syntax
to force a new instance
and jump to a line number is:
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" $F /command "edit.goto $L"
Replace the studio version number
with the correct version for your setup.
The version posted by @Mungo64 worked for me, but of course the version number is always changing, so I made a version that automatically searches until we find it.
Add Reference->Search 'envdte'->Check Checkbox for envdte->Click OK
//using EnvDTE; //I didn't use the using directive as it causes ambiguity in another module I'm using.
private static void OpenFileAtLine(string file, int line)
{
//The number needs to be rolled to the next version each time a new version of visual studio is used...
EnvDTE.DTE dte = null;
for (int i = 25; i > 8; i--) {
try
{
dte = (EnvDTE.DTE)Marshal.GetActiveObject("VisualStudio.DTE." + i.ToString() + ".0");
}
catch (Exception ex)
{
//don't care... just keep bashing head against wall until success
}
}
//the following line works fine for visual studio 2019:
//EnvDTE.DTE dte = (EnvDTE.DTE)Marshal.GetActiveObject("VisualStudio.DTE.16.0");
dte.MainWindow.Visible = true;
dte.ExecuteCommand("File.OpenFile", file);
dte.ExecuteCommand("Edit.GoTo", line.ToString());
}
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