Jump to content

Recommended Posts

Posted

I would like some help with a UDF that am using, the purpose of the UDF is to captures a region and load to memory for OCR processing later. At the moment the screen capture function captures whats visible on screen for the region. I would like it to capture a region of a handle (even if there is a other window in front of it or the window is minimized ) and return that information.

i tried to tweak the code myself using the _ScreenCapture_CaptureWnd() command in "ScreenCapture.au3" but it doesn't seem to return the correct value. i dont have much experience with these command so i am having some trouble with troubleshooting and changing these functions.

This is how the screen capture code is called in my program:

;; title =  WinGetHandle('[CLASS:Notepad]')
;; Local left= 0, $top= 0, $right= 200, $buttom= 200
$hDll = DllOpen("gdi32.dll")
$vDC = _PixelGetColor_CreateDC($hDll)
$vRegion = _PixelGetColor_CaptureRegion($vDC, $left, $top, $right, $bottom, $hDll)

 

This is part of the UDF where both of the above commands are written:

#include <ScreenCapture.au3>
#include-once

; #FUNCTION# ;===============================================================================
;
; Name...........: _PixelGetColor_CreateDC
; Description ...: Creates a DC for use with the other _PixelGetColor functions.
; Syntax.........: _PixelGetColor_CreateDC()
; Parameters ....: None.
; Return values .: Success - Returns the handle to a compatible DC.
;                  Failure - Returns 0 and Sets @error according to @error from the DllCall.
; Author ........: Jos van Egmond
; Modified.......:
; Remarks .......:
; Related .......: _PixelGetColor_CaptureRegion, _PixelGetcolor_GetPixel, _PixelGetColor_GetPixelRaw, _PixelGetColor_ReleaseRegion, _PixelGet_Color_ReleaseDC
; Example .......; No
;
; ;==========================================================================================
Func _PixelGetColor_CreateDC($hDll = "gdi32.dll")
    $iPixelGetColor_MemoryContext = DllCall($hDll, "int", "CreateCompatibleDC", "int", 0)
    If @error Then Return SetError(@error,0,0)
    Return $iPixelGetColor_MemoryContext[0]
EndFunc

; #FUNCTION# ;===============================================================================
;
; Name...........: _PixelGetColor_CaptureRegion
; Description ...: Captures the user defined region and reads it to a memory DC.
; Syntax.........: _PixelGetColor_CaptureRegion($iPixelGetColor_MemoryContext, $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $fCursor = False)
; Parameters ....: $iPixelGetColor_MemoryContext    - The DC as returned by _PixelGetColor_CreateDC
;                   $iLeft      - Left side of the screen for use with the region
;                   $iTop       - Top side of the screen for use with the region
;                   $iRight     - Right side of the screen for use with the region
;                   $iBottom    - Bottom side of the screen for use with the region
;                   $iCursor    - If this is true, then the cursor is also read into memory
; Return values .: Success - Returns the handle to a region.
;                  Failure - 
; Author ........: Jos van Egmond
; Modified.......:
; Remarks .......:
; Related .......: _PixelGet_Color_CreateDC, _PixelGetcolor_GetPixel, _PixelGetColor_GetPixelRaw, _PixelGetColor_ReleaseRegion, _PixelGet_Color_ReleaseDC
; Example .......; No
;
; ;==========================================================================================
Func _PixelGetColor_CaptureRegion($iPixelGetColor_MemoryContext, $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $fCursor = False, $hDll = "gdi32.dll")
    $HBITMAP = _ScreenCapture_Capture("", $iLeft, $iTop, $iRight, $iBottom, $fCursor)
    DllCall($hDll, "hwnd", "SelectObject", "int", $iPixelGetColor_MemoryContext, "hwnd", $HBITMAP)
    Return $HBITMAP
EndFunc

 

This is the ScreenCapture UDF

