如何捕获(Aero)窗口(所有状态) [英] How to Capture (Aero) Window (all states)

查看:167
本文介绍了如何捕获(Aero)窗口(所有状态)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Hello all :)

(抱歉我的英文不好)



最近我开始了一个可以直播的小应用程序使用DWM进行窗口预览。其中一个功能是仅渲染源窗口的一部分。这可以通过DWM API来实现,这一切都有效......

最终用户可以输入 RECT 值(X,Y,宽度和高度),但这是不实际的,非常不舒服。我的想法是让用户可视地选择(使用光标或其他指示设备)源窗口的哪个部分将被渲染。所以,我需要源窗口的图像。选择等不是问题,我已经完成了......

我面临的问题是如何正确捕获一个窗口



我需要帮助编写一些接受 hWnd / Handle 窗口并返回的函数它的形象。



当然我试图通过天真捕获来解决问题( BitBlt 直接到 Graphics.HDC [1] PrintWindow function [2] 。之后,尝试高级捕获到CompatibleBitmap(使用 CreateCompatibleBitmap 函数创建) [3] ,这是最接近我想要的。但是......它是最接近的,但是太过接受它作为解决方案。

我也试过 Form.DrawToBitmap() [4] 但是没有成功。



问题:

[1]它捕获得不是很好(无论如何,更好的是[3]方法)

[ 2]某些应用程序忽略 WM_PRINT WM_PRINTCLIENT 消息。此外, PrintWindow 将在窗口最小化时打印黑色图像。

[3]嗯,有很多问题......当窗口最小化时我只能得到它的标题栏(或某些窗口,没有,空白图像)。

此外, BitBlt (恕我直言)无法捕获一些Aero部分,图像1 [链接^ ]

此外,当窗口最大化时, BitBlt 未捕获其标题栏,图片2 [链接^ ]

在图像1中,您可以在右下角看到一点任务栏,VS窗口周围的黑色边框(黑色边框是真正的Aero边框)

图2:你也可以看到任务栏的部分,但是窗口后面会看到VS标题栏(Aero标题栏应该在哪里)



这是问题我无法解决,因为我认为这是一个 BitBlt 问题。我的程序需要完整的窗口图像,而不仅仅是客户区域。此外,仅在窗口可见时才会发布问题。在最小化状态下显示空白图像。



[4]我试过这个,因为DWM很好地渲染了最小化的窗口。创建新表单,使用DWM渲染,然后调用 .DrawToBitmap 函数。但这不起作用,因为DWM在更高层上渲染。所以,如果我在表单上有一个按钮,DMW将对其进行渲染。



我将发布我试过的所有解决方案的VB.NET代码。我认为很容易转换为C#或任何其他语言...

但是,在我这样做之前,我想提一下我想要捕获窗口而不使用DicetX / OpenGL或其他第三党的图书馆。此外,由显示窗口,然后捕获它,并再次最小化它的解决方案是非常不实用的,我的应用程序是在最小化时显示窗口的内容。



试试[1]:

Hello all :)
(Sorry for my bad English)

Recently I've started a small application that can show live window previews using DWM. One of the features is to render only part of source window. That can be achieved using DWM API, and that is all working...
End-user can enter the RECT values (X, Y, Width and Height) but that is not practical and is very uncomfortable. My idea was to let user to select (with cursor or other pointing device) visually which part of the source window will be rendered. So, I need image of source window. Selecting and etc. is not a problem, I've finished that...
The problem I'm facing is how to correctly capture a window?

I need help with writing some sort of function that accepts hWnd/Handle of window and returns its image.

Of course I've tried to solve problem by naive capturing (BitBlt direct to Graphics.HDC) [1] or by PrintWindow function [2]. After that, tried "advanced" capturing to CompatibleBitmap (created with CreateCompatibleBitmap function) [3] and that is closest to what I want. But... It is closest, but too far to accept it as solution.
I also tried with Form.DrawToBitmap() [4] but unsuccessfully.

Problems:
[1] it doesn't capture very well (anyway, much more better is [3] method)
[2] some applications are ignoring the WM_PRINT and WM_PRINTCLIENT messages. Also, PrintWindow will print black image when window is minimized.
[3] Well, There are many problems... When window is minimized I can only get its titlebar (or for some windows, nothing, blank image).
Furthermore, BitBlt (IMHO) cannot capture some Aero portions, image 1 [Link^]
Also, when window is maximized, BitBlt doesn't capture its titlebar, image 2 [Link^]
In Image 1 you can see in the bottom right corner a little bit of taskbar, and black border around VS window (that black border is real Aero border)
Image 2: you can also see portions of taskbar, but VS titlebar is seen behind the window (where Aero titlebar should be)

That are problems I can't solve because I think it is a BitBlt problem. My program requires full window image, not the client area only. Also, problems posted are only when window is visible. In minimized state blank image is shown.

[4] I've tried this because DWM renders minimized windows very well. Create new form, render with DWM to it, and call .DrawToBitmap function. But this won't work because DWM is rendering on a higher layer. So, if I have a button on a form, DMW will render over it.

