Tôi cần sao chép nội dung của cửa sổ (BitBlt) bị ẩn, sang cửa sổ khác. Vấn đề là khi tôi ẩn cửa sổ nguồn, bối cảnh thiết bị mà tôi nhận được không còn được vẽ nữa.Sao chép nội dung từ cửa sổ bị ẩn hoặc bị cắt bớt trong XP?
Trả lời
Có thể bạn có thể kích hoạt thao tác vẽ lại trên cửa sổ bằng InvalidateRect?
Sao chép bitmap nguồn vào bitmap bộ nhớ trước khi đóng/ẩn cửa sổ.
Bạn có thể thử gửi thông báo WM_PRINT
tới cửa sổ. Đối với nhiều cửa sổ (bao gồm tất cả các cửa sổ tiêu chuẩn và các điều khiển chung), điều này sẽ làm cho nó sơn vào DC được cung cấp.
Ngoài ra, nếu bạn vượt qua HDC làm wparam của một tin nhắn WM_PAINT, nhiều cửa sổ (chẳng hạn như các điều khiển chung) sẽ vẽ vào DC đó chứ không phải trên màn hình.
Thật không may, tôi nghĩ rằng bạn sẽ gặp phải các vấn đề thực tế khi việc này hoạt động đáng tin cậy. Bạn không nói chính xác những gì bạn đang làm, nhưng tôi giả định rằng, với cửa sổ xử lý, bạn đang lấy bối cảnh thiết bị liên kết với cửa sổ bằng cách gọi GetWindowDC(), và sau đó sử dụng bối cảnh thiết bị kết quả.
Điều này sẽ hoạt động tốt trên XP khi cửa sổ hiển thị. Tuy nhiên, trên Vista, nếu tính năng tổng hợp máy tính để bàn được bật, thậm chí nó sẽ không hoạt động chính xác: bạn sẽ nhận được 0 từ GetWindowDC(). Về cơ bản, việc lấy bối cảnh thiết bị cửa sổ sẽ không hoạt động đáng tin cậy.
Nếu cửa sổ bạn đang cố gắng sao chép là một phần của ứng dụng của riêng bạn, tôi khuyên bạn nên sửa đổi mã của mình để hỗ trợ tin nhắn WM___PRINT: hoạt động như WM_PAINT, nhưng cho phép bạn cung cấp ngữ cảnh thiết bị .
Nếu cửa sổ không nằm trong ứng dụng của bạn, về cơ bản bạn sẽ không may: nếu cửa sổ bị ẩn, hình ảnh của cửa sổ sẽ hiển thị nếu nó hiển thị không tồn tại ở bất kỳ đâu.
Những gì bạn cần là chức năng PrintWindow có sẵn trong Win32 API từ Windows XP. Nếu bạn cần nó để làm việc với các phiên bản cũ của Windows, bạn có thể thử WM_PRINT, mặc dù tôi chưa bao giờ có thể làm cho nó hoạt động.
Có một bài viết tốt đẹp here cho thấy làm thế nào để sử dụng PrintWindow, và đây là đoạn mã có liên quan từ bài viết rằng:
// Takes a snapshot of the window hwnd, stored in the memory device context hdcMem
HDC hdc = GetWindowDC(hwnd);
if (hdc)
{
HDC hdcMem = CreateCompatibleDC(hdc);
if (hdcMem)
{
RECT rc;
GetWindowRect(hwnd, &rc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, RECTWIDTH(rc), RECTHEIGHT(rc));
if (hbitmap)
{
SelectObject(hdcMem, hbitmap);
PrintWindow(hwnd, hdcMem, 0);
DeleteObject(hbitmap);
}
DeleteObject(hdcMem);
}
ReleaseDC(hwnd, hdc);
}
tôi nên có một số mã Python sử dụng wxPython để đạt được điều tương tự. Thả cho tôi một lưu ý nếu bạn muốn.
Chức năng PrintWindow dường như không hoạt động trên cửa sổ ẩn, chỉ trên các cửa sổ hiển thị.
nhưng nó có thể hoạt động cho những màn hình ngoài ... – rogerdpack
Tiếp cận mọi thứ từ một góc nhìn khác, bạn có chắc đó thực sự là điều bạn muốn làm không? Chẳng hạn, bạn không muốn sử dụng CreateCompatibleDC và CreateCompatibleBitmap để tạo bề mặt vẽ vô hình của bạn, vẽ lên đó và sau đó sử dụng BitBlt?
Một số thông tin thêm về nền để những gì bạn đang lên đến có thể cho phép một người nào đó để đến với một trong hai giải pháp hoặc một số suy nghĩ bên ...
http://msdn.microsoft.com/en-us/library/dd144909.aspx (GetPixel) có thể giúp ...
Tôi chỉ thử nghiệm này trong Windows 7, nên làm việc tốt từ XP lên.
Nó mang cửa sổ về phía trước mà không đưa tiêu điểm vào trước khi chụp. Nó không hoàn hảo, nhưng đó là điều tốt nhất bạn sẽ làm nếu bạn không thể lấy PrintWindow() để làm việc.
Đó là một phương pháp tĩnh, vì vậy bạn chỉ có thể chỉ đơn giản gọi nó là như vậy:
Orwellophile.TakeScreenShotOfWindow("window.jpg", Form.Handle);
Không lộn xộn, không ồn ào. Đó là từ một lớp học lớn hơn, vì vậy hy vọng không có gì là mất tích. Bản gốc là:
http://sfinktah.trac.cvsdude.com/vhddirector/browser/main/VHD%20Director/UnhandledExceptionManager.cs và http://sfinktah.trac.cvsdude.com/vhddirector/browser/main/CSharp.cc/Win32Messaging.cs mặc dù chúng không có gì gọn gàng như ví dụ tôi đã dán bên dưới.
using System;
using System.Drawing;
using System.Threading;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class Orwellophile {
public static void TakeScreenshotOfWindow(String strFilename, IntPtr hTargetWindow)
{
Rectangle objRectangle;
RECT r;
IntPtr hForegroundWindow = GetForegroundWindow();
GetWindowRect(hTargetWindow, out r);
objRectangle = r.ToRectangle();
if (hTargetWindow != hForegroundWindow)
{
ShowWindow(hTargetWindow, SW_SHOWNOACTIVATE);
SetWindowPos(hTargetWindow.ToInt32(), HWND_TOPMOST, r.X, r.Y, r.Width, r.Height, SWP_NOACTIVATE);
Thread.Sleep(500);
}
TakeScreenshotPrivate(strFilename, objRectangle);
}
private static void TakeScreenshotPrivate(string strFilename, Rectangle objRectangle)
{
Bitmap objBitmap = new Bitmap(objRectangle.Width, objRectangle.Height);
Graphics objGraphics = default(Graphics);
IntPtr hdcDest = default(IntPtr);
int hdcSrc = 0;
objGraphics = Graphics.FromImage(objBitmap);
hdcSrc = GetDC(0); // Get a device context to the windows desktop and our destination bitmaps
hdcDest = objGraphics.GetHdc(); // Copy what is on the desktop to the bitmap
BitBlt(hdcDest.ToInt32(), 0, 0, objRectangle.Width, objRectangle.Height, hdcSrc, objRectangle.X, objRectangle.Y, SRCCOPY);
objGraphics.ReleaseHdc(hdcDest); // Release DC
ReleaseDC(0, hdcSrc);
objBitmap.Save(strFilename);
}
[DllImport("gdi32.dll", SetLastError = true)]
static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("user32.dll")]
static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("User32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); // To capture only the client area of window, use PW_CLIENTONLY = 0x1 as nFlags
[DllImport("gdi32.dll")]
static extern bool DeleteObject(IntPtr hObject);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // window handle
int hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags); // window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
static public extern IntPtr GetForegroundWindow();
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
private const int SRCCOPY = 0xcc0020;
}
Lưu ý rằng bạn có thể triển khai lớp/cấu trúc RECT trọng lượng nhẹ của riêng mình, nhưng đây là loại tôi sử dụng. Tôi đã đính kèm riêng nó do kích thước của nó là
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
public RECT(System.Drawing.Rectangle Rectangle)
: this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
{
}
public RECT(int Left, int Top, int Right, int Bottom)
{
_Left = Left;
_Top = Top;
_Right = Right;
_Bottom = Bottom;
}
public int X
{
get { return _Left; }
set { _Left = value; }
}
public int Y
{
get { return _Top; }
set { _Top = value; }
}
public int Left
{
get { return _Left; }
set { _Left = value; }
}
public int Top
{
get { return _Top; }
set { _Top = value; }
}
public int Right
{
get { return _Right; }
set { _Right = value; }
}
public int Bottom
{
get { return _Bottom; }
set { _Bottom = value; }
}
public int Height
{
get { return _Bottom - _Top; }
set { _Bottom = value - _Top; }
}
public int Width
{
get { return _Right - _Left; }
set { _Right = value + _Left; }
}
public Point Location
{
get { return new Point(Left, Top); }
set
{
_Left = value.X;
_Top = value.Y;
}
}
public Size Size
{
get { return new Size(Width, Height); }
set
{
_Right = value.Height + _Left;
_Bottom = value.Height + _Top;
}
}
public Rectangle ToRectangle()
{
return new Rectangle(this.Left, this.Top, this.Width, this.Height);
}
static public Rectangle ToRectangle(RECT Rectangle)
{
return Rectangle.ToRectangle();
}
static public RECT FromRectangle(Rectangle Rectangle)
{
return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
}
static public implicit operator Rectangle(RECT Rectangle)
{
return Rectangle.ToRectangle();
}
static public implicit operator RECT(Rectangle Rectangle)
{
return new RECT(Rectangle);
}
static public bool operator ==(RECT Rectangle1, RECT Rectangle2)
{
return Rectangle1.Equals(Rectangle2);
}
static public bool operator !=(RECT Rectangle1, RECT Rectangle2)
{
return !Rectangle1.Equals(Rectangle2);
}
public override string ToString()
{
return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
}
public bool Equals(RECT Rectangle)
{
return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
}
public override bool Equals(object Object)
{
if (Object is RECT)
{
return Equals((RECT)Object);
}
else if (Object is Rectangle)
{
return Equals(new RECT((Rectangle)Object));
}
return false;
}
public override int GetHashCode()
{
return Left.GetHashCode()^Right.GetHashCode()^Top.GetHashCode()^Bottom.GetHashCode();
}
}
Mã của bạn không trả lời được câu hỏi. Những gì bạn làm là dễ dàng! Nhưng nếu cửa sổ lớn hơn màn hình hoặc cắt bớt mã của bạn sẽ chỉ chụp được một phần! Câu hỏi đặt ra là cách chụp một cửa sổ phía sau cửa sổ khác hoặc bị ẩn hoặc bị cắt bớt. – Elmue
Mã này cực kỳ khó xử. Bạn có thể làm tương tự với 3 dòng mã mà không có bất kỳ DllImport nào bằng cách sử dụng Graphics.CopyFromScreen() – Elmue
Đối với cửa sổ ẩn sau một cửa sổ khác, bạn có thể đặt nó trong suốt (với alpha cao để không trong suốt). Sau đó, bạn có thể chụp toàn bộ cửa sổ bằng BitBlt.
- 1. System.Net.HttpWebResponse.GetResponseStream() trả về nội dung bị cắt bớt trong WebException
- 2. Trường Máy chủ SQL bị cắt bớt
- 3. Chuỗi RODBC bị cắt bớt
- 4. CSS: xóa toàn bộ phần tử khi bị cắt bớt
- 5. Cột văn bản MySQL bị cắt bớt
- 6. Nội dung tràn tự động bên trong tràn bị ẩn?
- 7. Cách đóng cửa sổ Kendo trong nội dung cửa sổ?
- 8. Cửa sổ WPF bị treo khi khởi động, hoặc nó bắt đầu nhưng bị treo và không hiển thị nội dung
- 9. Lỗi SQL: Chuỗi hoặc dữ liệu nhị phân sẽ bị cắt bớt
- 10. UINavigationBar tiêu đề bị cắt bớt khi thay đổi viewControllers
- 11. Cửa sổ xoay Java bị hỏng
- 12. Làm cách nào để sao chép tệp hoặc thư mục bị khóa trong cửa sổ theo chương trình?
- 13. Tại sao tam giác bị cắt trong lưới này?
- 14. Tại sao văn bản tiêu đề của tôi bị cắt bớt?
- 15. Tại sao các hoạt ảnh Xem đôi khi bị cắt bớt?
- 16. cắt nội dung trong TextView
- 17. Bật cửa sổ sao chép, cắt, quá khứ trong hộp văn bản có định dạng
- 18. Bóng SVG bị cắt
- 19. Drupal: tạo nội dung trong cửa sổ bật lên/lightbox?
- 20. Cửa sổ chính bị đóng băng khi cửa sổ con bị đóng băng quá mức từ một quá trình khác
- 21. Chụp ảnh màn hình nội dung cửa sổ cuộn
- 22. sendfile không sao chép nội dung tệp
- 23. Văn bản bị cắt bớt hoặc một hoặc nhiều ký tự không khớp trong trang mã đích Khi nhập từ tệp Excel
- 24. cửa sổ lệnh để cắt cột từ một văn bản
- 25. Sao chép nội dung DataGridView vào clipboard
- 26. Sử dụng rsync để chỉ sao chép các tệp bị ẩn
- 27. Cách mở cửa sổ từ thiết bị đầu cuối mac
- 28. Hiển thị nội dung wpf trên/ngoài các giới hạn cửa sổ chính
- 29. Đường dẫn cửa sổ Python cắt giảm
- 30. Cách duyệt nội dung của Tệp trong điện thoại cửa sổ 7?
Tôi đã luôn luôn tự hỏi nếu PrintWindow() sử dụng logic riêng của nó, hoặc nếu nó chỉ gửi một WM_PRINT đến cửa sổ nhất định. MSDN có vẻ mơ hồ vào thời điểm đó. Thời gian cho một chương trình thử nghiệm để kiểm tra rằng ... – DavidK
Nó sử dụng logic riêng của nó, không phải WM_PRINT. –
@DavidK: Phiên bản hiện tại của tài liệu rõ ràng nói rằng 'WM_PRINT' hoặc' WM_PRINTCLIENT' được gửi. –