; #CURRENT# =====================================================================================================================
; _ScreenCapture_Capture
; _ScreenCapture_CaptureWnd
; _ScreenCapture_SaveImage
; _ScreenCapture_SetBMPFormat
; _ScreenCapture_SetJPGQuality
; _ScreenCapture_SetTIFColorDepth
; _ScreenCapture_SetTIFCompression
; ===============================================================================================================================

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_Capture($sFileName = "", $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $bCursor = True)
    Local $bRet = False
    If $iRight = -1 Then $iRight = _WinAPI_GetSystemMetrics($__SCREENCAPTURECONSTANT_SM_CXSCREEN) - 1
    If $iBottom = -1 Then $iBottom = _WinAPI_GetSystemMetrics($__SCREENCAPTURECONSTANT_SM_CYSCREEN) - 1
    If $iRight < $iLeft Then Return SetError(-1, 0, $bRet)
    If $iBottom < $iTop Then Return SetError(-2, 0, $bRet)

    Local $iW = ($iRight - $iLeft) + 1
    Local $iH = ($iBottom - $iTop) + 1
    Local $hWnd = _WinAPI_GetDesktopWindow()
    Local $hDDC = _WinAPI_GetDC($hWnd)
    Local $hCDC = _WinAPI_CreateCompatibleDC($hDDC)
    Local $hBMP = _WinAPI_CreateCompatibleBitmap($hDDC, $iW, $iH)
    _WinAPI_SelectObject($hCDC, $hBMP)
    _WinAPI_BitBlt($hCDC, 0, 0, $iW, $iH, $hDDC, $iLeft, $iTop, $__SCREENCAPTURECONSTANT_SRCCOPY)

    If $bCursor Then
        Local $aCursor = _WinAPI_GetCursorInfo()
        If Not @error And $aCursor[1] Then
            $bCursor = True ; Cursor info was found.
            Local $hIcon = _WinAPI_CopyIcon($aCursor[2])
            Local $aIcon = _WinAPI_GetIconInfo($hIcon)
            If Not @error Then
                _WinAPI_DeleteObject($aIcon[4]) ; delete bitmap mask return by _WinAPI_GetIconInfo()
                If $aIcon[5] <> 0 Then _WinAPI_DeleteObject($aIcon[5]); delete bitmap hbmColor return by _WinAPI_GetIconInfo()
                _WinAPI_DrawIcon($hCDC, $aCursor[3] - $aIcon[2] - $iLeft, $aCursor[4] - $aIcon[3] - $iTop, $hIcon)
            EndIf
            _WinAPI_DestroyIcon($hIcon)
        EndIf
    EndIf

    _WinAPI_ReleaseDC($hWnd, $hDDC)
    _WinAPI_DeleteDC($hCDC)
    If $sFileName = "" Then Return $hBMP

    $bRet = _ScreenCapture_SaveImage($sFileName, $hBMP, True)
    Return SetError(@error, @extended, $bRet)
EndFunc   ;==>_ScreenCapture_Capture

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......: jpm based on Kafu
; ===============================================================================================================================
Func _ScreenCapture_CaptureWnd($sFileName, $hWnd, $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $bCursor = True)
    If Not IsHWnd($hWnd) Then $hWnd = WinGetHandle($hWnd)
    Local $tRECT = DllStructCreate($tagRECT)
    ; needed to get rect when Aero theme is active : Thanks Kafu, Zedna
    Local Const $DWMWA_EXTENDED_FRAME_BOUNDS = 9
    Local $bRet = DllCall("dwmapi.dll", "long", "DwmGetWindowAttribute", "hwnd", $hWnd, "dword", $DWMWA_EXTENDED_FRAME_BOUNDS, "struct*", $tRECT, "dword", DllStructGetSize($tRECT))
    If (@error Or $bRet[0] Or (Abs(DllStructGetData($tRECT, "Left")) + Abs(DllStructGetData($tRECT, "Top")) + _
            Abs(DllStructGetData($tRECT, "Right")) + Abs(DllStructGetData($tRECT, "Bottom"))) = 0) Then
        $tRECT = _WinAPI_GetWindowRect($hWnd)
        If @error Then Return SetError(@error + 10, @extended, False)
    EndIf

    $iLeft += DllStructGetData($tRECT, "Left")
    $iTop += DllStructGetData($tRECT, "Top")
    If $iRight = -1 Then $iRight = DllStructGetData($tRECT, "Right") - DllStructGetData($tRECT, "Left") - 1
    If $iBottom = -1 Then $iBottom = DllStructGetData($tRECT, "Bottom") - DllStructGetData($tRECT, "Top") - 1
    $iRight += DllStructGetData($tRECT, "Left")
    $iBottom += DllStructGetData($tRECT, "Top")
    If $iLeft > DllStructGetData($tRECT, "Right") Then $iLeft = DllStructGetData($tRECT, "Left")
    If $iTop > DllStructGetData($tRECT, "Bottom") Then $iTop = DllStructGetData($tRECT, "Top")
    If $iRight > DllStructGetData($tRECT, "Right") Then $iRight = DllStructGetData($tRECT, "Right") - 1
    If $iBottom > DllStructGetData($tRECT, "Bottom") Then $iBottom = DllStructGetData($tRECT, "Bottom") - 1
    $bRet = _ScreenCapture_Capture($sFileName, $iLeft, $iTop, $iRight, $iBottom, $bCursor)
    Return SetError(@error, @extended, $bRet)
