1

經過多年的愉快使用開源軟件,我認爲是時候回饋了。而且由於文檔通常是許多項目的薄弱環節,加上我的C#技能在FLOSS的角落並不是很高的需求,我想我會從教程等開始。拍攝截圖並在視覺上突出顯示集中控制

第二個教程對於刻錄工具,我已經得到惱火

  1. 截屏
  2. 亮點任何重要組成部分的日常
  3. 將其標註爲
  4. 添加到網站
  5. 重複

並認爲我可以自動化。

我想我正在尋找的是一個程序,它會截取當前打開的窗口,一個圍繞焦點控件的黃色條(可能是一個按鈕),然後彈出一個小文本框爲我輸入圖片的描述,最後將其添加到網站/數據庫/列表等。

現在對於我的實際問題:除非任何人知道已經做到這一點的工具,否則我需要一些初學者來了解如何在'外部'窗口訪問控件的大小和位置,以便我可以計算在哪裏繪製高亮條重要的控制。我記得那些可以揭示任何******受保護文本框的內容的Windows密碼揭密工具,但是我找不到任何打開的示例。我想,WinFAPI東西,WindowFromPoint + GetDlgItem或類似的東西。不知道在Linux中它是否更容易,但是任何一個都可以。對編程語言也沒有偏好。

回答

2

據我所知,你要做什麼需要一些P/Invoke,因爲.NET沒有任何API來訪問其他應用程序的窗口。

您可以先使用GetForegroundWindow開始獲取當前窗口(您需要使用全局熱鍵或計時器觸發該代碼,因爲如果切換窗口以獲取屏幕截圖,則會從您的窗口返回自己的窗口GetForegroundWindow)。

編輯

我被你的問題做一個小小的週日下午編碼的啓發。我發現,GetForegroundWindow會爲您提供前景窗口,但不是控制級別。但還有另一個有用的功能,即GetGUIThreadInfo,它可以幫助您獲得當前的重點控制和其他一些信息。我們可以使用GetWindowInfo來獲取有關窗口的信息(可能是包含在頂層窗口中的控件)。

把這些東西放在一起,我們可以抽象掉所有的堅韌不拔的P/Invoke調用一個窗口類:

