gpt4 book ai didi

visual-studio - 我可以从 Visual Studio "Find Symbol Results"窗口复制多行吗?

转载 作者:行者123 更新时间:2023-12-03 07:51:38 27 4
gpt4 key购买 nike

有谁知道如何将 Visual Studio“查找符号结果”窗口中的所有行复制到剪贴板上?您可以复制一行,但我想全部复制它们。

我不敢相信我是第一个想要这样做的人,但我什至找不到关于这个明显缺失的功能的讨论。

最佳答案

下面是一些使用 .Net 自动化库将所有文本复制到剪贴板的代码。

开始新的WinForms项目,然后添加以下引用:

  • WindowsBase
  • UIAutomationTypes
  • UIAutomationClient
  • System.Xaml
  • 介绍核心
  • 演示框架
  • 系统管理

  • 该代码还解释了如何在 Visual Studio 中设置菜单项以将内容复制到剪贴板。

    编辑: UI 自动化仅返回可见的树 View 项。因此,要复制所有项目,将查找符号结果窗口设置为前景,然后设置 {PGDN}发送,并复制下一批项目。重复此过程,直到找不到新项目。最好使用 ScrollPattern ,但是它抛出了 Exception尝试设置滚动时。

    编辑 2:试图通过在单独的线程上运行来提高 AutomationElement FindAll 的性能。在某些情况下似乎很慢。

    编辑 3:通过使 TreeView 窗口非常大来提高性能。可以在大约 10 秒内复制大约 400 个项目。

    编辑 4:处理对象实现 IDisposable .更好的消息报告。更好地处理流程参数。将窗口恢复到原来的大小。

    enter image description here
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Management;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    using System.Windows.Automation;
    using System.Windows.Forms;

    namespace CopyFindSymbolResults {

    // This program tries to find the 'Find Symbol Results' window in visual studio
    // and copy all the text to the clipboard.
    //
    // The Find Symbol Results window uses a TreeView control that has the class name 'LiteTreeView32'
    // In the future if this changes, then it's possible to pass in the class name as the first argument.
    // Use TOOLS -> Spy++ to determine the class name.
    //
    // After compiling this code into an Exe, add a menu item (TOOLS -> Copy Find Symbol Results) in Visual Studio by:
    // 1) TOOLS -> External Tools...
    // (Note: in the 'Menu contents:' list, count which item the new item is, starting at base-1).
    // Title: Copy Find Symbol Results
    // Command: C:\<Path>\CopyFindSymbolResults.exe (e.g. C:\Windows\ is one option)
    // 2) TOOLS -> Customize... -> Keyboard... (button)
    // Show Commands Containing: tools.externalcommand
    // Then select the n'th one, where n is the count from step 1).
    //
    static class Program {

    enum Tabify {
    No = 0,
    Yes = 1,
    Prompt = 2,
    }

    [STAThread]
    static void Main(String[] args) {

    String className = "LiteTreeView32";
    Tabify tabify = Tabify.Prompt;

    if (args.Length > 0) {
    String arg0 = args[0].Trim();
    if (arg0.Length > 0)
    className = arg0;

    if (args.Length > 1) {
    int x = 0;
    if (int.TryParse(args[1], out x))
    tabify = (Tabify) x;
    }
    }

    DateTime startTime = DateTime.Now;
    Data data = new Data() { className = className };

    Thread t = new Thread((o) => {
    GetText((Data) o);
    });
    t.IsBackground = true;
    t.Start(data);

    lock(data) {
    Monitor.Wait(data);
    }

    if (data.p == null || data.p.MainWindowHandle == IntPtr.Zero) {
    System.Windows.Forms.MessageBox.Show("Cannot find Microsoft Visual Studio process.");
    return;
    }

    try {

    SimpleWindow owner = new SimpleWindow { Handle = data.MainWindowHandle };

    if (data.appRoot == null) {
    System.Windows.Forms.MessageBox.Show(owner, "Cannot find AutomationElement from process MainWindowHandle: " + data.MainWindowHandle);
    return;
    }

    if (data.treeViewNotFound) {
    System.Windows.Forms.MessageBox.Show(owner, "AutomationElement cannot find the tree view window with class name: " + data.className);
    return;
    }

    String text = data.text;
    if (text.Length == 0) { // otherwise Clipboard.SetText throws exception
    System.Windows.Forms.MessageBox.Show(owner, "No text was found: " + data.p.MainWindowTitle);
    return;
    }

    TimeSpan ts = DateTime.Now - startTime;

    if (tabify == Tabify.Prompt) {
    var dr = System.Windows.Forms.MessageBox.Show(owner, "Replace dashes and colons for easy pasting into Excel?", "Tabify", System.Windows.Forms.MessageBoxButtons.YesNo);
    if (dr == System.Windows.Forms.DialogResult.Yes)
    tabify = Tabify.Yes;

    ts = TimeSpan.Zero; // prevent second prompt
    }

    if (tabify == Tabify.Yes) {
    text = text.Replace(" - ", "\t");
    text = text.Replace(" : ", "\t");
    }

    System.Windows.Forms.Clipboard.SetText(text);

    String msg = "Data is ready on the clipboard.";
    var icon = System.Windows.Forms.MessageBoxIcon.None;

    if (data.lines != data.count) {
    msg = String.Format("Only {0} of {1} rows copied.", data.lines, data.count);
    icon = System.Windows.Forms.MessageBoxIcon.Error;
    }

    if (ts.TotalSeconds > 4 || data.lines != data.count)
    System.Windows.Forms.MessageBox.Show(owner, msg, "", System.Windows.Forms.MessageBoxButtons.OK, icon);

    } finally {
    data.p.Dispose();
    }
    }

    private class SimpleWindow : System.Windows.Forms.IWin32Window {
    public IntPtr Handle { get; set; }
    }

    private const int TVM_GETCOUNT = 0x1100 + 5;

    [DllImport("user32.dll")]
    static extern int SendMessage(IntPtr hWnd, int msg, int wparam, int lparam);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int Width, int Height, bool Repaint);

    private class Data {
    public int lines = 0;
    public int count = 0;
    public IntPtr MainWindowHandle = IntPtr.Zero;
    public IntPtr TreeViewHandle = IntPtr.Zero;
    public Process p;
    public AutomationElement appRoot = null;
    public String text = null;
    public String className = null;
    public bool treeViewNotFound = false;
    }

    private static void GetText(Data data) {
    Process p = GetParentProcess();
    data.p = p;

    if (p == null || p.MainWindowHandle == IntPtr.Zero) {
    data.text = "";
    lock(data) { Monitor.Pulse(data); }
    return;
    }

    data.MainWindowHandle = p.MainWindowHandle;
    AutomationElement appRoot = AutomationElement.FromHandle(p.MainWindowHandle);
    data.appRoot = appRoot;

    if (appRoot == null) {
    data.text = "";
    lock(data) { Monitor.Pulse(data); }
    return;
    }

    AutomationElement treeView = appRoot.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.ClassNameProperty, data.className));
    if (treeView == null) {
    data.text = "";
    data.treeViewNotFound = true;
    lock(data) { Monitor.Pulse(data); }
    return;
    }

    data.TreeViewHandle = new IntPtr(treeView.Current.NativeWindowHandle);
    data.count = SendMessage(data.TreeViewHandle, TVM_GETCOUNT, 0, 0);

    RECT rect = new RECT();
    GetWindowRect(data.TreeViewHandle, out rect);

    // making the window really large makes it so less calls to FindAll are required
    MoveWindow(data.TreeViewHandle, 0, 0, 800, 32767, false);
    int TV_FIRST = 0x1100;
    int TVM_SELECTITEM = (TV_FIRST + 11);
    int TVGN_CARET = TVGN_CARET = 0x9;

    // if a vertical scrollbar is detected, then scroll to the top sending a TVM_SELECTITEM command
    var vbar = treeView.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Vertical Scroll Bar"));
    if (vbar != null) {
    SendMessage(data.TreeViewHandle, TVM_SELECTITEM, TVGN_CARET, 0); // select the first item
    }

    StringBuilder sb = new StringBuilder();
    Hashtable ht = new Hashtable();

    int chunk = 0;
    while (true) {
    bool foundNew = false;

    AutomationElementCollection treeViewItems = treeView.FindAll(TreeScope.Subtree, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TreeItem));
    if (treeViewItems.Count == 0)
    break;

    if (ht.Count == 0) {
    chunk = treeViewItems.Count - 1;
    }

    foreach (AutomationElement ele in treeViewItems) {
    try {
    String n = ele.Current.Name;
    if (!ht.ContainsKey(n)) {
    ht[n] = n;
    foundNew = true;
    data.lines++;
    sb.AppendLine(n);
    }
    } catch {}
    }

    if (!foundNew || data.lines == data.count)
    break;

    int x = Math.Min(data.count-1, data.lines + chunk);
    SendMessage(data.TreeViewHandle, TVM_SELECTITEM, TVGN_CARET, x);
    }

    data.text = sb.ToString();
    MoveWindow(data.TreeViewHandle, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top, false);
    lock(data) { Monitor.Pulse(data); }
    }

    // this program expects to be launched from Visual Studio
    // alternative approach is to look for "Microsoft Visual Studio" in main window title
    // but there could be multiple instances running.
    private static Process GetParentProcess() {
    // from thread: http://stackoverflow.com/questions/2531837/how-can-i-get-the-pid-of-the-parent-process-of-my-application
    int myId = 0;
    using (Process current = Process.GetCurrentProcess())
    myId = current.Id;
    String query = String.Format("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", myId);
    using (var search = new ManagementObjectSearcher("root\\CIMV2", query)) {
    using (ManagementObjectCollection list = search.Get()) {
    using (ManagementObjectCollection.ManagementObjectEnumerator results = list.GetEnumerator()) {
    if (!results.MoveNext()) return null;
    using (var queryObj = results.Current) {
    uint parentId = (uint) queryObj["ParentProcessId"];
    return Process.GetProcessById((int) parentId);
    }
    }
    }
    }
    }

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT {
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
    }
    }
    }

    关于visual-studio - 我可以从 Visual Studio "Find Symbol Results"窗口复制多行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1173808/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com