EndFunc   ;==>_ScreenCapture_CaptureWnd

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_SaveImage($sFileName, $hBitmap, $bFreeBmp = True)
    _GDIPlus_Startup()
    If @error Then Return SetError(-1, -1, False)

    Local $sExt = StringUpper(__GDIPlus_ExtractFileExt($sFileName))
    Local $sCLSID = _GDIPlus_EncodersGetCLSID($sExt)
    If $sCLSID = "" Then Return SetError(-2, -2, False)
    Local $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    If @error Then Return SetError(-3, -3, False)

    Local $tData, $tParams
    Switch $sExt
        Case "BMP"
            Local $iX = _GDIPlus_ImageGetWidth($hImage)
            Local $iY = _GDIPlus_ImageGetHeight($hImage)
            Local $hClone = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iX, $iY, $__g_iBMPFormat)
            _GDIPlus_ImageDispose($hImage)
            $hImage = $hClone
        Case "JPG", "JPEG"
            $tParams = _GDIPlus_ParamInit(1)
            $tData = DllStructCreate("int Quality")
            DllStructSetData($tData, "Quality", $__g_iJPGQuality)
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, DllStructGetPtr($tData))
        Case "TIF", "TIFF"
            $tParams = _GDIPlus_ParamInit(2)
            $tData = DllStructCreate("int ColorDepth;int Compression")
            DllStructSetData($tData, "ColorDepth", $__g_iTIFColorDepth)
            DllStructSetData($tData, "Compression", $__g_iTIFCompression)
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOLORDEPTH, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "ColorDepth"))
            _GDIPlus_ParamAdd($tParams, $GDIP_EPGCOMPRESSION, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "Compression"))
    EndSwitch
    Local $pParams = 0
    If IsDllStruct($tParams) Then $pParams = $tParams

    Local $bRet = _GDIPlus_ImageSaveToFileEx($hImage, $sFileName, $sCLSID, $pParams)
    _GDIPlus_ImageDispose($hImage)
    If $bFreeBmp Then _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_Shutdown()

    Return SetError($bRet = False, 0, $bRet)
EndFunc   ;==>_ScreenCapture_SaveImage

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_SetBMPFormat($iFormat)
    Switch $iFormat
        Case 0
            $__g_iBMPFormat = $GDIP_PXF16RGB555
        Case 1
            $__g_iBMPFormat = $GDIP_PXF16RGB565
        Case 2
            $__g_iBMPFormat = $GDIP_PXF24RGB
        Case 3
            $__g_iBMPFormat = $GDIP_PXF32RGB
        Case 4
            $__g_iBMPFormat = $GDIP_PXF32ARGB
        Case Else
            $__g_iBMPFormat = $GDIP_PXF24RGB
    EndSwitch
EndFunc   ;==>_ScreenCapture_SetBMPFormat

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_SetJPGQuality($iQuality)
    If $iQuality < 0 Then $iQuality = 0
    If $iQuality > 100 Then $iQuality = 100
    $__g_iJPGQuality = $iQuality
EndFunc   ;==>_ScreenCapture_SetJPGQuality

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_SetTIFColorDepth($iDepth)
    Switch $iDepth
        Case 24
            $__g_iTIFColorDepth = 24
        Case 32
            $__g_iTIFColorDepth = 32
        Case Else
            $__g_iTIFColorDepth = 0
    EndSwitch
EndFunc   ;==>_ScreenCapture_SetTIFColorDepth

; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......:
; ===============================================================================================================================
Func _ScreenCapture_SetTIFCompression($iCompress)
    Switch $iCompress
        Case 1
            $__g_iTIFCompression = $GDIP_EVTCOMPRESSIONNONE
        Case 2
            $__g_iTIFCompression = $GDIP_EVTCOMPRESSIONLZW
        Case Else
            $__g_iTIFCompression = 0
    EndSwitch
EndFunc   ;==>_ScreenCapture_SetTIFCompression

 

Posted

You will need to use win32 API printWindow, like this :

#include <WinAPIGdi.au3>
#include <ScreenCapture.au3>

Local $hWnd = WinGetHandle("[CLASS:Notepad]")
Capture_Window($hWnd, 650, 500)
ShellExecute("test.jpg")

