我有一个实用程序(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;
}
答案 0 :(得分:29)
使用VS2008 SP1 ,您可以使用以下命令行在现有实例中的特定行打开文件:
devenv /edit FILE_PATH /command "edit.goto FILE_LINE"
答案 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 source,here 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());
}