I will post VB.NET code of all 'solutions' I tried. I think it is easy to convert to C# or any other language...
But, before I do that, I want to mention that I want to capture window without using DicetX/OpenGL or and other 3rd party libraries. Also, solution that consists of Showing window, then capturing it, and minimizing it again is very unpractical, and my application is there to show content of window(s) when minimized.

Try [1]:

Dim B As New Bitmap(Rc.Width, Rc.Height) 'Rc is Rectangle that represents window placement
Using G As Graphics = Graphics.FromImage(B)
    Dim I As IntPtr = G.GetHdc
    Dim U As IntPtr = GetWindowDC(H)
    BitBlt(I, 0, 0, Rc.Width, Rc.Height, U, Rc.Left, Rc.Top, &HCC0020) ' SrcCpy
    'ReleaseDC(H, U)
    G.ReleaseHdc(I)
End Using



试试[2]:


Try [2]:

Dim B As New Bitmap(Rc.Width, Rc.Height)
Using G As Graphics = Graphics.FromImage(B)
    Dim I As IntPtr = G.GetHdc
    PrintWindow(H, I, 0)
    G.ReleaseHdc(I)
End Using



尝试[3]

我不是这个特别代码的作者,但并不难实现


Try [3]
I'm not author of this particularly code, but is not hard to implement

Public Function CaptureWindow(handle As IntPtr) As Image
        ' get te hDC of the target window
        Dim hdcSrc As IntPtr = GetWindowDC(handle)
        ' get the size
        Dim windowRect As New RECT()
        GetWindowRect(handle, windowRect)
        Dim R As Rectangle = GetAeroRect(handle) ' ------> NOTE 1#
        Dim width As Integer = windowRect.Right - windowRect.Left
        Dim height As Integer = windowRect.Bottom - windowRect.Top
        ' create a device context we can copy to
        Dim hdcDest As IntPtr = CreateCompatibleDC(hdcSrc)
        ' create a bitmap we can copy it to,
        ' using GetDeviceCaps to get the width/height
        Dim hBitmap As IntPtr = CreateCompatibleBitmap(hdcSrc, width, height)
        ' select the bitmap object
        Dim hOld As IntPtr = SelectObject(hdcDest, hBitmap)
        ' bitblt over
        BitBlt(hdcDest, 0, 0, width, height, hdcSrc, _
            0, 0, CopyPixelOperation.SourceCopy)
        ' restore selection
        SelectObject(hdcDest, hOld)
        ' clean up
        DeleteDC(hdcDest)
        ReleaseDC(handle, hdcSrc)
        ' get a .NET image object for it
        Dim img As Image = Image.FromHbitmap(hBitmap)
        ' free up the Bitmap object
        DeleteObject(hBitmap)
        Return img
    End Function



尝试4很简单,我不会发布它。



在Try [3]中,注释注释1#


Try 4 is simple, and I won't post it.

In Try [3], line commented with Note 1#

Dim R As Rectangle = GetAeroRect(handle)



那是我面临的另一个问题。某些窗口的标准 GetWindowRect 函数返回了错误的结果(例如Skype窗口),因为Aero玻璃像素填充链接(新窗口/标签页)

我创建了 GetAeroRect 使用 DwmGetWindowAttribute API的函数,它现在正在运行(没注意到错误的结果)





所以,就是这样。我真的非常抱歉语法错误和重大问题。但我不能没有选择,我想发一个清晰的问题,不想得到像'你试过PrintWindow吗?'这样的问题; 你怎么试过BitBlt?; 这是DirectX解决方案等......并且一次又一次地发布。



感谢VB.NET,C#甚至C / C ++语言的解决方案,但这并不重要,重要的是一个概念和一组API调用。



我将不胜感激任何帮助:)





提前谢谢,Xson


That was another problem I was facing. The standard GetWindowRect function for some windows returned wrong results (ex. Skype window), because of Aero glass pixel padding Link (new window/tab).
I created GetAeroRect function that uses DwmGetWindowAttribute API, and it is working for now (haven't noticed wrong results)


So, that is it. I'm really, really sorry for grammar mistakes and for the very big question. But I haven't no choice, I want to post a crystal clear question, don't want to get questions like 'Have you tried PrintWindow?'; 'How you tried BitBlt?'; 'This is DirectX solution' etc... and to post again and again.

Solution in VB.NET, C#, or even C/C++ language is appreciated, but that is not important, important is a concept and set of API calls.

I will appreciate any help :)


Thanks in advance, Xson

推荐答案

解决方案很简单。将您的代码放在适当的case语句中。



The solution is simple. Put your code within the appropriate case statement.

//To obtain the position coordinates in screen coordinates, use the following code:

xPos = GET_X_LPARAM(lParam);    // horizontal position 
yPos = GET_Y_LPARAM(lParam);    // vertical position



     CASE WM_SYSCOMMAND:
     {
	switch(WMNUM)
	{
	case SC_MINIMIZE:
				
		
		
		
		break;
	case SC_MAXIMIZE:
		
		
		
		
		break;
	case SC_SIZE:
		
		
		
		
		break;
	case SC_RESTORE:
		
		
		
		
		break;
	case SC_MOVE:
		
		
		
		
		break;
	case SC_CLOSE:
		
		
		
		
		break;
	default:
	}

     }


这篇关于如何捕获(Aero)窗口(所有状态)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