News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Screen Capture not using the clipboard.

Started by hutch--, June 18, 2020, 03:45:16 PM

Previous topic - Next topic

hutch--

I got tired of trying to fix exceptions when a rogue app kept leaving the clipboard locked so I used a different technique, a direct BitBlt() from the screen to a compatible bitmap. This is in module form to put into the library.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include64\masm64rt.inc

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    LOCAL hBmp  :QWORD

    GdiPlusBegin                                                    ; initialise GDIPlus

    mov hBmp, rvcall(ScreenCapture)

  ; ||||||||||||||||||||||||||||||||||||||||||

    rcall Gdip_Save_JPG,hBmp,"capture.jpg",100                      ; save it as a JPG

  ; ||||||||||||||||||||||||||||||||||||||||||

    invoke MessageBox,0,"'capture.jpg' written to disk", \
                        " File Saved",MB_ICONINFORMATION

    rcall DeleteObject,hBmp                                         ; delete object after use

    GdiPlusEnd                                                      ; GdiPlus cleanup

    .exit

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

ScreenCapture proc

    LOCAL dDC   :QWORD
    LOCAL cDC   :QWORD
    LOCAL hBmp  :QWORD
    LOCAL hDesk :QWORD
    LOCAL hOld  :QWORD
    LOCAL wScrn :QWORD
    LOCAL hScrn :QWORD
    LOCAL ps    :PAINTSTRUCT

    mov wScrn, rvcall(GetSystemMetrics,SM_CXSCREEN)                 ; get full screen size
    mov hScrn, rvcall(GetSystemMetrics,SM_CYSCREEN)

    mov hDesk, rvcall(GetDesktopWindow)                             ; get desktop window handle
    rcall BeginPaint,hDesk,ptr$(ps)
    mov dDC, rvcall(GetDC,hDesk)                                    ; get desktop DC

    mov hBmp, rvcall(CreateCompatibleBitmap,dDC,wScrn,hScrn)        ; create a compatible bitmap
    mov cDC, rvcall(CreateCompatibleDC,dDC)                         ; create a compatible DC
    mov hOld, rvcall(SelectObject,cDC,hBmp)                         ; select BMP into compatible DC

    invoke BitBlt,cDC,0,0,wScrn,hScrn,dDC,0,0,SRCCOPY               ; blit screen to bitmap

    rcall SelectObject,cDC,hOld                                     ; re-select the old object
    rcall DeleteDC,cDC                                              ; release CompatibleDC
    rcall ReleaseDC,hDesk,dDC                                       ; release desktop DC

    rcall EndPaint,hDesk,ptr$(ps)

    mov rax, hBmp                                                   ; return the bitmap handle

    ret

ScreenCapture endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

felipe

Looks like you are very good at structuring the code hutch  :thup:. I'm curious why you decided to name the rvcall macro like that? (i mean what the rv stands for?)  :icon_idea:

hutch--

Hi felipe,

The "rcall" macro is purely a register call where "rvcall" is a register only return value call. The two macros are to take advantage of the 64 bit FASTCALL that uses the first 4 registers to reduce stack overhead. They are both wrappers for the "register_call" macro and differ only in the return value. They are simple and fast but limited to 4 args which must write directly to a 64 bit register.

For procedures that have more than 4 arguments and for a more tolerant and flexible method of calling procedures there are two main macros, "invoke" and "rv" that were both used in the 32 bit version of MASM and they are just wrappers for the "procedure_call" macro.

The wrapper technique for both base macros is to give greater flexibility in naming rather than have particular values locked in like it was in the 32 bit version of MASM.

felipe

Thanks for the explanation  :thup:. I just tested the program and worked fine  :thumbsup:.

daydreamer

my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

hutch--

The clipboard is the last remnant of the fundamental problems inherent with the software multi-tasking that 16 bit Windows used. One rogue app could take down other apps and the operating system. On 64 bit Windows it won't take down the OS but it can lock up the clipboard so other apps cannot use it. Pressing Prnt-Screen a couple of time tends to fix it but often you have to reboot the OS to get the clipboard to work again.

This technique bypasses the clipboard and just does a BitBlt directly from the desktop to a predefined buffer and its faster as well.

Vortex


hutch--

