debugging 调试:附加到在cmd.exe内运行的控制台应用程序的进程

nom7f22z  于 2022-12-13  发布在  其他
关注(0)|答案(8)|浏览(201)

对于从CMD窗口运行而不是由F5启动的控制台应用程序,如何“连接到进程...”?我这样问的原因是因为该应用程序采用命令行参数,我希望获得真正的体验。
我甚至连接到CMD.exe,但没有成功,或者使用Console.ReadKey()设置断点也没有成功。我有点不知所措。
这可能吗?

xzv2uavs

xzv2uavs1#

您可以选择:

  • 在Visual Studio中使用“调试-〉命令行参数”选项;
  • 使用“Debug -〉Attach to process”找到你的进程;它不是cmd.exe,而是一个可执行文件名为“MyProject.exe”的进程。您可以使用Process Explorer或其他支持“树视图”的任务管理器轻松找到进程ID -只需查找cmd.exe启动的进程。
  • 在Windows上(2022年),将Debugger.Launch()Debugger.Break()放入您的代码中--执行this时,系统将启动一个对话框,要求您选择要使用哪个Visual Studio示例进行调试(您可以选择已打开项目的示例)。
sxissh06

sxissh062#

要从命令行而不是使用VS GUI迷宫进行调试,请执行以下操作:

  • 启动Visual Studio命令提示字符
  • 键入vsjitdebugger/?,它将为您提供如下命令示例:

c:〉vsjitdebugger [应用程序名称] [参数]:启动指定的可执行文件并附加到调试器

  • 键入tlisttasklist将为您提供用于附加到现有进程的PID。例如:

c:〉任务列表|查找/i“web”

3gtaxfhh

3gtaxfhh3#

有可能,当然。试试这两种方法之一:
1.启动进程,然后进入Debug-〉Attach并找到该进程。您可能需要刷新才能看到它。
1.如果可能的话,在代码中添加一个“Debugger.Break()”语句;它将自动中断(但一定要删除它或用预处理器指令将它包围起来,这样它就不会进入生产代码)。

5kgi1eie

5kgi1eie4#

**2020更新:**到@VladV答题

Debugger.Break()不再起作用。
请尝试使用Debugger.Launch(),并在此行之后放置断点,否则VS将开始抱怨。

sqxo8psd

sqxo8psd5#

正如其他人所说,您可以在项目中指定stratup命令行参数,然后在Visual Studio中开始调试。
如果您仍然想要附加至执行中的应用程序,您必须将调试工具附加至MyApp.exe(无论您的应用程序名称为何,也就是编译至bin\debug目录的exe),而不是cmd.exe。附加至cmd.exe会附加至命令行程序,而不是应用程序的行程序。

yduiuuwa

yduiuuwa6#

在项目设置的“调试”部分有一个文本框“命令行参数:“。当VS调试器启动C#程序时,它会将这些参数传递给进程,就像程序是从命令行启动的一样。
另一种方法是使用命令行调试器。这里有几个选项,但老实说,除非你遇到一些非常麻烦的调试场景,否则你可能不想使用它们来代替VS。如果你有兴趣检查它们,下面的SO答案是一个很好的总结:

  • MSIL调试工具- Mdbg、Dbgclr、Cordbg

您还可以尝试在初始化早期调用System.Diagnostics.Debugger.Break()的技术-如果程序在调试器下运行,它将中断,如果它没有在调试器下运行,那么应该询问您是否要附加一个调试器。您可以根据配置文件或环境变量设置有条件地进行调用,这样只有在您真正感兴趣的情况下才会得到中断(有点打扰,但不是太坏)。

c7rzv4ha

c7rzv4ha7#

只要在“HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options”中为您的exe的名称添加一个注册表项,在它下面添加一个值为“vsjitdebugger.exe”的“debugger”项,您就可以看到一个对话框弹出,要求您在exe启动时选择要调试的VS版本。
有关详细信息,请参阅MSDN“How to: Launch the Debugger Automatically“。

nzkunb0c

nzkunb0c8#

我想我会在这里找到一些更好的解决方案,但似乎我已经有一个是最好的。Debugger.Break()只是根本不为我工作。但前一段时间我发现了VisualStudioAttacher类在GitHub上。找不到代表现在,但我张贴我的轻微修改版本。
你要这样使用它。

class Program {
    static void Main(string[] args) {
        VSAttacher.attachDebugger("SolutionFileContainingThisCode.sln");

        Console.WriteLine("Hello World"); //set a brakepoint here
        //...               
    }

}

这只会附加到目前开启的visual studio执行严修,而不需要您选择调试工具。

设置

1.创建名为VSAttacher的新类库项目,或创建您喜欢的任何名称。
1.在要调试的项目中添加对VSAttacher项目的引用。
1.在VSAttacher项目中,添加对envdte库的引用
1.将以下代码粘贴到VSAttacher项目:
密码:

using System.IO;
using EnvDTE;
using DTEProcess = EnvDTE.Process;
using System;
using System.Collections.Generic;
using Process = System.Diagnostics.Process;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace AppController {
    #region Classes

    /// <summary>Visual Studio attacher.</summary>
    public static class VSAttacher {

        public static Action<object> log = (o) => Console.WriteLine(o);
    
        //Change following variables depending on your version of visual studio
        //public static string VSProcessName = "WDExpress";
        //public static string VSObjectName = "!WDExpress";
        public static string VSProcessName = "devenv";
        public static string VSObjectName = "!VisualStudio";

        /// <summary>
        /// Tries to attach the program to Visual Studio debugger.
        /// Returns true is the attaching was successful, false is debugger attaching failed.
        /// </summary>
        /// <param name="sln">Solution file containing code to be debugged.</param>
        public static bool attachDebugger(string sln) {
            if (System.Diagnostics.Debugger.IsAttached) return true;
            log("Attaching to Visual Studio debugger...");

            var proc = VSAttacher.GetVisualStudioForSolutions(
                new List<string>() { Path.GetFileName(sln) });
            if (proc != null) VSAttacher.AttachVSToProcess(
                    proc, Process.GetCurrentProcess());
            else { 
                try { System.Diagnostics.Debugger.Launch(); }
                catch (Exception e) { }
            } // try and attach the old fashioned way

            if (System.Diagnostics.Debugger.IsAttached) {
                log(@"The builder was attached successfully. Further messages will displayed in ""Debug"" output of ""Output"" window.");
                return true;
            }
            log("Could not attach to visual studio instance.");
            return false;
        }

        #region Public Methods

        #region Imports
        [DllImport("User32")]
        private static extern int ShowWindow(int hwnd, int nCmdShow);

        /// <summary>Returns a pointer to an implementation of <see cref="IBindCtx"/> (a bind context object). This object stores information about a particular moniker-binding operation.</summary>
        /// <param name="reserved">This parameter is reserved and must be 0.</param>
        /// <param name="ppbc">Address of an <see cref="IBindCtx"/>* pointer variable that receives the interface pointer to the new bind context object. When the function is successful, the caller is responsible for calling Release on the bind context. A NULL value for the bind context indicates that an error occurred.</param>
        /// <returns></returns>
        [DllImport("ole32.dll")]
        public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

        /// <summary>Returns a pointer to the <see cref="IRunningObjectTable"/> interface on the local running object table (ROT).</summary>
        /// <param name="reserved">This parameter is reserved and must be 0.</param>
        /// <param name="prot">The address of an IRunningObjectTable* pointer variable that receives the interface pointer to the local ROT. When the function is successful, the caller is responsible for calling Release on the interface pointer. If an error occurs, *pprot is undefined.</param>
        /// <returns>his function can return the standard return values E_UNEXPECTED and S_OK.</returns>
        [DllImport("ole32.dll")]
        public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetFocus(IntPtr hWnd);
        #endregion

        public static string GetSolutionForVisualStudio(Process visualStudioProcess) {
            var vsi = getVSInstance(visualStudioProcess.Id);
            try { return vsi?.Solution.FullName;}
            catch (Exception) {} return null;
        }

        public static Process GetAttachedVisualStudio(Process ap) {
            var vsps = getVSProcess();
            foreach (Process vsp in vsps) {
                var vsi = getVSInstance(vsp.Id);
                if (vsi == null) continue;
                try {
                    foreach (Process dp in vsi.Debugger.DebuggedProcesses)
                        if (dp.Id == ap.Id) return dp;
                } catch (Exception) {}
            }
            return null;
        }

        public static void AttachVSToProcess(Process vsp, Process applicationProcess) {
            var vsi = getVSInstance(vsp.Id);
            if (vsi == null) return;
            //Find the process you want the VS instance to attach to...
            DTEProcess tp = vsi.Debugger.LocalProcesses.Cast<DTEProcess>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);

            //Attach to the process.
            if (tp != null) {
                tp.Attach();

                ShowWindow((int)vsp.MainWindowHandle, 3);
                SetForegroundWindow(vsp.MainWindowHandle);
            } else {
                throw new InvalidOperationException("Visual Studio process cannot find specified application '" + applicationProcess.Id + "'");
            }
        }

        public static Process GetVisualStudioForSolutions(List<string> sns) {
            foreach (string sn in sns) {
                var vsp = GetVSProc(sn);
                if (vsp != null) return vsp;
            }
            return null;
        }

        public static Process GetVSProc(string name) {
            var vsps = getVSProcess(); var e = false;
            foreach (Process vsp in vsps) {
                _DTE vsi = getVSInstance(vsp.Id);
                if (vsi == null) { e = true; continue; }
                try {
                    string sn = Path.GetFileName(vsi.Solution.FullName);
                    if (string.Compare(sn, name, StringComparison.InvariantCultureIgnoreCase)
                        == 0) return vsp;
                } catch (Exception) { e = true; }
            }
            if (!e) log($@"No running Visual Studio process named ""{VSProcessName}"" were found.");
            return null;
        }

        #endregion

        #region Private Methods

        private static IEnumerable<Process> getVSProcess() {
            Process[] ps = Process.GetProcesses();
            //var vsp = ps.Where(p => p.Id == 11576);
            return ps.Where(o => o.ProcessName.Contains(VSProcessName));
        }

        private static _DTE getVSInstance(int processId) {
            IntPtr numFetched = IntPtr.Zero;
            IMoniker[] m = new IMoniker[1];

            GetRunningObjectTable(0, out var rot);
            rot.EnumRunning(out var ms); ms.Reset();

            var rons = new  List<string>();
            while (ms.Next(1, m, numFetched) == 0) {
                IBindCtx ctx;
                CreateBindCtx(0, out ctx);

                m[0].GetDisplayName(ctx, null, out var ron);
                rons.Add(ron);
                rot.GetObject(m[0], out var rov);

                if (rov is _DTE && ron.StartsWith(VSObjectName)) {
                    int currentProcessId = int.Parse(ron.Split(':')[1]);

                    if (currentProcessId == processId) {
                        return (_DTE)rov;
                    }
                }
            }
            log($@"No Visual Studio _DTE object was found with the name ""{VSObjectName}"" that resides in given process (PID:{processId}).");
            log("The processes exposes following objects:");
            foreach (var ron in rons) log(ron);
            return null;
        }

        #endregion
    }

    #endregion
}

如果您使用的是Visual Studio的Express版本,则应更改VSProcessNameVSObjectName(这仅在Express和社区版本中进行了测试)。

相关问题