Func Capture_Window($hWnd, $w, $h)
  Local $hDC_Capture = _WinAPI_GetDC($hWnd)
  Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC_Capture)
  Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $w, $h)
  Local $hObject = _WinAPI_SelectObject($hMemDC, $hHBitmap)
  _WinAPI_PrintWindow($hWnd, $hMemDC)
  _ScreenCapture_SaveImage("test.jpg", $hHBitmap)
  _WinAPI_DeleteDC($hMemDC)
  _WinAPI_ReleaseDC($hWnd, $hDC_Capture)
  _WinAPI_DeleteObject($hHBitmap)
EndFunc   ;==>Capture_Window

But it will not work on minimized window.  I don't believe there is a solution for minimized window, but you can always restore them for the duration of the copy...

Posted

@Nine first of all thanks for the reply and appreciate your help! 

I thought that a minimized window would be a bit tricky but thats ok and was only a 'extra'.  The most important for me now is that when there is a other window on top of the window being OCR, OCR can still do its work. I tested your example and still have some questions hopefully you can help me with.

1.  for speed/load purpose and possibility of false positives i need to set the region with left, top, right and bottom e.g. $left= 190, $top= 213, $right= 433, $bottom= 250

2. The current function in my script does not save the image but returns the region as result of "_WinAPI_CreateCompatibleBitmap", after that a DllCall (i think loading the image into memory), and returning the $HBITMAP. How can i return your function correctly to the function used by OCR UDF "_PixelGetColor_CaptureRegion"?

;;<OCR.au3>
$hDll = DllOpen("gdi32.dll")
$vDC = _PixelGetColor_CreateDC($hDll)
$vRegion = _PixelGetColor_CaptureRegion($vDC, $left, $top, $right + 1, $bottom + 1, $hDll)



;;<_PixelGetColor.au3>
Func _PixelGetColor_CreateDC($hDll = "gdi32.dll")
    $iPixelGetColor_MemoryContext = DllCall($hDll, "int", "CreateCompatibleDC", "int", 0)
    If @error Then Return SetError(@error,0,0)
    Return $iPixelGetColor_MemoryContext[0]
EndFunc

Func _PixelGetColor_CaptureRegion($iPixelGetColor_MemoryContext, $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $fCursor = False, $hDll = "gdi32.dll")
    $HBITMAP = _ScreenCapture_Capture("", $iLeft, $iTop, $iRight, $iBottom, $fCursor)
    DllCall($hDll, "hwnd", "SelectObject", "int", $iPixelGetColor_MemoryContext, "hwnd", $HBITMAP)
    Return $HBITMAP
EndFunc



;;<ScreenCapture.au3>
Func _ScreenCapture_Capture($sFileName = "", $iLeft = 0, $iTop = 0, $iRight = -1, $iBottom = -1, $bCursor = True)
    Local $bRet = False
    If $iRight = -1 Then $iRight = _WinAPI_GetSystemMetrics($__SCREENCAPTURECONSTANT_SM_CXSCREEN) - 1
    If $iBottom = -1 Then $iBottom = _WinAPI_GetSystemMetrics($__SCREENCAPTURECONSTANT_SM_CYSCREEN) - 1
    If $iRight < $iLeft Then Return SetError(-1, 0, $bRet)
    If $iBottom < $iTop Then Return SetError(-2, 0, $bRet)

    Local $iW = ($iRight - $iLeft) + 1
    Local $iH = ($iBottom - $iTop) + 1
    Local $hWnd = _WinAPI_GetDesktopWindow()
    Local $hDDC = _WinAPI_GetDC($hWnd)
    Local $hCDC = _WinAPI_CreateCompatibleDC($hDDC)
    Local $hBMP = _WinAPI_CreateCompatibleBitmap($hDDC, $iW, $iH)
    _WinAPI_SelectObject($hCDC, $hBMP)
    _WinAPI_BitBlt($hCDC, 0, 0, $iW, $iH, $hDDC, $iLeft, $iTop, $__SCREENCAPTURECONSTANT_SRCCOPY)

    If $bCursor Then
        Local $aCursor = _WinAPI_GetCursorInfo()
        If Not @error And $aCursor[1] Then
            $bCursor = True ; Cursor info was found.
            Local $hIcon = _WinAPI_CopyIcon($aCursor[2])
            Local $aIcon = _WinAPI_GetIconInfo($hIcon)
            If Not @error Then
                _WinAPI_DeleteObject($aIcon[4]) ; delete bitmap mask return by _WinAPI_GetIconInfo()
                If $aIcon[5] <> 0 Then _WinAPI_DeleteObject($aIcon[5]); delete bitmap hbmColor return by _WinAPI_GetIconInfo()
                _WinAPI_DrawIcon($hCDC, $aCursor[3] - $aIcon[2] - $iLeft, $aCursor[4] - $aIcon[3] - $iTop, $hIcon)
            EndIf
            _WinAPI_DestroyIcon($hIcon)
        EndIf
    EndIf

    _WinAPI_ReleaseDC($hWnd, $hDDC)
    _WinAPI_DeleteDC($hCDC)
    If $sFileName = "" Then Return $hBMP
    
    $bRet = _ScreenCapture_SaveImage($sFileName, $hBMP, True)
    Return SetError(@error, @extended, $bRet)
