Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ON ERROR Screen-Capture 4

Status
Not open for further replies.

ramani

Programmer
Mar 15, 2001
4,336
AE
** How to use screen capture as a good tool for error log
1. Add the ON ERROR.. code as given below in the beginning of your Main.PRG
*********************************************************
ON ERROR DO errhand WITH ;
ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO(1)
*********************************************************

2. AT the end of your Main.Prg, add the following .. two procedures..

*********************************************************
** My error handler
PROCEDURE errhand
PARAMETER merror, mess, mess1, mprog, mlineno
LOCAL myMessage, lcAlias
lcALias = ALIAS()
myMessage='Error number: ' + LTRIM(STR(merror))+ CHR(13) ;
+ 'Error message: ' + mess + CHR(13) ;
+ 'Line of code with error: ' + mess1 + CHR(13);
+ 'Line number of error: ' + LTRIM(STR(mlineno)) + CHR(13) ;
+ 'Program with error: ' + mprog
DO shot_screen
WAIT WINDOW myMessage +CHR(13)+CHR(13)+"Press Any Key to Continue"

** Baltmans idea of capturing image in a General Field
SELECT 0
IF !FILE("ErrorLog.DBF")
CREATE TABLE ErrorLog (eDateTime T, UserInfo M, ErrorImg G)
ELSE
USE ErrorLog ALIAS errorLog
ENDIF
SCATTER MEMVAR BLANK
m.eDateTime = DATETIME()
m.UserInfo = ;
"User : "+GETENV("USERNAME")+ CHR(13)+ ;
"Computer :"+ GETENV("ComputerName")+CHR(13)+ ;
"User Profile :"+ GETENV("USERPROFILE")+CHR(13)+ ;
"OS :"+ GETENV("OS") + CHR(13)+ ;
"Alias In Use : " + lcAlias + CHR(13)+ ;
"Error Message..... " + CHR(13)+ myMessage
INSERT INTO ErrorLog FROM MEMVAR

MODIFY General ErrorImg NOWAIT
KEYBOARD '{CTRL+V}'
DOEVENTS

USE IN ErrorLog
IF !EMPTY(lcALias)
SELECT (lcAlias)
ENDIF
RETURN
*********************************************************
PROCEDURE shot_screen
** Microsoft's code
DECLARE INTEGER keybd_event IN Win32API ;
INTEGER, INTEGER, INTEGER, INTEGER
VK_SNAPSHOT = 44 && from the winuser.h
VK_LMENU = 164
KEYEVENTF_KEYUP = 2
KEYEVENTF_EXTENDEDKEY = 1
DOEVENTS
keybd_event( VK_LMENU, 0, KEYEVENTF_EXTENDEDKEY, 0 ) && key down
keybd_event( VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0 )
keybd_event( VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY + KEYEVENTF_KEYUP, 0 )
keybd_event( VK_LMENU, 0, KEYEVENTF_EXTENDEDKEY + KEYEVENTF_KEYUP, 0 )
DOEVENTS
RETURN
*********************************************************
** EOF
*********************************************************

I have been working on this idea when time permits as to how we can save that easily as JPG image, so that the file size is limited. There are alternatives available.
1. Use Office automation (excel or word) - depends on OFFICE software availability.
2. MSPAINT.. looking into tighter code patterns.

Once these objectives are achieved, I will post the whole thing as an FAQ. Baltman has been of immense help in providing the views in a related thread. Appropriate credit to him.

Also, once this concept is completed, I will post another FAQ as to how we can use this for possible documentation screen capture or such possibilities. I have already tried successfully, but the BMP method is extremely space consuming and so holding it for a while. The way to go is very simple..

at the beginning of MAIN.PRG as in step 1 here, add a line
ON KEY LABEL F12 DO myCapture
Add a function..
PROCEDURE MyCapture
DO shot_screen
DO shot_save && and in Shot save open the table and save whatever..

The possibilities are countless.
:)


____________________________________________
ramani - (Subramanian.G) :)
When you ask VFP questions, please add VFP version.
 
Hi ramani,

I'm not sure why, but I can't see the whole screen shot and when I try to click the picture in the general field I get an error. I had been playing around with exporting the picture minus the 599 header bytes, but I can't seem to get a valid BMP out of the FPT.

I had been playing around with a way to automate paint in thread184-700870 as you already know...

I'm sure we'll figure out something [thumbsup2]

Brian
 
ramani

'I have been working on this idea when time permits as to how we can save that easily as JPG image'

Suggest you simply use a freeware command line image converter to convert from .bmp to .jpg, and run it hidden with ShellExecute() or WSH.

One example is topng.exe available at


FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
HI,

Thanks for the input.

There was a silly mistake. The error message window was getting cleared and then the screen capturing was done as per earlier code. Now that stands rectified. This can be tried now.
*********************************************************
** 1. Add the ON ERROR.. code as given below in the beginning of your Main.PRG
*********************************************************
ON ERROR DO errhand WITH ;
ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO(1)
*********************************************************

** 2. AT the end of your Main.Prg, add the following .. two procedures..
*********************************************************
** My error handler
PROCEDURE errhand
PARAMETER merror, mess, mess1, mprog, mlineno
LOCAL myMessage, lcAlias
USE IN SELECT ("ErrorLog")
lcALias = ALIAS()
myMessage='Error number: ' + LTRIM(STR(merror))+ CHR(13) ;
+ 'Error message: ' + mess + CHR(13) ;
+ 'Line of code with error: ' + mess1 + CHR(13);
+ 'Line number of error: ' + LTRIM(STR(mlineno)) + CHR(13) ;
+ 'Program with error: ' + mprog
WAIT WINDOW myMessage +CHR(13)+CHR(13)+"Press Any Key to Continue" NOCLEAR NOWAIT
DO shot_screen
WAIT ""
WAIT CLEAR
** Baltmans idea of capturing image in a General Field
SELECT 0
IF !FILE("ErrorLog.DBF")
CREATE TABLE ErrorLog (eDateTime T, UserInfo M, ErrorImg G)
ELSE
USE ErrorLog ALIAS errorLog
ENDIF
SCATTER MEMVAR BLANK MEMO
m.eDateTime = DATETIME()
m.UserInfo = ;
"User : "+GETENV("USERNAME")+ CHR(13)+ ;
"Computer :"+ GETENV("ComputerName")+CHR(13)+ ;
"User Profile :"+ GETENV("USERPROFILE")+CHR(13)+ ;
"OS :"+ GETENV("OS") + CHR(13)+ ;
"Alias In Use : " + lcAlias + CHR(13)+ ;
"Error Message..... " + CHR(13)+ myMessage
INSERT INTO ErrorLog FROM MEMVAR

MODIFY General ErrorImg NOWAIT
KEYBOARD '{CTRL+V}'
DOEVENTS

USE IN ErrorLog
IF !EMPTY(lcALias)
SELECT (lcAlias)
ENDIF
RETURN
*********************************************************
PROCEDURE shot_screen
** Microsoft's code
DECLARE INTEGER keybd_event IN Win32API ;
INTEGER, INTEGER, INTEGER, INTEGER
VK_SNAPSHOT = 44 && from the winuser.h
VK_LMENU = 164
KEYEVENTF_KEYUP = 2
KEYEVENTF_EXTENDEDKEY = 1
DOEVENTS
keybd_event( VK_LMENU, 0, KEYEVENTF_EXTENDEDKEY, 0 ) && key down
keybd_event( VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0 )
keybd_event( VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY + KEYEVENTF_KEYUP, 0 )
keybd_event( VK_LMENU, 0, KEYEVENTF_EXTENDEDKEY + KEYEVENTF_KEYUP, 0 )
DOEVENTS
RETURN
*********************************************************
*********************************************************
For testing , you can copy the above and save it as
gsError.PRG
Then from command window, type
DO gsError && sets the on error command.
DO 123 && This should generate an error.
USE ErrorLog
BROW && PageDown on Gen field to see image captured
USE to close the file
*********************************************************
I will post this as FAQ soon.

I will look into what Chris said, after trying any possibility of capturing as JPG.

I will work on this, because, it has potential for wider usage. :)

____________________________________________
ramani - (Subramanian.G) :)
When you ask VFP questions, please add VFP version.
 
Baltman

had been playing around with a way to automate paint in Thread184-700870 as you already know...

Here is one way to do it, and if your bitmaps are set to open with MSPaint.

Code:
DO decl

PRIVATE hMemDC, hMemBmp, lnWidth, lnHeight, lnBitsPerPixel,;
	lnBytesPerScan, lcBFileHdr, lcBIHdr, lpBitsArray, lnBitsSize,;
	lcRgbQuad, lnRgbQuadSize, lcBInfo, lnFileSize

