********************************************************************
*  CLASS MxPrintScreen
********************************************************************
*  Copyright:
*      Joe Carrick - 03/07/2000
*
*  Note: This implementation clears the Windows Clipboard.
*        This is necessary to avoid printing the Window continuously.
********************************************************************

#include "Gra.ch"
#include "Xbp.ch"
#include "Appevent.ch"
#include "Common.ch"
#include "MxKeys.ch"
#include "directry.ch"
#include "dll.ch"

#pragma Library( "XppUI2.lib" )

// #define VK_SNAPSHOT 44

CLASS MxPrintScreen FROM Thread

	EXPORTED:
	VAR oClipboard

	INLINE METHOD init()
	::thread:init()
	::oClipboard := XbpClipboard():new():create()
	RETURN

	EXPORTED:
	METHOD execute()
	METHOD atStart()
	METHOD atEnd()

ENDCLASS


METHOD MxPrintScreen:atStart()

	LOCAL aFormats

	::oClipBoard:open()
	aFormats := ::oClipBoard:queryFormats()
	IF AScan( aFormats, XBPCLPBRD_BITMAP ) > 0
		::oClipboard:clear()
	ENDIF
	::oClipBoard:close()

RETURN


METHOD MxPrintScreen:atEnd()

	::oClipboard:destroy()

RETURN


METHOD MxPrintScreen:Execute()

	LOCAL aFormats, oBitmap, aDir
	LOCAL cFileName, dFileDate, cFileTime, nFileTime, cFileDateTime, cCheck
	LOCAL i

	DO WHILE .T.
		aDir := AllWindows( .F. )
		FOR i := 1 TO len(aDir)
			IF alltrim(aDir[i])=="PrintScreen" .AND. setAppWindow():title<>"PrintScreen"
 				::atEnd()
				::quit()
				RETURN
			ENDIF
		NEXT i

      IF GetAsyncKeyState(VK_SNAPSHOT)<>0

			::oClipBoard:open()
			aFormats := ::oClipBoard:queryFormats()
			IF AScan( aFormats, XBPCLPBRD_BITMAP ) > 0
				oBitmap := ::oClipBoard:getBuffer( XBPCLPBRD_BITMAP )

				PrintWindow(oBitmap)

				aDir := directory("ScrnDmp?.bmp")

				IF empty(aDir)
					cFileName := "ScrnDmp1.bmp"
				ELSEIF len(aDir)<9
					cFileName := "ScrnDmp"+alltrim(str(len(aDir)+1))+".bmp"
				ELSE
					// find the oldest file and replace it
					cFileName := aDir[9,F_NAME]
					cFileDateTime := padl(dtos(aDir[9,F_WRITE_DATE]),8,"0") +;
					                 left(time(),2)+substr(time(),4,2)+right(time(),2)
					FOR i := 8 TO 1 STEP -1
						cCheck := padl(dtos(aDir[i,F_WRITE_DATE]),8,"0") +;
					            left(aDir[i,F_WRITE_TIME],2)+substr(aDir[i,F_WRITE_TIME],4,2)+right(aDir[i,F_WRITE_TIME],2)
						IF val(cCheck)<val(cFileDateTime)
							cFileName := aDir[i,F_NAME]
		 					cFileDateTime := cCheck
						ENDIF
					NEXT i
				ENDIF

				IF file(cFileName)
					FErase(cFileName)
				ENDIF

				IF !oBitmap:saveFile(cFileName)
					Msgbox("Couldn't Save Bitmap File "+cFileName)
				ENDIF

				::oClipboard:clear()
			ENDIF
			::oClipBoard:close()
      ENDIF
      Sleep( 20 )

	ENDDO

RETURN



