Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open a file in Visual Studio at a specific line number

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;
}
like image 880
Harold Bamford Avatar asked Dec 08 '08 18:12

Harold Bamford


People also ask

How do I go to a specific line number in Visual Studio?

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.

How do you overwrite a line in a file in C#?

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.

How do I make line by line in Visual Studio?

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 ...


10 Answers

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

like image 179
Fouré Olivier Avatar answered Oct 04 '22 04:10

Fouré Olivier


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 !

like image 39
reder Avatar answered Oct 04 '22 04:10

reder


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%
like image 27
diimdeep Avatar answered Oct 04 '22 06:10

diimdeep


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.

like image 22
Wade Hatler Avatar answered Oct 04 '22 04:10

Wade Hatler


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.

like image 44
Evgeny Panasyuk Avatar answered Oct 04 '22 05:10

Evgeny Panasyuk


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?

like image 29
OnceUponATimeInTheWest Avatar answered Oct 04 '22 05:10

OnceUponATimeInTheWest


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());
}
like image 20
Mungo64 Avatar answered Oct 04 '22 06:10

Mungo64


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)

like image 1
Dinis Cruz Avatar answered Oct 04 '22 06:10

Dinis Cruz


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.

like image 1
Richard Mills Avatar answered Oct 04 '22 06:10

Richard Mills


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());
}
like image 1
Joe Avatar answered Oct 04 '22 06:10

Joe