STORE "" TO lcBIHdr, lcBInfo, lcRgbQuad
STORE 0 TO hMemDC, hMemBmp, lnWidth, lnHeight, lnFileSize,;
	lnBitsPerPixel, lnBytesPerScan, lnRgbQuadSize, lpBitsArray, lnBitsSize

	= MakeSnapshot()
	= InitBitmapInfo()
	= InitBitsArray()

	#DEFINE DIB_RGB_COLORS   0
	= GetDIBits (hMemDC, hMemBmp, 0, lnHeight, lpBitsArray,;
			@lcBInfo, DIB_RGB_COLORS)
	
	LOCAL lcFilename
	lcFilename = "c:\Temp\myfile.bmp"

	IF bmp2file (lcFilename)
		ACTI SCREEN
		? "File:          ", lcFilename
		? "Size:          ", LTRIM(TRANS(lnFileSize, "999,999,999,999"))
		? "Width:         ", LTRIM(STR(lnWidth)) + " pixels"
		? "Height:        ", LTRIM(STR(lnHeight)) + " pixels"
		? "Bits per pixel:", LTRIM(STR(lnBitsPerPixel))
		
	ENDIF
    =Shellexecute(0,"Open",lcFilename,"","",0)
	= GlobalFree (lpBitsArray)
	= DeleteObject (hMemBmp)
	= DeleteDC (hMemDC)
RETURN  && main 
=Shellexecute(0,"Open",lcFilename,"","",0)
PROCEDURE  InitBitmapInfo()
#DEFINE BI_RGB  0
#DEFINE RGBQUAD_SIZE     4  && RGBQUAD
#DEFINE BHDR_SIZE       40  && BITMAPINFOHEADER

	lnBitsPerPixel = 24
	lnBytesPerScan = lnWidth * 3
	IF Mod(lnBytesPerScan, 4) <> 0
		lnBytesPerScan = lnBytesPerScan + 4 - Mod(lnBytesPerScan, 4)
	ENDIF

	lcBIHdr = num2dword(BHDR_SIZE) + num2dword(lnWidth) +;
		num2dword(lnHeight) + num2word(1) + num2word(lnBitsPerPixel) +;
		num2dword(BI_RGB) + num2dword(0) + num2dword(0) + num2dword(0) +;
		num2dword(0) + num2dword(0)

	IF lnBitsPerPixel <= 8
		lnRgbQuadSize = (2^lnBitsPerPixel) * RGBQUAD_SIZE
		lcRgbQuad = Repli(Chr(0), lnRgbQuadSize)
	ELSE
		lnRgbQuadSize = 0
		lcRgbQuad = &quot;&quot;
	ENDIF

	lcBInfo = lcBIHdr + lcRgbQuad
RETURN

PROCEDURE  InitBitsArray()
#DEFINE GMEM_FIXED   0
	lnBitsSize = lnHeight * lnBytesPerScan
	lpBitsArray = GlobalAlloc (GMEM_FIXED, lnBitsSize)
	= ZeroMemory (lpBitsArray, lnBitsSize)

FUNCTION  bmp2file (lcTargetFile)
#DEFINE GENERIC_WRITE          1073741824  && 0x40000000
#DEFINE FILE_SHARE_WRITE                2
#DEFINE CREATE_ALWAYS                   2
#DEFINE FILE_ATTRIBUTE_NORMAL         128
#DEFINE INVALID_HANDLE_VALUE           -1
#DEFINE BFHDR_SIZE      14  && BITMAPFILEHEADER

	LOCAL hFile, lnOffBits

	lnFileSize = BFHDR_SIZE + BHDR_SIZE + lnRgbQuadSize + lnBitsSize

	lnOffBits = BFHDR_SIZE + BHDR_SIZE + lnRgbQuadSize
	
	lcBFileHdr = &quot;BM&quot; + num2dword(lnFileSize) +;
			num2dword(0) + num2dword(lnOffBits)
	
	hFile = CreateFile (lcTargetFile,;
				GENERIC_WRITE,;
				FILE_SHARE_WRITE, 0,; 
				CREATE_ALWAYS,;
				FILE_ATTRIBUTE_NORMAL, 0) 

	IF hFile <> INVALID_HANDLE_VALUE
		= String2File (hFile, @lcBFileHdr)           && BitmapFileHeader
		= String2File (hFile, @lcBInfo)              && BitmapInfo
		= Ptr2File (hFile, lpBitsArray, lnBitsSize)  && bitmap data
		= CloseHandle (hFile)
		RETURN .T.
	ELSE
		= MessageB (&quot;Unable to create file: &quot; + lcTargetFile)
		RETURN .F.
	ENDIF

PROCEDURE  String2File (hFile, lcBuffer)
	DECLARE INTEGER WriteFile IN kernel32;
		INTEGER hFile, STRING @lpBuffer, INTEGER nBt2Write,;
		INTEGER @lpBtWritten, INTEGER lpOverlapped

	= WriteFile (hFile, @lcBuffer, Len(lcBuffer), 0, 0)
RETURN

PROCEDURE  Ptr2File (hFile, lnPointer, lnBt2Write)
	DECLARE INTEGER WriteFile IN kernel32;
		INTEGER hFile, INTEGER lpBuffer, INTEGER nBt2Write,;
		INTEGER @lpBtWritten, INTEGER lpOverlapped

	= WriteFile (hFile, lnPointer, lnBt2Write, 0, 0)
RETURN
PROCEDURE  MakeSnapshot()
#DEFINE SRCCOPY        13369376
	LOCAL hwnd, hdc, hSavedBitmap

	hwnd = GetFocus()
	hdc = GetWindowDC(hwnd)
	= GetWinRect(hwnd, @lnWidth, @lnHeight)

	hMemDC = CreateCompatibleDC (hdc)
	hMemBmp = CreateCompatibleBitmap (hdc, lnWidth, lnHeight)

	hSavedBitmap = SelectObject (hMemDC, hMemBmp)
	= BitBlt (hMemDC, 0,0, lnWidth,lnHeight, hdc, 0,0, SRCCOPY)
	= SelectObject (hMemDC, hSavedBitmap)
	= ReleaseDC (hwnd, hdc)
RETURN
PROCEDURE  GetWinRect(hwnd, lnWidth, lnHeight)
#DEFINE MAX_DWORD  4294967295  && 0xffffffff
    LOCAL lpRect, lnLeft, lnTop, lnRight, lnBottom
    lpRect = Repli(Chr(0), 16)  
    = GetWindowRect (hwnd, @lpRect)  
    lnLeft   = buf2dword(SUBSTR(lpRect,  1,4))  
    lnTop    = buf2dword(SUBSTR(lpRect,  5,4))  
    lnRight  = buf2dword(SUBSTR(lpRect,  9,4))  
    lnBottom = buf2dword(SUBSTR(lpRect, 13,4))  
    IF lnLeft > lnRight
    	lnLeft = lnLeft - MAX_DWORD
    ENDIF
    IF lnTop > lnBottom
    	lnTop = lnTop - MAX_DWORD
    ENDIF
 
	lnWidth  = lnRight - lnLeft
	lnHeight = lnBottom - lnTop
RETURN
FUNCTION  num2dword (lnValue)
#DEFINE m0       256
#DEFINE m1     65536
#DEFINE m2  16777216
	LOCAL b0, b1, b2, b3
	b3 = Int(lnValue/m2)
	b2 = Int((lnValue - b3*m2)/m1)
	b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
	b0 = Mod(lnValue, m0)
RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)

FUNCTION  num2word (lnValue)
RETURN Chr(MOD(m.lnValue,256)) + CHR(INT(m.lnValue/256))
FUNCTION  buf2dword (lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
	Asc(SUBSTR(lcBuffer, 2,1)) * 256 +;
	Asc(SUBSTR(lcBuffer, 3,1)) * 65536 +;
	Asc(SUBSTR(lcBuffer, 4,1)) * 16777216
FUNCTION  buf2word (lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) + ;
	Asc(SUBSTR(lcBuffer, 2,1)) * 256
PROCEDURE  decl
	DECLARE INTEGER GetDIBits IN gdi32;
		INTEGER hdc, INTEGER hbmp, INTEGER uStartScan,;
		INTEGER cScanLines, INTEGER lpvBits, STRING @lpbi,;
		INTEGER uUsage
	DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER wFlags, INTEGER dwBytes 
	DECLARE INTEGER GetWindowRect IN user32 INTEGER hwnd, STRING @lpRect 
	DECLARE INTEGER SelectObject IN gdi32 INTEGER hdc, INTEGER hObject
	DECLARE INTEGER ReleaseDC IN user32 INTEGER hwnd, INTEGER hdc
	DECLARE INTEGER DeleteDC IN gdi32 INTEGER hdc
	DECLARE INTEGER GetFocus IN user32
	DECLARE INTEGER GetWindowDC IN user32 INTEGER hwnd
    DECLARE INTEGER GlobalFree IN kernel32 INTEGER hMem
	DECLARE INTEGER DeleteObject IN gdi32 INTEGER hObject
	DECLARE INTEGER CreateCompatibleDC IN gdi32 INTEGER hdc
	DECLARE INTEGER CloseHandle IN kernel32 INTEGER hObject

	DECLARE RtlZeroMemory IN kernel32 As ZeroMemory;
		INTEGER dest, INTEGER numBytes

	DECLARE INTEGER CreateCompatibleBitmap IN gdi32;
		INTEGER hdc, INTEGER nWidth, INTEGER nHeight

	DECLARE INTEGER BitBlt IN gdi32;
		INTEGER hDestDC, INTEGER x, INTEGER y,;
		INTEGER nWidth, INTEGER nHeight, INTEGER hSrcDC,;
		INTEGER xSrc, INTEGER ySrc, INTEGER dwRop

	DECLARE INTEGER CreateFile IN kernel32;
		STRING lpFileName, INTEGER dwDesiredAccess,;
		INTEGER dwShareMode, INTEGER lpSecurityAttr,;
		INTEGER dwCreationDisp, INTEGER dwFlagsAndAttrs,;
		INTEGER hTemplateFile
Declare Integer ShellExecute In &quot;Shell32.dll&quot; ;
	INTEGER HWnd, ;
	STRING lpVerb, ;
	STRING lpFile, ;
	STRING lpParameters, ;
	STRING lpDirectory, ;
	LONG nShowCmd
[code]

[sub]Some of this code from [URL unfurl="true"]http://www.news2news.com[/URL][/sub]

[b][i]Mike Gagnon[/i][/b]

[i]If you want to get the best response to a question, please check out FAQ184-2483 first.[/I]
 
ramani and mgagnon,

Certainly expert posts. Stars to the both of you.

Slighthaze = NULL
craig1442@mchsi.com
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
 
Mike,

That is indeed pretty slick and star worthy. It runs very quickly too. Do you know of any additional code that could convert the output into a jpg on thr fly without using Office?

Brian
 
Dear Mike,

That is very very nice.

1. Now I have to change that window capturing to capture entire desktop (Snap_shot to be modified suitably).

2. I think The ShellExecute() line is just straying out by mistake. I have not looked very deeply.

Star worthy (star to you) and alomost almost likely that this will be in my routine with due credit to you. :)

