Jump to content
Sign in to follow this  
Zedna

Get control screenshot as bitmap

Recommended Posts

Zedna

Purpose is to get bitmap screenshot of nonstandard statusbar from another application and later compare it with saved bitmap to see state of application.

Now I have working script but only if I capture bitmap (and save it as BMP file) from my own AutoIt's GUI control (StatusBar):

#include <GUIConstants.au3>
#include <GDIPlus.au3>
#Include <WinAPI.au3>
#include <GUIStatusBar.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StatusBarConstants.au3>
#include <WindowsConstants.au3>

$Form1_1 = GUICreate("Form1", 593, 453, 193, 115)
$StatusBar1 = _GUICtrlStatusBar_Create($Form1_1)
_GUICtrlStatusBar_SetSimple($StatusBar1)
_GUICtrlStatusBar_SetText($StatusBar1, "Optimizing F:\ks\sybaz7\az-los.pbl ...")
$MyButton1 = GUICtrlCreateButton("Get Status as image", 224, 176, 140, 30, 0)
GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $MyButton1
            GetStatusImage()
    EndSwitch
WEnd


Func GetStatusImage()
$hWnd = ControlGetHandle("Form1","","msctls_statusbar321")
$pos = ControlGetPos("Form1","","msctls_statusbar321")

_GDIPlus_StartUp()
$Width = $pos[2]
$Height = $pos[3]

;~ MsgBox(0,'Image size', $Width & 'x' & $Height)

$hDC = _WinAPI_GetDC($hWnd)
$memDC = _WinAPI_CreateCompatibleDC($hDC)
$memBmp = _WinAPI_CreateCompatibleBitmap($hDC, $Width, $Height)
_WinAPI_SelectObject ($memDC, $memBmp)
;~ Func _WinAPI_BitBlt($hDestDC, $iXDest, $iYDest, $iWidth, $iHeight, $hSrcDC, $iXSrc, $iYSrc, $iROP)
_WinAPI_BitBlt($memDC, 0, 0, $Width, $Height, $hDC, 0, 0, $SRCCOPY)

$hImage = _GDIPlus_BitmapCreateFromHBITMAP ($memBmp)
_GDIPlus_ImageSaveToFile($hImage, 'status.bmp')
    _GDIPlus_ImageDispose ($hImage)
_WinAPI_ReleaseDC($hWnd, $hDC)
_WinAPI_DeleteDC($memDC)
_WinAPI_DeleteObject ($memBmp)