I have been having a ton of PHUN trying to get a consistent window capture working. Its a toss between getting the keyboard VK_SNAPSHOT working reliably or directly blitting the window content to a compatible bitmap and both have their problems. To set the focus of the window to copy I use WindowFromPoint() but it is broken and performs like ChildWindowFromPoint() which is not exactly what you need in this context as it can get a child window on a main window instead of only the main window.

The next problem is GetWindowRect() grabs a wider area than just the boundaries of the window and you get a left, bottom and right area around the window as well which renders the technique useless.

The keyboard technique produces a better result but only when it works. The key combination CTRL ALT PrintScreen on this version of Win10 64 works fine at capturing a focus window but emulating this key combination only works most of the time and in particular it fails on a regular basis with the old Winfile.exe and is not reliable on the old Winhelp engine.

I have attached the current binary and would appreciate anyone who has the time to test it. It runs OK on my Win7 64 and Win10 64.

This is the screen capture algo that works fine but grabs a larger area than the target window.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

CaptureWindow proc xWin:QWORD

    LOCAL dDC   :QWORD
    LOCAL cDC   :QWORD
    LOCAL hBmp  :QWORD
    LOCAL hDesk :QWORD
    LOCAL hOld  :QWORD
    LOCAL wScrn :QWORD
    LOCAL hScrn :QWORD
    LOCAL ps    :PAINTSTRUCT
    LOCAL rct   :RECT

    rcall GetWindowRect,xWin,ptr$(rct)

    mov eax, rct.right
    sub eax, rct.left
    mov wScrn, rax

    mov eax, rct.bottom
    sub eax, rct.top
    mov hScrn, rax

    mov hDesk, rvcall(GetDesktopWindow)                             ; get desktop window handle
    rcall BeginPaint,hDesk,ptr$(ps)
    mov dDC, rvcall(GetDC,hDesk)                                    ; get desktop DC

    mov hBmp, rvcall(CreateCompatibleBitmap,dDC,wScrn,hScrn)        ; create a compatible bitmap
    mov cDC, rvcall(CreateCompatibleDC,dDC)                         ; create a compatible DC
    mov hOld, rvcall(SelectObject,cDC,hBmp)                         ; select BMP into compatible DC

    invoke BitBlt,cDC,0,0,wScrn,hScrn,dDC,rct.left,rct.top,SRCCOPY  ; blit window to bitmap

    rcall SelectObject,cDC,hOld                                     ; re-select the old object
    rcall DeleteDC,cDC                                              ; release CompatibleDC
    rcall ReleaseDC,hDesk,dDC                                       ; release desktop DC

    rcall EndPaint,hDesk,ptr$(ps)

    mov rax, hBmp                                                   ; return the bitmap handle

    ret

CaptureWindow endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

Siekmanski

Creative coders use backward thinking techniques as a strategy.

hutch--

Hi Marinus,

The screen capture works fine, its the window capture that I am having problems with. If you have time to test it, click the camera toolbar icon, then click in the client area and drag the mouse to another window and see if it captures it.

This last capacity has been more hassle than you can imagine, works under some conditions but not others.

TouEnMasm


On windows 10 the windows capture work.... with apllications who don't use the screen capture.
Fa is a musical note to play with CL

jj2007

Quote from: hutch-- on June 25, 2020, 06:10:41 PMGetWindowRect() grabs a wider area than just the boundaries of the window

Weird. How is that possible? How much is the difference to the real dimensions?

hutch--

> Weird. How is that possible? How much is the difference to the real dimensions?

Sad to say yes and the bigger the window, the worse it gets. I think its because WindowFromPoint() is broken and performs like ChildWindowFromPoint(). This has wasted an enormous amount of time so I went back to the Clipboard and just used WindowFromPoint() to get the handle of the window to be copied and set it as the active window while performing the capture. I even coded a test piece in 32 bit but the effect was the same.

Interestingly enough the manual CTRL ALT PrintScreen key combination when done manually works every time so there is something happening that is not well known. To make it even stranger, if I start the app from Winfile.exe it all works but if I run the app from the desktop, it fails on some windows.

I imagine there are some security reasons for this type of inter app activity, its just that it is not documented anywhere so its all experimentation.

hutch--

I just found yet another standard key combination, left side US keyboard SHIFT, Microsoft key and S gives you multiple options at screen, window and freestyle capture.

TouEnMasm


It's also a tool "Snipping Tool" in the task bar (start button)
Fa is a musical note to play with CL