using System; 
using System.Drawing; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace dr.Stackoverflow.ScreenshotTest 
{ 
    public class Window 
    { 
     private WINDOWINFO info; 
     private readonly IntPtr handle; 

     internal Window(IntPtr handle) 
     { 
      this.handle = handle; 
     } 

     public int Handle 
     { 
      get { return handle.ToInt32(); } 
     } 

     // Note - will not work on controls in other processes. 
     public string Text 
     { 
      get 
      { 
       int length = GetWindowTextLength(handle); 
       if (length > 0) 
       { 
        StringBuilder buffer = new StringBuilder(length); 
        if (0 < GetWindowText(handle, buffer, length)) 
        { 
         return buffer.ToString(); 
        } 
       } 
       return "<unknown>"; 
      } 
     } 

     public Rectangle WindowArea 
     { 
      get 
      { 
       EnsureWindowInfo(); 
       return info.rcWindow; 
      } 
     } 

     public override string ToString() 
     { 
      return String.Format("{0} 0x{1}", Text, handle.ToString("x8")); 
     } 

     private unsafe void EnsureWindowInfo() 
     { 
      if (info.cbSize == 0) 
      { 
       info.cbSize = sizeof (WINDOWINFO); 
       if (!GetWindowInfo(handle, out info)) 
        throw new ApplicationException("Unable to get Window Info"); 

      } 
     } 

     public static Window GetForeground() 
     { 
      IntPtr handle = GetForegroundWindow(); 
      if (handle == IntPtr.Zero) 
       return null; 

      return new Window(handle); 
     } 

     public unsafe static Window GetFocus() 
     { 
      IntPtr foreground = GetForegroundWindow(); 
      int procId; 
      int tId = GetWindowThreadProcessId(foreground, out procId); 
      if (0 != tId) 
      { 
       GUITHREADINFO threadInfo = new GUITHREADINFO() {cbSize = sizeof (GUITHREADINFO)}; 
       if (GetGUIThreadInfo(tId, out threadInfo)) 
       { 
        return new Window(threadInfo.hwndFocus); 
       } 
      } 
      return null; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct WINDOWINFO 
     { 
      public int cbSize; 
      public RECT rcWindow; 
      public RECT rcClient; 
      public int dwStyle; 
      public int dwExStyle; 
      public int dwWindowStatus; 
      public uint cxWindowBorders; 
      public uint cyWindowBorders; 
      public int atomWindowType; 
      public int wCreatorVersion; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct GUITHREADINFO 
     { 

      public int cbSize; 
      public int flags; 
      public IntPtr hwndActive; 
      public IntPtr hwndFocus; 
      public IntPtr hwndCapture; 
      public IntPtr hwndMenuOwner; 
      public IntPtr hwndMoveSize; 
      public IntPtr hwndCaret; 
      public RECT rcCaret; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct RECT 
     { 
      public int left; 
      public int top; 
      public int right; 
      public int bottom; 

      public static implicit operator Rectangle(RECT rhs) 
      { 
       return new Rectangle(rhs.left, rhs.top, rhs.right - rhs.left, rhs.bottom - rhs.top); 
      } 
     } 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern bool GetWindowInfo(IntPtr hwnd, out WINDOWINFO pwi); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
     private static extern bool GetGUIThreadInfo(int threadId, out GUITHREADINFO threadInfo); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
     private static extern IntPtr GetForegroundWindow(); 

     [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
     private static extern int GetWindowTextLength(IntPtr hWnd); 

     [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount); 
    } 
} 

然後,我們可以用它做一個示例程序:

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Threading; 

namespace dr.Stackoverflow.ScreenshotTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Sleeping for 3 seconds (switch to a window of interest)"); 
      Thread.Sleep(3000); 

      Window currentWindow = Window.GetForeground(); 
      Window focusedWindow = Window.GetFocus();  
      if (currentWindow != null) 
      { 
       Console.WriteLine("Foreground window"); 
       Console.WriteLine(currentWindow.Text); 
       Console.WriteLine(currentWindow.WindowArea); 
      } 
      if (focusedWindow != null) 
      { 
       Console.WriteLine("\tFocused window"); 
       Console.WriteLine("\t{0}", focusedWindow.WindowArea); 
      } 

      if (focusedWindow !=null && currentWindow != null && focusedWindow.Handle != currentWindow.Handle) 
      { 
       Console.WriteLine("\nTaking a screenshot"); 
       Rectangle screenshotArea = currentWindow.WindowArea; 
       Bitmap bm = new Bitmap(currentWindow.WindowArea.Width,currentWindow.WindowArea.Height); 
       using(Graphics g = Graphics.FromImage(bm)) 
       { 
        g.CopyFromScreen(screenshotArea.Left,screenshotArea.Top, 0,0, new Size(screenshotArea.Width,screenshotArea.Height)); 
        Rectangle focusBox = focusedWindow.WindowArea; 
        focusBox.Offset(screenshotArea.Left * -1, screenshotArea.Top * -1); 
        focusBox.Inflate(5,5); 
        g.DrawRectangle(Pens.Red,focusBox); 
       } 
       bm.Save("D:\\screenshot.png", ImageFormat.Png); 
      } 
     } 
    } 
} 

這將使當前前景窗口的屏幕截圖顯示一個紅色框,突出顯示當前聚焦的控件。請注意,這是示例代碼,並且具有最小錯誤檢查功能:-)當您運行它時,Alt-Tab到感興趣的窗口並保持在該程序直到程​​序結束。

雖然有一些限制。我發現的最重要的一點是,這種方法在WPF應用程序中不起作用 - 僅僅因爲單個控件不是Windows,就像它們在其他Windows程序中一樣。

+0

哇...嫁給我嗎? 這幾乎就是我想到的,甚至是我心愛的C# - 非常感謝你:) – moraxy 2010-05-23 23:12:00

相關問題