60 Stimmen

Öffnen einer Datei in Visual Studio an einer bestimmten Zeilennummer

Ich habe ein Dienstprogramm (grep), das mir eine Liste von Dateinamen und Zeilennummern liefert. Nachdem ich festgestellt habe, dass devenv das richtige Programm zum Öffnen einer Datei ist, möchte ich sicherstellen, dass sie an der angegebenen Zeilennummer geöffnet wird. In emacs wäre dies der Fall:

emacs +140 filename.c

Ich habe nichts dergleichen für Visual Studio (devenv) gefunden. Das nächste, was ich gefunden habe, ist:

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

Dadurch wird jedoch für jede dieser Dateien eine eigene Instanz von devenv erzeugt. Ich würde lieber etwas haben, das eine bestehende Instanz verwendet.

Diese Varianten verwenden ein bestehendes devenv, gehen aber nicht bis zur angegebenen Zeile:

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

Ich dachte, dass die Verwendung mehrerer "/Command"-Argumente könnte es tun, aber ich habe wahrscheinlich nicht die richtige, weil ich entweder Fehler oder keine Antwort überhaupt (andere als das Öffnen eines leeren devenv) erhalten.

Ich könnte ein spezielles Makro für devenv schreiben, aber ich möchte, dass dieses Dienstprogramm auch von anderen verwendet werden kann, die dieses Makro nicht haben. Und mir ist nicht klar, wie ich dieses Makro mit der Option "/Command" aufrufen kann.

Irgendwelche Ideen?


Nun, es sieht nicht so aus, als gäbe es eine Möglichkeit, dies so zu tun, wie ich es wollte. Da es so aussieht, als bräuchte ich einen eigenen Code, um Visual Studio zu starten, habe ich mich entschieden, EnvDTE wie unten gezeigt zu verwenden. Ich hoffe, dass dies jemand anderem helfen wird.

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

1voto

Joe Punkte 597

Die von @Mungo64 gepostete Version hat bei mir funktioniert, aber natürlich ändert sich die Versionsnummer ständig, also habe ich eine Version erstellt, die automatisch sucht, bis wir sie finden.

Verweis hinzufügen->Suche 'envdte'->Kontrollkästchen für envdte ankreuzen->Klick OK

//using EnvDTE; //Ich habe die using-Direktive nicht verwendet, da sie in einem anderen Modul, das ich verwende, zu Mehrdeutigkeiten führt.

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

0voto

EndangeredMassa Punkte 16782

Ich kann keine Möglichkeit finden, dies mit direkten Befehlszeilenoptionen zu tun. Es sieht so aus, als müssten Sie ein Makro dafür schreiben. Angeblich kann man sie folgendermaßen aufrufen.

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

Sie können also wahrscheinlich ein Makro erstellen, das einen Dateinamen und eine Zeilennummer annimmt, dann die Datei öffnet und an die richtige Stelle springt. Aber ich weiß nicht, ob man irgendwo ein "same-instance"-Flag angeben kann oder nicht.

0voto

Tahir Hassan Punkte 5469

Ich wollte diese Frage stellen, denn wenn man beim Debuggen einer Webanwendung den "gelben Bildschirm des Todes" erhält, möchte man schnell zu der Datei und der Zeile gehen, die im Stacktrace angezeigt werden, z. B:

[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

Angenommen, ich möchte zu ServiceUserController.cs in Zeile 41 gehen. Normalerweise würde ich Visual Studio öffnen und es manuell tun, aber dann habe ich ein kleines Autohotkey-Skript geschrieben, das dies erledigt.

Um sie zu öffnen, markieren Sie den Dateinamen und die Zeilennummer, z. B. ServiceUserController.cs:41 und drücken Sie anschließend Ihr Tastenkürzel Alt + v . Hier ist der Code dafür:

$!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

Sie sollten die folgenden "Hilfsfunktionen" davor einfügen:

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
}

0voto

Craigw1701 Punkte 19

Mit diesem Befehl funktioniert es bei mir, solange Visual Studio NICHT bereits geöffnet ist. " C:\Program Dateien (x86) \Microsoft Visual Studio 14.0 \Common7\IDE\devenv.exe " /Bearbeiten "ABSOLUTEFILEPATH_FILENAME.CPP" /Befehl "Edit.GoTo 164"

Wenn es bereits geöffnet ist, funktioniert es manchmal und geht zur richtigen Zeile, aber dann funktioniert es einfach nicht mehr, und ich habe nie herausgefunden, warum. Es sieht so aus, als ob Microsoft sich des Problems bewusst ist, aber sie haben gesagt, dass sie es nicht beheben werden, solange sich nicht mehr Leute beschweren. Wenn es also immer noch ein Problem ist, würde ich vorschlagen, hier einen Kommentar abzugeben: https://connect.microsoft.com/VisualStudio/Feedback/Details/1128717

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X