EndFunc   ;==>_ScreenCapture_Capture

 

Posted

Here one way to do it :

#include <WinAPIGdi.au3>
#include <GDIPlus.au3>

Local $hWnd = WinGetHandle("[CLASS:Notepad]")
Local $hHbmp = Capture_Window($hWnd, 100, 100, 650, 500)
; do your OCR stuff here
_WinAPI_DeleteObject($hHBmp)

Func Capture_Window($hWnd, $l, $t, $r, $b)
  Local $hDC_Capture = _WinAPI_GetDC($hWnd)
  Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC_Capture)
  Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $r, $b)
  Local $hObject = _WinAPI_SelectObject($hMemDC, $hHBitmap)
  _WinAPI_PrintWindow($hWnd, $hMemDC)
  _GDIPlus_Startup ()
  Local $hBMP = _GDIPlus_BitmapCreateFromHBITMAP ($hHBitmap)
  Local $hBMP2 = _GDIPlus_BitmapCloneArea ($hBMP, $l, $t, $r-$l, $b-$t)
  $hHBitmap2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap ($hBMP2)
  _GDIPlus_BitmapDispose ($hBMP)
  _GDIPlus_BitmapDispose ($hBMP2)
  _GDIPlus_Shutdown ()
  _WinAPI_DeleteDC($hMemDC)
  _WinAPI_ReleaseDC($hWnd, $hDC_Capture)
  _WinAPI_DeleteObject($hHBitmap)
  Return $hHBitmap2
EndFunc   ;==>Capture_Window

 

Posted

Or this, which is 2 times faster :)

#include <WinAPIGdi.au3>
#include <WindowsConstants.au3>
#include <ScreenCapture.au3>

Local $hWnd = WinGetHandle("[CLASS:Notepad]")
Local $hTimer = TimerInit ()
Local $hBmp = Capture_Window($hWnd, 100, 100, 650, 500)
ConsoleWrite (TimerDiff ($hTimer & @CRLF))
_ScreenCapture_SaveImage("test.jpg", $hBmp)
_WinAPI_DeleteObject($hBmp)

ShellExecute("test.jpg")

Func Capture_Window($hWnd, $l, $t, $r, $b)
  Local $hDC_Capture = _WinAPI_GetDC($hWnd)
  Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC_Capture)
  Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $r, $b)
  _WinAPI_SelectObject($hMemDC, $hHBitmap)
  _WinAPI_PrintWindow($hWnd, $hMemDC)
  Local $hMemDC2 = _WinAPI_CreateCompatibleDC($hDC_Capture)
  Local $hHBitmap2 = _WinAPI_CreateCompatibleBitmap($hDC_Capture, $r-$l, $b-$t)
  _WinAPI_SelectObject($hMemDC2, $hHBitmap2)
  _WinAPI_BitBlt ($hMemDC2, 0, 0, $r-$l, $b-$t, $hMemDC, $l, $t, $SRCCOPY)
  _WinAPI_DeleteDC($hMemDC)
  _WinAPI_DeleteDC($hMemDC2)
  _WinAPI_ReleaseDC($hWnd, $hDC_Capture)
  _WinAPI_DeleteObject($hHBitmap)
  Return $hHBitmap2
EndFunc   ;==>Capture_Window

Like in the previous post, the return value of the function is usable by your OCR engine...

Posted

Thanks again! This seems to do the work for notepad unfortunately i'm getting black screens for Opera (and Chrome) browser, Is this because those applications run hardware-accelerated graphics (Intermediate D3D)? If so is there a other way?

Screenshot_25.thumb.png.c59bef37a434239bacf8168f1cdec364.pngtest.jpg.a6b84c32c764f1160946d73f57d93d88.jpg

Posted

Nine thanks again i will take a look at the webdriver UDF.

 

@Danp2 : Its a discord channel. I am collecting data from different sources to compile that data and do some automation action if needed.

Posted (edited)

Just want to let you know.  If you cannot use WebDriver (for some weird reasons -- it would be much more appropriate to use it though), I tested my screen capture script using PrintWindow, and it works well with IE.  So at least you have an alternative solution.  A combination of IE UDF with some OCR could work then.

Edited by Nine

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...