_GDIPlus_ShutDown()
EndFuncoÝ÷ Û`¦Û«z«µ«­¢+Ø¥¹±Õ±ÐíU%
½¹ÍѹÑ̹ÔÌÐì(¥¹±Õ±Ðí%A±Õ̹ÔÌÐì(%¹±Õ±Ðí]¥¹A$¹ÔÌÐì(¥¹±Õ±ÐíU%MÑÑÕÍ  ȹÔÌÐì(¥¹±Õ±Ðí ÕÑѽ¹
½¹ÍѹÑ̹ÔÌÐì(¥¹±Õ±ÐíU%
½¹ÍѹÑÍà¹ÔÌÐì(¥¹±Õ±ÐíMÑÑÕÍ  É
½¹ÍѹÑ̹ÔÌÐì(¥¹±Õ±Ðí]¥¹½ÝÍ
½¹ÍѹÑ̹ÔÌÐì((íøÕ¹ÑMÑÑÕÍ%µ ¤(ÀÌØí¡]¹ô
½¹Ñɽ±Ñ!¹± ÅÕ½Ðí½É´ÄÅÕ½Ðì°ÅÕ½ÐìÅÕ½Ðì°ÅÕ½ÐíµÍѱÍ}ÍÑÑÕÍÈÌÈÄÅÕ½Ðì¤)
½¹Í½±]É¥Ñ ÀÌØí¡]¹¤(ÀÌØíÁ½Ìô
½¹Ñɽ±ÑA½Ì ÅÕ½Ðí½É´ÄÅÕ½Ðì°ÅÕ½ÐìÅÕ½Ðì°ÅÕ½ÐíµÍѱÍ}ÍÑÑÕÍÈÌÈÄÅÕ½Ðì¤()}%A±ÕÍ}MÑÉÑUÀ ¤((ÀÌØí]¥Ñ ôÀÌØíÁ½ÍlÉt(ÀÌØí!¥¡ÐôÀÌØíÁ½ÍlÍt((íø5Í   ½à À°Ìäí%µÍ¥éÌäì°ÀÌØí]¥Ñ µÀìÌäíàÌäìµÀìÀÌØí!¥¡Ð¤((ÀÌØí¡ô}]¥¹A%}Ñ ÀÌØí¡]¹¤(ÀÌØíµµô}]¥¹A%}
ÉÑ
½µÁÑ¥± ÀÌØí¡¤(ÀÌØíµµ  µÀô}]¥¹A%}
ÉÑ
½µÁÑ¥±    ¥ÑµÀ ÀÌØí¡°ÀÌØí]¥Ñ °ÀÌØí!¥¡Ð¤)}]¥¹A%}M±Ñ=©Ð ÀÌØíµµ°ÀÌØíµµ   µÀ¤(íøÕ¹}]¥¹A%}    ¥Ñ    ±Ð ÀÌØí¡ÍÑ°ÀÌØí¥aÍаÀÌØí¥eÍаÀÌØí¥]¥Ñ °ÀÌØí¥!¥¡Ð°ÀÌØí¡MÉ°ÀÌØí¥aMÉ°ÀÌØí¥eMÉ°ÀÌØí¥I=)}]¥¹A%}    ¥Ñ    ±Ð ÀÌØíµµ°À°À°ÀÌØí]¥Ñ °ÀÌØí!¥¡Ð°ÀÌØí¡°À°À°ÀÌØíMI

=Ad¤((ÀÌØí¡%µô}%A±ÕÍ}    ¥ÑµÁ
ÉÑɽµ! %Q5@ ÀÌØíµµ   µÀ¤)}%A±ÕÍ}%µMÙQ½¥± ÀÌØí¡%µ°ÌäíÍÑÑÕÌȹµÀÌäì¤(%}%A±ÕÍ}%µ¥ÍÁ½Í ÀÌØí¡%µ¤)}]¥¹A%}I±Í ÀÌØí¡]¹°ÀÌØí¡¤)}]¥¹A%}±Ñ ÀÌØíµµ¤)}]¥¹A%}±Ñ=©Ð ÀÌØíµµ µÀ¤()}%A±ÕÍ}M¡Õѽݸ ¤(íø¹Õ¹

Here is screenshot from my first working example:

Can somebody help me with this weird behaviour?

status.bmp

Share this post


Link to post
Share on other sites
smashly

Hi,

The window needs to be active or in view from what I can see..

Add

WinActivate("Form1")
to the top of "2) Capture part" of the code and it works like it should.

Cheers

Share this post


Link to post
Share on other sites
Zedna

Hi,

The window needs to be active or in view from what I can see..

Add

WinActivate("Form1")
to the top of "2) Capture part" of the code and it works like it should.

Cheers

OK. Thanks for the answer smashly.

In my original script I tested MouseGetCursor() = 15 in While loop so it was dependent on active status too.

So if somebody switched to another application cursor (hourglass) changed and my logic was gone.

I'm rewriting my script to check some inner states inside my target application so it will not be dependent on active status.

I thought this will work also on non-active windows/controls.

So now new question:

How can I do that (bitmap screenshot of control) also with non-active window (it's control)?

AutoIt can do such things also with non-active/minimized windows as far as I know.

What's the trick?

Share this post


Link to post
Share on other sites
Zedna

I discovered the

WinActivate("Form1","")
WinWaitActive("Form1","")

must be called before (not after) BitBlt API call.

So problem is in BitBlt API. It needs to have active windows.

But on MSDN I see no note about such behaviour/limitation :)

http://msdn.microsoft.com/en-us/library/ms532278(VS.85).aspx

The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context.

Edited by Zedna

Share this post


Link to post
Share on other sites
smashly

I'm not sure as of yet how to get an image of a window/control that's not showing.

I know it's not what you want to hear or be asked, but can't you use ControlGetText() instead?

At least it works on minimized and non focused windows.

Share this post


Link to post
Share on other sites
smashly

In regards to the msdn link you posted, it's sorta whack that it states in the dwRop descriptions...

CAPTUREBLT Windows 98/Me, Windows 2000/XP: Includes any windows that are layered on top of your window in the resulting image. By default, the image only contains your window. Note that this generally cannot be used for printing device contexts.

So the default isn't really working as a default then is it?

Share this post


Link to post
Share on other sites
Zedna

I know it's not what you want to hear or be asked, but can't you use ControlGetText() instead?

At least it works on minimized and non focused windows.

Really No.

My target application is PowerBuilder and it uses non-standard StatusBar control (ClassName PBHELP801) and I can't see any text from it in Au3Info tool.

So I really can't use standard controls' functions.

Share this post


Link to post
Share on other sites
Siao

Yea, the subject was discussed before http://www.autoitscript.com/forum/index.php?showtopic=55564 and the same article quoted.

All the kiddies around here probably would be overjoyed, as this would be kind of a breakthrough moment in game botting with AutoIt. And therefore I'm not sure if it's really good idea.


"be smart, drink your wine"

Share this post


Link to post
Share on other sites
Zedna

I wasn't successfull :)

I replaced

_WinAPI_BitBlt($memDC, 0, 0, $Width, $Height, $hDC, 0, 0, $SRCCOPY)

by

$ret = _SendMessage($hWnd, $WM_PRINT, $memDC,  BitOR($PRF_CHILDREN , $PRF_CLIENT, $PRF_NONCLIENT))

I tested all combinations of PRF constants:

Const $WM_PRINT = 0x317
Const $PRF_CLIENT = 0x4  ; Draw the window's client area.
Const $PRF_NONCLIENT = 0x2
Const $PRF_CHILDREN = 0x10; Draw all visible child windows.
Const $PRF_OWNED = 0x20  ; Draw all owned windows.

But resulting bitmap was always black. It was black also if I commented WM_PRINT line.

I noticed on MSDN at WM_PAINT:

http://msdn.microsoft.com/en-us/library/ms534901(VS.85).aspx

The WM_PAINT message is generated by the system and should not be sent by an application. To force a window to draw into a specific device context, use the WM_PRINT or WM_PRINTCLIENT message. Note that this requires the target window to support the WM_PRINTCLIENT message. Most common controls support the WM_PRINTCLIENT message.

So if somebody can tell me what else must be done to do the trick I will be glad. Edited by Zedna

Share this post


Link to post
Share on other sites
martin

I'm curious why but now it works (also previous code):

$ret = _SendMessage($hWnd, $WM_PRINT, $memDC, BitOR($PRF_CHILDREN , $PRF_CLIENT, $PRF_NONCLIENT, $PRF_ERASEBKGND ))

thanks ptrex - his post is here:

http://www.autoitscript.com/forum/index.ph...st&p=568428

I cannot get anything but a black area if I use $PRF_CLIENT. If I add a menu then the menu appears in the jpg but the client area, apart from the menu, is black and no controls are shown. How do you do that? Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites
Zedna

I cannot get anything but a black area if I use $PRF_CLIENT. If I add a menu then the menu appears in the jpg but the client area, apart from the menu, is black and no controls are shown. How do you do that?

It works for me on WIN98.

Tomorrow I will test it also on WINXP ...

EDIT: On WINXP it really doesn't work (only WIN98). So problem still not solved ;)

Edited by Zedna

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×