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
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:
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.
Thanks for the explanation :thup:. I just tested the program and worked fine :thumbsup:.
it works :thumbsup:
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.
Hi Hutch,
It works on Windows XP :thumbsup:
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
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Win8.1 x64
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.
On windows 10 the windows capture work.... with apllications who don't use the screen capture.
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?
> 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.
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.
It's also a tool "Snipping Tool" in the task bar (start button)
I have just waded through a Microsoft list of hot keys and does not look like Win7 64 supports it. What a shame.
Quote from: hutch-- on June 25, 2020, 09:17:26 PM
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.
Seems the problem is solved, I checked the main file it failed on, the re-written Winfile.exe and it is classed as a Win7 driver so I set JpgTool.exe to "Run as Adminstrator" and it now captures everything. This nearly drove me NUTZ ! :tongue: