2009-07-23 57 views
36

Có ai biết cách sao chép tất cả các dòng trong cửa sổ "Tìm biểu tượng kết quả" của Visual Studio vào khay nhớ tạm không? Bạn có thể sao chép một dòng, nhưng tôi muốn sao chép tất cả.Tôi có thể sao chép nhiều hàng từ cửa sổ "Tìm biểu tượng kết quả" của Visual Studio không?

Tôi không thể tin rằng tôi là người đầu tiên muốn làm điều này, nhưng tôi thậm chí không thể tìm thấy một cuộc thảo luận về tính năng này dường như bị thiếu.

Trả lời

17

Dưới đây là một số mã có sử dụng thư viện Net Automation để sao chép tất cả các văn bản vào clipboard.

Bắt đầu một dự án mới WinForms và sau đó thêm các tài liệu tham khảo sau đây:

  • WindowsBase
  • UIAutomationTypes
  • UIAutomationClient
  • System.Xaml
  • PresentationCore
  • PresentationFramework
  • System.Management

Mã này cũng giải thích cách thiết lập mục menu trong studio trực quan để sao chép nội dung vào khay nhớ tạm.

Chỉnh sửa: Tự động hóa giao diện người dùng chỉ trả về các mục chế độ xem dạng cây có thể nhìn thấy. Do đó, để sao chép tất cả các mục, cửa sổ kết quả biểu tượng tìm được đặt làm nền trước, sau đó gửi {PGDN} và lô mục tiếp theo được sao chép. Quá trình này được lặp lại cho đến khi không tìm thấy mục mới nào. Sẽ thích hợp hơn khi sử dụng ScrollPattern, tuy nhiên nó đã ném một số Exception khi cố gắng đặt cuộn.

Chỉnh sửa 2: Đã cố gắng cải thiện hiệu suất của AutomationElement FindAll bằng cách chạy trên một chuỗi riêng biệt. Dường như chậm trong một số trường hợp.

Chỉnh sửa 3: Cải thiện hiệu suất bằng cách làm cho cửa sổ TreeView rất lớn. Có thể sao chép khoảng 400 mục trong khoảng 10 giây.

Chỉnh sửa 4: Vứt bỏ các đối tượng đang triển khai IDisposable. Báo cáo tin nhắn tốt hơn. Xử lý tốt hơn quá trình args. Đặt cửa sổ trở lại kích thước ban đầu của nó.

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; 
    } 
} 
} 
+0

Điều này thật ấn tượng. Cảm ơn bạn đã đăng nó. Tôi không thể chờ đợi để thử nó. –

+0

@ Mr.Putty Nó có phù hợp với bạn không? – Loathing

+0

Điều này làm việc tuyệt vời cho tôi. Tôi đã phải thêm "System.Management" cho VS 2013. – mojo

-1

Từ kinh nghiệm trước đây của tôi và một vài thử nghiệm tôi vừa làm, không có tính năng tích hợp để thực hiện việc này.

Tại sao bạn muốn thực hiện việc này? Tại sao bạn muốn sao chép tất cả các tham chiếu vào clipboard? Theo tôi hiểu, tốc độ của các tính năng này sẽ khiến cho bản sao tĩnh của tất cả các tham chiếu sẽ tương đối vô dụng nếu bạn có thể tạo bản sao động và hoàn chỉnh một cách nhanh chóng.

Bạn luôn có thể mở rộng studio trực quan để thêm chức năng này, xem this post tại quán cà phê egghead.

+3

Tôi không thể nói những tìm kiếm này hoàn thành nhanh chóng cho tôi. Tôi có một giải pháp khá lớn với nhiều dự án độc lập và tìm kiếm các ký hiệu mất nhiều phút (và không, máy của tôi không phải là một con chó tổng cộng). Ngoài ra, đầu ra chứa hàng trăm dòng, có phần hơi cồng kềnh. Thật không may, các tìm kiếm này thông minh hơn là bất kỳ điều gì tôi có thể dễ dàng thực hiện theo cách thủ công và tôi cũng muốn có thể so sánh đầu ra của một số tìm kiếm tương tự. Có lẽ hôm nay tôi chỉ là cáu kỉnh, nhưng đối với tôi, điều này thực sự dường như là một tính năng thiếu. –

