• Print

Author Topic: Re: SMcNeill: Screen capture (discussion)  (Read 478 times)

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: SMcNeill: Screen capture (discussion)
« on: November 28, 2012, 11:33:35 PM »
Just discussion at this point.

Quote from: SMcNeill on November 28, 2012, 02:18:16 PM
Could someone convert this C# to QB64?   It's a nice little snip it that allows alt-print screen to save a windowed screenshot to file.  My C is just too weak to make the needed swap ovet to something that would be QB64able.

Code: [Select]
Here is something to start to capture and save to a file. You will just need to hook the key "Print screen".

using System;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public class CaptureScreen
{

static public void Main(string[] args)
{

try
{
Bitmap capture = CaptureScreen.GetDesktopImage();
string file = Path.Combine(Environment.CurrentDirectory, "screen.gif");
ImageFormat format = ImageFormat.Gif;
capture.Save(file, format);
}
catch (Exception e)
{
Console.WriteLine(e);
}

}

public static Bitmap GetDesktopImage()
{
WIN32_API.SIZE size;

IntPtr hDC = WIN32_API.GetDC(WIN32_API.GetDesktopWindow());
IntPtr hMemDC = WIN32_API.CreateCompatibleDC(hDC);

size.cx = WIN32_API.GetSystemMetrics(WIN32_API.SM_CXSCREEN);
size.cy = WIN32_API.GetSystemMetrics(WIN32_API.SM_CYSCREEN);

m_HBitmap = WIN32_API.CreateCompatibleBitmap(hDC, size.cx, size.cy);

if (m_HBitmap!=IntPtr.Zero)
{
IntPtr hOld = (IntPtr) WIN32_API.SelectObject(hMemDC, m_HBitmap);
WIN32_API.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, WIN32_API.SRCCOPY);
WIN32_API.SelectObject(hMemDC, hOld);
WIN32_API.DeleteDC(hMemDC);
WIN32_API.ReleaseDC(WIN32_API.GetDesktopWindow(), hDC);
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
return null;
}

protected static IntPtr m_HBitmap;
}

