在Visual Studio中以特定的行号打开文件

时间:2008-12-08 18:04:42

标签: visual-studio command-line

我有一个实用程序(grep),它给我一个文件名和行号列表。在我确定devenv是打开文件的正确程序之后,我想确保它在指定的行号处打开。在emacs中,这将是:

emacs +140 filename.c

我发现Visual Studio(devenv)没有这样的东西。我找到的最接近的是:

devenv /Command "Edit.Goto 140" filename.c

但是,这会为每个此类文件创建一个单独的devenv实例。我宁愿拥有使用现有实例的东西。

这些变体会重复使用现有的devenv,但不会转到指定的行:

devenv /Command "Edit.Goto 140" /Edit filename.c
devenv /Command  /Edit filename.c "Edit.Goto 140"

我认为使用多个“/ Command”参数可能会这样做,但我可能没有正确的参数,因为我得到错误或根本没有响应(除了打开一个空的devenv)。

我可以为devenv编写一个特殊的宏,但我希望这个实用程序可以被没有该宏的其他人使用。而且我不清楚如何使用“/ Command”选项调用该宏。

有什么想法吗?


嗯,似乎没有办法按我的意愿去做。由于看起来我需要有专门的代码来启动Visual Studio,所以我决定使用EnvDTE,如下所示。希望这会对其他人有所帮助。

#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;
}

14 个答案:

答案 0 :(得分:29)

使用VS2008 SP1 ,您可以使用以下命令行在现有实例中的特定行打开文件:

devenv /edit FILE_PATH /command "edit.goto FILE_LINE"

Source

答案 1 :(得分:26)

在阐述Harold的问题和答案时,我将C ++解决方案(我最初采用的)改编为C#。它更简单(这是我的第一个C#程序!)。只需要创建一个项目,添加对“envDTE”和“envDTE80”的引用并删除以下代码:

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);      
            }
        }
    }
}

然后只需拨打openStudioFileLine path_to_file numberOfLine

希望这可能有所帮助!

答案 2 :(得分:13)

根据reder回答,我发布了repository with sourcehere is binary(.net2.0)

我还添加了对多个VS版本的支持

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 

使用GrepWin的示例:

VisualStudioFileOpenTool.exe 12 %path% %line%

答案 3 :(得分:3)

很老的帖子,但它让我开始了,所以这是另一个例子。此AutoHotkey函数打开一个文件,并将光标放在特定的rowand列上。

; 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)
}

致电:

VST_Goto("C:\Palabra\.NET\Addin\EscDoc\EscDoc.cs", 328, 40)

你可以将它逐行翻译成VBScript或JScript。

答案 4 :(得分:3)

以下是哈罗德解决方案的VBS变体:link to .vbs script

open-in-msvs.vbs full-path-to-file line column

Windows原生支持VBScript - 无需编译或任何其他解释器。

答案 5 :(得分:2)

以下是Harold解决方案的Python变体:

import sys
import win32com.client

filename = sys.argv[1]
line = int(sys.argv[2])
column = int(sys.argv[3])

dte = win32com.client.GetActiveObject("VisualStudio.DTE")

dte.MainWindow.Activate
dte.ItemOperations.OpenFile(filename)
dte.ActiveDocument.Selection.MoveToLineAndOffset(line, column+1)

它显示了如何转到指定的行+列。

答案 6 :(得分:1)

此处参考的是用C#编写的ENVDE(在VisualStudio中使用O2 Platform来获取对直播DTE对象的引用)

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;

此代码执行一个小动画,其中选择了20行(间隔为100毫秒)

答案 7 :(得分:1)

强制wingrep并跳转到行号的正确syntax命令行new instance是:

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" $F /command "edit.goto $L"

studio version number替换为您的设置的正确版本。

答案 8 :(得分:1)

这是我适用于Visual Studio 2017(15.9.7)的C#解决方案

对于其他版本的VS,只需更改版本号(即“ VisualStudio.DTE.14.0”)

待办事项:     添加参考->搜索“ envdte”->选中“ envdte”复选框->单击“确定”

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());
}

答案 9 :(得分:0)

我无法通过直接命令行选项找到解决方法。看起来你必须为它编写一个宏。据说,你可以像这样调用它们。

devenv /command "Macros.MyMacros.Module1.OpenFavoriteFiles"

因此,您可以创建一个带有文件名和行号的宏,然后打开文件并跳转到正确的位置。但是,我不知道你可以在某处指定同一实例标志。

答案 10 :(得分:0)