Probably, I will provide different ways to do the thing, based on availability of resources. Baltman's way of doing using office automation, and Mikes above way.

True Foxy ways. Hmmm. I like them all. :)

:)

____________________________________________
ramani - (Subramanian.G) :)
When you ask VFP questions, please add VFP version.
 
Ramani

I think The ShellExecute() line is just straying out by mistake. I have not looked very deeply.

Thank you for the star. Yes you are right the second SHELLEXECUTE() shoudn't be there, I was trying different things to open up paint and I left one there be mistake.
You can also remove the following part since the object of the code is not to determine the size etc of the bitmap generated :
IF bmp2file (lcFilename)
ACTI SCREEN
? &quot;File: &quot;, lcFilename
? &quot;Size: &quot;, LTRIM(TRANS(lnFileSize, &quot;999,999,999,999&quot;))
? &quot;Width: &quot;, LTRIM(STR(lnWidth)) + &quot; pixels&quot;
? &quot;Height: &quot;, LTRIM(STR(lnHeight)) + &quot; pixels&quot;
? &quot;Bits per pixel:&quot;, LTRIM(STR(lnBitsPerPixel))
ENDIF


baltman

Do you know of any additional code that could convert the output into a jpg on thr fly without using Office?

I'm not sure what Office has to do with it, other than showing you the result, but since the code takes a snapshot in 24 bits, just use this line instead:
Code:
lcFilename = &quot;c:\Temp\myfile.jpg&quot;



Mike Gagnon

If you want to get the best response to a question, please check out FAQ184-2483 first.
 
Mike

lcFilename = &quot;c:\Temp\myfile.jpg&quot;

Untested, but the result of that will probably be a .bmp format file with a .jpg extension which will become unreadable by certain graphics editors.

As I read it, ramani wants to convert the .bmp to .jpg by applying 'lossy' compression to the original file and thus reduce the file size?

FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
Hi Mike
Thanks for that. Going thru the thread, you should have 3 stars. Dont know, I made a mistake. Let me try again. :)

Chris. Valid point. I will check also. :)

____________________________________________
ramani - (Subramanian.G) :)
When you ask VFP questions, please add VFP version.
 
Chris

Untested, but the result of that will probably be a .bmp format file with a .jpg extension which will become unreadable by certain graphics editors.

Most likely. Although on my system, the jpg does open with MSpaint, I did noticed that the file size was the same as the bitmap, so I would tend to agree with you that the resulting file has no compression ratio applied to it.

Ramani

Thanks for that. Going thru the thread, you should have 3 stars. Dont know, I made a mistake. Let me try

It seems to be OK now, thank you. And please let me apologize for posting my suggestion in your thread, I didn't notice that your thread was a helpfull hint and I was mostly responding to Baltman, rather then taking away from your our own suggestion.


Mike Gagnon

If you want to get the best response to a question, please check out FAQ184-2483 first.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top