+0

Tôi đã chơi thử với Visual Studio khá gần đây và mặc dù các hướng dẫn và tài liệu tầm thường bạn có thể làm nhiều thứ thú vị để mở rộng studio trực quan và bắt đầu thêm một thuật sĩ. Tôi khuyến khích bạn thêm điều này, vì nó không phải là khó để làm. – user142350

1

Có cùng yêu cầu và giải quyết vấn đề này bằng cách sử dụng công cụ chụp màn hình có tên Hypersnap cũng có một số chức năng OCR cơ bản.

2

Tôi đã giải quyết vấn đề này bằng cách sử dụng Macro Express. Họ có một bản dùng thử 30 ngày miễn phí mà tôi đã sử dụng vì đây là một lần cho tôi. Tôi đã viết một macro đơn giản để sao chép tất cả các kết quả tìm kiếm biểu tượng, một dòng tại một thời điểm, hơn vào một tài liệu Notepad.

trình tự: * Lặp lại (x) lần (kết quả tuy nhiên nhiều biểu tượng bạn có) * Kích hoạt Tìm Symbol cửa sổ Kết quả * trễ 0,5 giây * Mô phỏng tổ hợp phím "mũi tên xuống" * Clipboard Sao chép * Kích hoạt Notepad cửa sổ * trễ 0,5 giây * Clipboard Dán * Mô phỏng tổ hợp phím "ENTER" * End Lặp lại

+0

Các lựa chọn nguồn mở: [AutoHotKey] (http://www.autohotkey.com/), [Sikuli] (http://www.sikuli.org/). –

+0

@Sikuli - Tôi yêu AutoHotKey! Vâng, tôi ghét nó quá, nhưng nó giải quyết rất nhiều vấn đề. Tôi sẽ thêm điều này vào danh sách công việc cần làm dài để tự động hóa với AHK, nhưng tôi nghĩ Microsoft đang cho phép chúng tôi đi vòng quanh các cạnh. –

1

Nếu bạn có thể mã hóa biểu tượng của bạn như là một biểu cho Find toàn cầu, sau đó sao chép-dán tất cả các kết quả từ các cửa sổ Tìm Kết quả dễ.

ví dụ như việc tìm kiếm tất cả các tài liệu tham khảo tài sản 'foo' bạn có thể làm một phát toàn cầu cho '.foo'

+2

Đúng, điều này đúng, nhưng tìm tất cả các tham chiếu có vẻ thông minh hơn tôi một chút, và đôi khi tôi thực sự muốn sức mạnh của nó. Nó làm cho tôi buồn rằng cửa sổ 'Find Results' bình thường có lệnh copy trong khi cửa sổ 'Find Symbol Results' thì không. –

+0

đây không phải là giải pháp xấu đặc biệt nếu bạn sử dụng cụm từ thông dụng (nhưng vẫn tốt hơn nếu bạn có thể sao chép mọi thứ từ cửa sổ biểu tượng tìm kiếm) – TooTone

-1

Hey Bằng cách nào đó bạn có thể đạt được điều này theo một cách khác,

Chỉ cần 'FindAll' văn ​​bản đã chọn và bạn sẽ có thể nắm bắt tất cả các dòng

0

Visual Studio Mã hoạt động như một trình duyệt. nó có thể mở công cụ phát triển và tìm kiếm cho rằng một phần của mã

Menu: Help> Chuyển đổi các công cụ phát triển

viết các hướng dẫn sau đây để các công cụ phát triển giao diện điều khiển:

var elementos = document.getElementsByClassName("plain match") 
console.log(elementos.length) 
for(var i = 0; i<elementos.length;i++) console.log(elementos[i].title) 

và bạn có thể thấy kết quả trận đấu.

Bây giờ nếu bạn có thể sao chép các kết quả

screen shot

0

tôi đã cùng một vấn đề. Tôi phải lập danh sách tất cả các lần xuất hiện của một phương pháp nhất định và một số phiên bản quá tải của nó.

Để giải quyết vấn đề của tôi, tôi đã sử dụng ReSharper. (ReSharper -> Tìm -> Tìm tập quán nâng cao).

Nó cũng có tính năng xuất văn bản được lập bảng rất đẹp.

Các vấn đề liên quan