FUNCTION PrintWindow(oBitMap)

	LOCAL oPrinterPS, oSourcePS
	LOCAL aPaperSize, aSize, aPos
	LOCAL oBmp
	LOCAL aRect := {0,0,oBitmap:xsize,oBitmap:ySize}, nWidth, nHeight, nRatio
	LOCAL lRet := .F.

	IF setAppWindow():isderivedFrom("XbpCrt")
		oSourcePS := SetAppWindow()
	ELSE
		oSourcePS := SetAppWindow():lockPS()
	ENDIF
	oPrinterPS := PrntScrnPS()
	IF oPrinterPS<>NIL

		aPaperSize := oPrinterPS:device():paperSize()

		nWidth := aPaperSize[5]-(2*aPaperSize[3])
		nRatio := aRect[4]/aRect[3]
		nHeight := int(nWidth*nRatio)

		aRect[4] := aPaperSize[6]-200
		aRect[2] := aRect[4]-nHeight
		aRect[1] := aPaperSize[3]
		aRect[3] := aRect[1]+nWidth

		oPrinterPS:device():startdoc()

		IF "Windows 9" $ Os() .OR. "Windows XP" $ Os()
			oBitmap:draw(oPrinterPS,aRect)
		ELSEIF "Windows NT" $ Os()
			aSize := SetAppWindow():currentSize()
			aPos  := SetAppWindow():currentPos()
			GraBitBlt( oPrinterPS,;
			           oSourcePS,;
			           aRect,;
			           {aPos[1],aPos[2],aSize[1],aSize[2]},;
			           GRA_BLT_ROP_SRCCOPY,;
			           GRA_BLT_BBO_IGNORE )
		ENDIF
		oPrinterPS:device():enddoc()

		lRet := .T.
		oPrinterPS:destroy()

	ENDIF
	IF !setAppWindow():isderivedFrom("XbpCrt")
		SetAppWindow():unlockPS()
	ENDIF

RETURN lRet



STATIC FUNCTION PrntScrnPS()
	LOCAL oPS, oDC
	LOCAL oFocus := setAppFocus()

	oDC := SetPrinter(.T.,XBPPDLG_MODE_DRIVER,.T.,.T.)
	IF oDC<>NIL
		oPS:=XbpPresSpace():new()
		oPS:Create( oDC, oDC:paperSize(), GRA_PU_LOMETRIC )
	ELSE
		oPS := NIL
	ENDIF

	setAppFocus( oFocus )

RETURN oPS



***********************************************************************************************
* Emulate a PrintScreen or Alt_PrintScreen key press to capture the screen to the clipboard   *
***********************************************************************************************
PROCEDURE Print_Window( nWindow )
	nWindow := iif(empty(nWindow),0,1)	// 0 is entire screen, 1 is active window
	sleep(50)														// Allow popup menus to clear first
	keybd_Event( VK_SNAPSHOT,nWindow,0,0)
RETURN



FUNCTION SetPrinter(lDisplay,nMode,nPrintRange,lPrintToFile,lMark,lCollate,nCopies,aRange)

	LOCAL oDC := XbpPrinter():new(), oPrintDlg
	LOCAL aArray[6], cTitle := "Print", cClass := chr(0)
   LOCAL oWin, aPos

	DEFAULT lDisplay      TO .F.
	DEFAULT nMode         TO XBPPDLG_MODE_DRIVER
	DEFAULT nPrintRange   TO XBPPDLG_PRINT_ALLPAGES
	DEFAULT lPrintToFile  TO .F.
	DEFAULT lMark         TO .F.
	DEFAULT lCollate      TO .F.
	DEFAULT nCopies       TO 1
	DEFAULT aRange        TO {0,0}

	IF empty(oDC:list())
		MsgBox("There are no Printers available on this System")
		RETURN NIL
	ELSEIF len(oDC:list())>1
		lDisplay := .T.
	ELSE
		oDC:create()
	ENDIF
	IF lDisplay
   	aPos := { AppDesktop():currentSize()[1], AppDesktop():currentSize()[2] }
      aPos[1] := (aPos[1]-460)/2
      aPos[2] := (aPos[2]-430)/2
   	oWin := XbpDialog():new():create(AppDesktop(),SetAppWindow(),aPos,{460,430},,.F.)
		oPrintDlg := XbpPrintDialog():new(oWin):create()
		IF nMode<>XBPPDLG_MODE_APPLICATION
			oPrintDlg:mode := XBPPDLG_MODE_DRIVER
		ELSE
			oPrintDlg:mode := nMode
		ENDIF
		oPrintDlg:printRange := nPrintRange
		oPrintDlg:enableMark := lMark
		oPrintDlg:enablePrintToFile := lPrintToFile
		oPrintDlg:enableCollate := lCollate
		oPrintDlg:enableNumCopies := .T.
		oPrintDlg:pageRange := aRange
		oDC := oPrintDlg:display()
      oWin:destroy()
      IF !empty(oDC)
			oDC:cargo := {oPrintDlg:printRange,;
		              oPrintDlg:printToFile,;
		              oPrintDlg:collate,;
		              oPrintDlg:numCopies,;
		              oPrintDlg:pageRangeSelected}
		ENDIF
	ENDIF

RETURN oDC


DLLFUNCTION GetAsyncKeyState(nKey) USING STDCALL FROM USER32.DLL