我正要问这个问题,因为当您在调试Web应用程序时遇到“黄色死亡屏幕”时,您希望快速转到它在堆栈跟踪中提供的文件和行,例如:

[ContractException: Precondition failed: session != null]
   System.Diagnostics.Contracts.__ContractsRuntime.TriggerFailure(ContractFailureKind kind, String msg, String userMessage, String conditionTxt, Exception inner) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   System.Diagnostics.Contracts.__ContractsRuntime.ReportFailure(ContractFailureKind kind, String msg, String conditionTxt, Exception inner) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   System.Diagnostics.Contracts.__ContractsRuntime.Requires(Boolean condition, String msg, String conditionTxt) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\CustomErrorsPageController.cs:0
   IAS_UI.Web.IAS_Session..ctor(HttpSessionStateBase session) in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Web\IAS_Session.cs:15
   IAS_UI.Controllers.ServiceUserController..ctor() in C:\_svn\IntegratedAdaptationsSystem\Source\IntegratedAdaptationsSystem\IAS_UI\Controllers\ServiceUserController.cs:41

说我想去第41行的ServiceUserController.cs。通常我会打开Visual Studio并手动完成,但后来我写了一个Autohotkey脚本来完成它。

要打开它,您将突出显示文件名和行号,例如ServiceUserController.cs:41然后按下您的快捷方式Alt + v。这是代码:

$!v::
if (NOT ProcessExists("devenv.exe"))
{
    MsgBox, % "Visual Studio is not loaded"
}
else
{
    IfWinExist, Microsoft Visual Studio
    {
        ToolTip, Opening Visual Studio...
        c := GetClip()

        if (NOT c) {
            MsgBox, % "No text selected"
        }
        else 
        {
            WinActivate ; now activate visual studio
            Sleep, 50
            ; for now assume that there is only one instance of visual studio - handling of multiple instances comes in later

            arr := StringSplitF(c, ":")

            if (arr.MaxIndex() <> 2) {
                MsgBox, % "Text: '" . c . "' is invalid."
            }
            else {
                fileName := arr[1]
                lineNumber := arr[2]

                ; give focus to the "Find" box
                SendInput, ^d 

                ; delete the contents of the "Find" box
                SendInput, {Home}
                SendInput, +{End}
                SendInput, {Delete}

                ; input *** >of FILENAME *** into the "Find" box
                SendInput, >of{Space}
                SendInput, % fileName

                ; select the first entry in the drop down list
                SendInput, {Down}
                SendInput, {Enter}

                ; lineNumber := 12 remove later

                ; open the go to line dialog
                SendInput, ^g
                Sleep, 20

                ; send the file number and press enter
                SendInput, % lineNumber
                SendInput {Enter}
            }
        }    
        ToolTip
    }
}
return

您需要在其前面粘贴以下“实用程序功能”:

GetClip()
{
    ClipSaved := ClipboardAll
    Clipboard=
    Sleep, 30
    Send ^c
    ClipWait, 2
    Sleep, 30
    Gc := Clipboard
    Clipboard := ClipSaved
    ClipSaved=

    return Gc
}

ProcessExists(procName)
{
    Process, Exist, %procName%

    return (ErrorLevel != 0)
}

StringSplitF(str, delimeters)
{
    Arr := Object()

    Loop, parse, str, %delimeters%,
    {
        Arr.Insert(A_LoopField)
    }

    return Arr
}

答案 11 :(得分:0)

只要Visual Studio尚未打开,使用此命令对我有用。 &#34; C:\ Program Files(x86)\ Microsoft Visual Studio 14.0 \ Common7 \ IDE \ devenv.exe&#34; / edit&#34; ABSOLUTEFILEPATH_FILENAME.CPP&#34; / command&#34; Edit.GoTo 164&#34;

如果它已经打开,那么有时它会起作用并转到正确的行,但它会停止工作而我从未弄清楚原因。看起来微软已经意识到了这个问题,但他们已经说过他们不会修复这个问题。它,除非有更多人抱怨。因此,如果它仍然存在问题,我建议您在此处发表评论:https://connect.microsoft.com/VisualStudio/Feedback/Details/1128717

答案 12 :(得分:0)

这些对项目引用的C#依赖完全没有必要。实际上,这里的许多代码过于冗长。您需要的就是这个。

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 });
}

简单吗?

答案 13 :(得分:0)

@ Mungo64发布的版本对我有用,但是当然版本号一直在变化,所以我制作了一个自动搜索直到找到的版本。

添加引用->搜索“ envdte”->选中“ envdte”复选框->单击“确定”

//使用EnvDTE; //我没有使用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());
}