public class WIN32_API
{
public struct SIZE
{
public int cx;
public int cy;
}
public  const int SRCCOPY = 13369376;
public  const int SM_CXSCREEN=0;
public  const int SM_CYSCREEN=1;

[DllImport("gdi32.dll",EntryPoint="DeleteDC")]
public static extern IntPtr DeleteDC(IntPtr hDc);

[DllImport("gdi32.dll",EntryPoint="DeleteObject")]
public static extern IntPtr DeleteObject(IntPtr hDc);

[DllImport("gdi32.dll",EntryPoint="BitBlt")]
public static extern bool BitBlt(IntPtr hdcDest,int xDest,int yDest,int wDest,int hDest,IntPtr hdcSource,int xSrc,int ySrc,int RasterOp);

[DllImport ("gdi32.dll",EntryPoint="CreateCompatibleBitmap")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

[DllImport ("gdi32.dll",EntryPoint="CreateCompatibleDC")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

[DllImport ("gdi32.dll",EntryPoint="SelectObject")]
public static extern IntPtr SelectObject(IntPtr hdc,IntPtr bmp);

[DllImport("user32.dll", EntryPoint="GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();

[DllImport("user32.dll",EntryPoint="GetDC")]
public static extern IntPtr GetDC(IntPtr ptr);

[DllImport("user32.dll",EntryPoint="GetSystemMetrics")]
public static extern int GetSystemMetrics(int abc);

[DllImport("user32.dll",EntryPoint="GetWindowDC")]
public static extern IntPtr GetWindowDC(Int32 ptr);

[DllImport("user32.dll",EntryPoint="ReleaseDC")]
public static extern IntPtr ReleaseDC(IntPtr hWnd,IntPtr hDc);
}


Code taken from: http://stackoverflow.com/questions/158151/how-can-i-save-a-screenshot-directly-to-a-file-in-windows

Interesting.

A few quick observations: That's just the code to capture the image. The code to hook the key was given separately.

The Win32 API stuff should be very doable from QB64, but I suspect that there might be some .Net stuff in there too. For example, I suspect that the "Bitmap" class with its "Save" method is likely .Net.

For the record, this is way outside of my current comfort zone. I've spent a fair amount of time in the past trying to make sense of the MSDN library documentation for GDI, but things like Device Contexts and the GDI concept of Bitmaps are still confusing to me. (I have purchased, among other books, Charles Petzold's "Programming Windows, 5th ed." (It is not as up to date as Jeffrey Richter & Christophe Nasarre's "Windows Via C/C++, 5th ed.", but the Petzold book has much more of a GUI focus, whereas the Richter book has more of a System Services focus.)  It is a huge book, and I have not properly studied it yet.) I have meant to learn GDI well enough to demonstrate loading a bitmap resource from an EXE and displaying it. So far, the best that I've done with GDI is to draw a pixel on a console window, which then gets erased when the window gets repainted. I am still on the wrong side of the GDI learning curve.

Anyway, I'll look into seeing what I can do with this over the coming days. I don't promise anything.

Regards,
Michael
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #1 on: November 29, 2012, 01:43:07 AM »
Thanks Michael.   I thought this would be a nice plus for QB64 if one could convert it over -- from what I was reading, it should allow for a screen capture, and then a save into multiple formats (jpg, png, bmp, maybe others), would could really expand the abilities of QB64.  It's nice being able to screen grab to a bmp, but personally I find jpg or png much more useful usually. 
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

Mrwhy

  • Hero Member
  • *****
  • Posts: 2893
  • My Dad called me Mr Why when I was 5.
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #2 on: November 29, 2012, 03:06:28 AM »
This is much needed anmd would be very useful



RhoSigma

  • Jr. Member
  • **
  • Posts: 75
  • 4 * 1.0079 = 4.0026
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #3 on: November 29, 2012, 04:08:43 AM »
Hi,

MS Windows already support this, press CTRL-PrintScr to snapshot the entire screen or ALT-PrintScr to capture just the active window, both copy the images to the clipboard, now just start a paint program of your choice and insert the image. Then you can save it in any format the paint program supports.

Regards
Download archives of my QB64 stuff:
Polygon functions: http://rhosigma-cw.net/down/GfxDemos.zip
Screen savers: http://rhosigma-cw.net/down/ScrSavers.zip
Libraries collection: http://rhosigma-cw.net/down/QB64Library.zip (extract into the QB64 folder, a new sub-folder "QB64Library" is created)

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #4 on: November 29, 2012, 05:39:25 AM »
Hi,

MS Windows already support this, press CTRL-PrintScr to snapshot the entire screen or ALT-PrintScr to capture just the active window, both copy the images to the clipboard, now just start a paint program of your choice and insert the image. Then you can save it in any format the paint program supports.

Regards

Aye, but the code above bypasses the need to open a paint program and saves directly to disk.  At least that's how I understand it's supposed to work... :)
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #5 on: November 29, 2012, 03:09:57 PM »
A quick question for you Michael:  What I posted was the code to capture the image.  The other code generates the key hook.  Couldn't QB64 use the existing ON KEY set up to avoid the need to rewrite the key hook, leaving the main conversion only needing to be the capture code itself?  It might not be as complex as it originally sounded, if ONKEY can work with it.:)
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

SkyCharger001

  • Hero Member
  • *****
  • Posts: 1594
Re: SMcNeill: Screen capture (discussion)
« Reply #6 on: November 29, 2012, 03:17:50 PM »
WIP
Code: [Select]
CLS
PRINT "OK"
LOCATE 24, 1: PRINT "OK";
SLEEP
bg = _SCREENIMAGE
border = 6 'adjust to twice the size of your borders
bar = 18 'adjust to the size of your title-bars
x = (_WIDTH(0) * 8) + border
y = (_HEIGHT(0) * 16) + bar + border+1
sx = _SCREENX
sy = _SCREENY
fg = _NEWIMAGE(x, y, 32)
_PUTIMAGE , bg, fg, (sx, sy)-((sx + x) - 1, (sy + y) - 1)
SCREEN fg
if you want to capture ANY window then you need to retrieve it's size and position AND bring it to the front immediately before calling _screenimage. (don't know how to do it though.)

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #7 on: November 29, 2012, 06:40:51 PM »
Quote from: SMcNeill on November 29, 2012, 03:09:57 PM
A quick question for you Michael:  What I posted was the code to capture the image.  The other code generates the key hook.  Couldn't QB64 use the existing ON KEY set up to avoid the need to rewrite the key hook, leaving the main conversion only needing to be the capture code itself?  It might not be as complex as it originally sounded, if ONKEY can work with it.:)

You would probably know that better than I would. I almost never use ON KEY. Does ON KEY work for key presses that are sent to other programs? That is, if the QB64 program is running in the background, and you have something else running in the foreground, ON KEY shouldn't be trapping those keypresses, should it?

You're wanting this to work even if the QB64 program is not in the foreground, right?

I was thinking about GetAsyncKeyState, but it would be unreliable.

Something could be done with RegisterHotKey, but your thread would have to process messages. Also, I think that there might be a delay between the key press, and when the thread gets around to reacting. I'm thinking that, given the preemptively multitasking nature of Windows, there would always be a potential delay with any method.)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646309%28v=vs.85%29.aspx

I'm of the impression that RegisterHotKey is significantly less intrusive than SetWindowsHookEx.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644985%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644959%28v=vs.85%29.aspx

You'll see from reading the Remarks that it would require you to load a DLL into other processes.

Quote
A global hook procedure can be called in the context of any application in the same desktop as the calling thread, so the procedure must be in a separate DLL module.

Quote
Note   You should use global hooks only for debugging purposes; otherwise, you should avoid them. Global hooks hurt system performance and cause conflicts with other applications that implement the same type of global hook.



On a separate note, I'm not sure whether GDI works directly with PNG and JPEG. You might need some other library for the conversion.

P.S. Thanks to SkyCharger001:
http://www.qb64.net/wiki/index.php?title=SCREENIMAGE

QB64 already has _SCREENIMAGE. Why do you need to mess with GDI?

P.S. I could be very mistaken, but I suspect that the ImageFormat stuff in the example is .Net. Maybe it's Win32, but I suspect not GDI.
http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.aspx
http://msdn.microsoft.com/en-us/library/9t4syfhh.aspx

Regards,
Michael
« Last Edit: November 29, 2012, 06:57:42 PM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #8 on: November 29, 2012, 08:19:37 PM »
The problem QB64 has is in saving a screen capture to disk.  _SCREENIMAGE gives the current image as a handle, but it doesn't allow for a quick save to disk.   

ON KEY only works if a QB64 program is in the foreground, so one couldn't use it to take a background screen shot (but it could be used to take a program screen shot).

Using SCREENIMAGE to capture the desktop image, then swapping to it as a screen QB64 could "sidestep" to do an image capture.

I was just hoping the C routine would allow for an easy way to save the images to the desktop as jpg, gif, or png files. 
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #9 on: November 30, 2012, 12:10:53 AM »
There is the Windows Imaging Component (WIC). It provides a Component Object Model (COM) interface. However, as far as I can tell, it requires Windows XP SP2 with .Net 3, or Windows Vista or later.
http://msdn.microsoft.com/en-us/library/ee719654%28v=vs.85%29.aspx
COM is usable from QB64, but is somewhat cumbersome. ( http://www.qb64.net/forum/index.php?topic=5613.0 )

QB64 SDL for Windows comes with libpng12-0.dll and jpeg.dll. I believe that these come from:
http://gnuwin32.sourceforge.net/packages/libpng.htm
http://gnuwin32.sourceforge.net/packages/jpeg.htm

The home of libpng is:
http://www.libpng.org/pub/png/libpng.html
Note that libpng 1.2.37 is an old version, and some of the vulnerability warnings might apply.
The documentation for libpng1.2.5 is:
http://www.libpng.org/pub/png/libpng-1.2.5-manual.html

Given that QB64 already has _LOADIMAGE, I think it might be reasonable for QB64 to get a _SAVEIMAGE with the appropriate functionality.

Regards,
Michael
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

Clippy

  • Hero Member
  • *****
  • Posts: 16439
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #10 on: November 30, 2012, 01:30:09 PM »
Why not just use _SCREENIMAGE and convert to bitmaps with SAVEIMAGE?
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #11 on: December 12, 2012, 03:25:13 PM »
Here is an example of using RegisterHotKey to make Shift+A a global hot key:

Code: [Select]
'public domain

CONST MOD_SHIFT = 4
CONST WM_HOTKEY = &H0312
CONST PM_REMOVE = 1
CONST WAIT_FAILED = -1
CONST QS_ALLEVENTS = &H04BF

DECLARE DYNAMIC LIBRARY "kernel32"
 FUNCTION GetLastError~& ()
END DECLARE

DECLARE DYNAMIC LIBRARY "user32"
 FUNCTION RegisterHotKey& (BYVAL hWnd~%&, BYVAL id&, BYVAL fsModifiers~&, BYVAL vk~&)
 FUNCTION UnregisterHotKey& (BYVAL hWnd~%&, BYVAL id&)
 FUNCTION GetMessageW& (BYVAL lpMsg~%&, BYVAL hWnd~%&, BYVAL wMsgFilterMin~&, BYVAL wMsgFilterMax~&)
 FUNCTION PeekMessageW& (BYVAL lpMsg~%&, BYVAL hWnd~%&, BYVAL wMsgFilterMin~&, BYVAL wMsgFilterMax~&, BYVAL wRemoveMsg~&)
 FUNCTION MsgWaitForMultipleObjects~& (BYVAL nCount~&, BYVAL pHandles~%&, BYVAL bWaitAll&, BYVAL dwMilliseconds~&, BYVAL dwWakeMask~&)
END DECLARE

TYPE POINT
 x AS LONG
 y AS LONG
END TYPE

TYPE MSG
 hwnd AS _UNSIGNED _OFFSET
 message AS _UNSIGNED LONG
 wParam AS _UNSIGNED _OFFSET
 lParam AS _OFFSET
 time AS _UNSIGNED LONG
 pt AS POINT
END TYPE

DIM bRet AS LONG
DIM msg AS MSG
DIM n AS _UNSIGNED LONG: n = 0

'Shift + "A"
IF 0 = RegisterHotKey(0, 0, MOD_SHIFT, &H41) THEN PRINT "RegisterHotKey failed. Error: 0x" + LCASE$(HEX$(GetLastError))

IF 0 THEN 'non-zero for GetMessageW example, 0 for PeekMessageW example

 DO
  bRet = GetMessageW(_OFFSET(msg), 0, 0, 0)
  SELECT CASE bRet
   CASE 0: EXIT DO
   CASE -1: PRINT "GetMessageW failed. Error: 0x" + LCASE$(HEX$(GetLastError))
   CASE ELSE: GOSUB gotamessage
  END SELECT
 LOOP UNTIL CHR$(&H1B) = INKEY$

ELSE

 DO
  'use MsgWaitForMultipleObjects instead of _LIMIT
  IF WAIT_FAILED = MsgWaitForMultipleObjects(0, 0, 0, 500, QS_ALLEVENTS) THEN PRINT "MsgWaitForMultipleObjects failed. Error: 0x" + LCASE$(HEX$(GetLastError))
  IF PeekMessageW(_OFFSET(msg), 0, 0, 0, PM_REMOVE) THEN GOSUB gotamessage
 LOOP UNTIL CHR$(&H1B) = INKEY$

END IF

IF 0 = UnregisterHotKey(0, 0) THEN PRINT "UnRegisterHotKey failed. Error: 0x" + LCASE$(HEX$(GetLastError))
END

gotamessage:
PRINT
PRINT "hwnd", "0x" + LCASE$(HEX$(msg.hwnd))
PRINT "message", "0x" + LCASE$(HEX$(msg.message))
PRINT "wParam", "0x" + LCASE$(HEX$(msg.wParam))
PRINT "lParam", "0x" + LCASE$(HEX$(msg.lParam))
PRINT "time", "0x" + LCASE$(HEX$(msg.time))
PRINT "pt", msg.pt.x, msg.pt.y
IF WM_HOTKEY = (&HFFFF~& AND msg.message) THEN
 n = n + 1: _TITLE STR$(n)
 PLAY "mbl16o1a" 'might not be heard due to: http://www.qb64.net/forum/index.php?topic=6246.0
END IF
RETURN

Note that GetMessageW locks up the thread, so a combination of MsgWaitForMultipleObjects and PeekMessageW might be preferable, depending on whether the thread needs to respond to anything other than the hotkey.

SMcNeill, I take it that you have your own PNG encoder now, so that there is no rush to try to use libpng? I might do so anyway, but I'll put a low priority on it.

Regards,
Michael
« Last Edit: December 12, 2012, 03:31:51 PM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #12 on: December 12, 2012, 06:54:10 PM »
Quote from: mcalkins on December 12, 2012, 03:25:13 PM
SMcNeill, I take it that you have your own PNG encoder now, so that there is no rush to try to use libpng? I might do so anyway, but I'll put a low priority on it.

Aye, and with the CRC check working the files we export are now directly importable in QB64 with _LOADIMAGE.  You can put this on the back burner if you want -- I'm going to be busy adding full PNG support to my little routine, and I expect to have it up and going fully by the New Year.  (At least I hope so by then...)

QB64 can now export BMPs with the code from the Wiki, and PNGs from the library I've got up and running.   Maybe next year I'll look into decoding and encoding avi or mp4 files sometime....  ;)

It's always a pain trying to understand a new data structure, read it properly, and then implement it -- but it always gives a rush of satisfaction as all the pieces finally come together.  Thanks to your help, I think I've finally passed the final hurdle for PNG files and QB64.   Many thanks -- I'll email you a cookie for all your hard work and help.   :D
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #13 on: December 12, 2012, 10:13:40 PM »
Code: [Select]
'be advised that this program runs invisibly in the background.
' hotkey code is public domain, by Michael Calkins. http://www.qb64.net/forum/index.php?topic=9979.0
' png export code is by SMcNeill. http://www.qb64.net/forum/index.php?topic=9999.0

$SCREENHIDE

CONST MOD_SHIFT = 4

' these next two constants determine the hotkey.
' the current example is Shift+A
CONST fsModifiers = MOD_SHIFT '   http://msdn.microsoft.com/en-us/library/ms646309(v=vs.85).aspx
CONST vk = &H41 '                 http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx

CONST mode = 0

'mode 0 makes the thread wait for the hotkey. It will not respond to requests
'to terminate, until it gets a hotkey message. Otherwise, Windows will
'consider it to be not responding.
'mode 1 causes the thread to wake up at 1 second intervals. This makes it
'use some CPU time, but it won't appear to be not responding.

'As $SCREENHIDE is used, you won't have an X to click, so you would probably
'use task manager or process explorer to kill it either way. However, mode
'might make a difference in how much it delays your log off/shutdown time.

CONST WM_HOTKEY = &H0312
CONST PM_REMOVE = 1
CONST WAIT_FAILED = -1
CONST QS_ALLEVENTS = &H04BF

CONST ERROR_ALREADY_EXISTS = &HB7
DECLARE DYNAMIC LIBRARY "kernel32"
 FUNCTION GetLastError~& ()
 FUNCTION CreateMutexA~%& (BYVAL lpMutexAttributes~%&, BYVAL bInitialOwner&, BYVAL lpName~%&)
END DECLARE

DECLARE DYNAMIC LIBRARY "user32"
 FUNCTION RegisterHotKey& (BYVAL hWnd~%&, BYVAL id&, BYVAL fsModifiers~&, BYVAL vk~&)
 FUNCTION UnregisterHotKey& (BYVAL hWnd~%&, BYVAL id&)
 FUNCTION GetMessageW& (BYVAL lpMsg~%&, BYVAL hWnd~%&, BYVAL wMsgFilterMin~&, BYVAL wMsgFilterMax~&)
 FUNCTION PeekMessageW& (BYVAL lpMsg~%&, BYVAL hWnd~%&, BYVAL wMsgFilterMin~&, BYVAL wMsgFilterMax~&, BYVAL wRemoveMsg~&)
 FUNCTION MsgWaitForMultipleObjects~& (BYVAL nCount~&, BYVAL pHandles~%&, BYVAL bWaitAll&, BYVAL dwMilliseconds~&, BYVAL dwWakeMask~&)
END DECLARE

TYPE POINT
 x AS LONG
 y AS LONG
END TYPE

TYPE MSG
 hwnd AS _UNSIGNED _OFFSET
 message AS _UNSIGNED LONG
 wParam AS _UNSIGNED _OFFSET
 lParam AS _OFFSET
 time AS _UNSIGNED LONG
 pt AS POINT
END TYPE

'$Include:'Zlib.BI'
DIM h AS LONG
DIM bRet AS LONG
DIM msg AS MSG
DIM t AS STRING

t = "Global\qb64 hotkey demo" + CHR$(0)
IF 0 = CreateMutexA(0, 0, _OFFSET(t)) THEN showerr "CreateMutexA"
IF ERROR_ALREADY_EXISTS = GetLastError THEN showerr "(Multiple instances?) "

IF 0 = RegisterHotKey(0, 0, fsModifiers, vk) THEN showerr "RegisterHotKey"

IF mode THEN

 DO
  bRet = GetMessageW(_OFFSET(msg), 0, 0, 0)
  SELECT CASE bRet
   CASE 0: EXIT DO
   CASE -1: showerr "GetMessageW"
   CASE ELSE: GOSUB gotamessage
  END SELECT
 LOOP

ELSE

 DO
  'use MsgWaitForMultipleObjects instead of _LIMIT
  IF WAIT_FAILED = MsgWaitForMultipleObjects(0, 0, 0, 1000, QS_ALLEVENTS) THEN showerr "MsgWaitForMultipleObjects"
  IF PeekMessageW(_OFFSET(msg), 0, 0, 0, PM_REMOVE) THEN GOSUB gotamessage
 LOOP

END IF

IF 0 = UnregisterHotKey(0, 0) THEN showerr "UnRegisterHotKey"
SYSTEM

gotamessage:
IF WM_HOTKEY = (&HFFFF~& AND msg.message) THEN
 h = _SCREENIMAGE
 SCREEN h
 IF 0 >= PNGExport("delme " + timestamp + ".png", 0) THEN pngerr
 SCREEN 0
 _FREEIMAGE h
END IF
RETURN

SUB showerr (f AS STRING)
_SCREENSHOW
PRINT f; " failed. Error: 0x" + LCASE$(HEX$(GetLastError))
END
END SUB

SUB pngerr
SCREEN 0
_SCREENSHOW
PRINT "Export failed.": END
END
END SUB

FUNCTION timestamp$
DIM d AS STRING * 10
DIM t AS STRING * 8
DO
 d = DATE$
 t = TIME$
LOOP WHILE d <> DATE$ ' try to prevent the situation where midnight is crossed between getting the date$ and time$
MID$(t, 3, 1) = " "
MID$(t, 6, 1) = " "
MID$(d, 3, 1) = " "
timestamp = RIGHT$(d, 4) + " " + LEFT$(d, 5) + "--" + t
END FUNCTION

'$Include:'PngExport.BM'

Regards,
Michael

Edit: changed END to SYSTEM in one place.
changed check for PNGExport error.
« Last Edit: December 13, 2012, 12:51:20 AM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: SMcNeill: Screen capture (discussion)
« Reply #14 on: December 12, 2012, 11:03:58 PM »
I love how one project builds off another -- it's the beauty of open source projects.  :)

One thing of note for the pngerr sub:  at the moment I'm doing very little error checking on the ExportPNG routine.   About the only error code that it'll generate right now is if the ZLib data compression routines fail to work properly.   (And trust me, they failed a lot at the beginning.). Optimally, we shouldn't generate a truly "good" result until we've exported the file, and re-opened the export with no issues.

I'll try and add better error handling to the routine sometime soonish, but for now the only result you'll get is 0 -- Compression Failure.   Since QB64 loads image handles in a negative order, I'll expand with error codes growing upward, so you might want to check for PNGExport (file$, mode) >= 0, instead of just 0 = ....

Nice job btw.  I didn't think anyone would make use of the export routines that quickly!  Good to see others interested in these little projects.  :D


EDIT:

PNGExport Codes for the next update (as I add them):
-1 All should be fine.  We exported our code properly.
 0 Compression Error.  The file may work still, but it may not in all PNG import programs either.  Either way, it's probably unnecessarily large and should be retried for better compression. 
  1 File Already Exists.  You're trying to export out to a file that already exists, and this may cause issues and damage existing data.  Change the filename or kill the old file if wanted, and try again.

Other codes to be added as time allows, and error-handling gets more sophisticated.  ;)
« Last Edit: December 13, 2012, 07:42:10 AM by SMcNeill »
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

  • Print