#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2009-2014, Mario Vilas
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice,this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of the copyright holder nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""
Wrapper for gdi32.dll in ctypes.
"""

__revision__ = "$Id$"

from winappdbg.win32.defines import *
from winappdbg.win32.kernel32 import GetLastError, SetLastError

# ==============================================================================
# This is used later on to calculate the list of exported symbols.
_all = None
_all = set(vars().keys())
# ==============================================================================

# --- Helpers ------------------------------------------------------------------

# --- Types --------------------------------------------------------------------

# --- Constants ----------------------------------------------------------------

# GDI object types
OBJ_PEN = 1
OBJ_BRUSH = 2
OBJ_DC = 3
OBJ_METADC = 4
OBJ_PAL = 5
OBJ_FONT = 6
OBJ_BITMAP = 7
OBJ_REGION = 8
OBJ_METAFILE = 9
OBJ_MEMDC = 10
OBJ_EXTPEN = 11
OBJ_ENHMETADC = 12
OBJ_ENHMETAFILE = 13
OBJ_COLORSPACE = 14
GDI_OBJ_LAST = OBJ_COLORSPACE

# Ternary raster operations
SRCCOPY = 0x00CC0020  # dest = source
SRCPAINT = 0x00EE0086  # dest = source OR dest
SRCAND = 0x008800C6  # dest = source AND dest
SRCINVERT = 0x00660046  # dest = source XOR dest
SRCERASE = 0x00440328  # dest = source AND (NOT dest)
NOTSRCCOPY = 0x00330008  # dest = (NOT source)
NOTSRCERASE = 0x001100A6  # dest = (NOT src) AND (NOT dest)
MERGECOPY = 0x00C000CA  # dest = (source AND pattern)
MERGEPAINT = 0x00BB0226  # dest = (NOT source) OR dest
PATCOPY = 0x00F00021  # dest = pattern
PATPAINT = 0x00FB0A09  # dest = DPSnoo
PATINVERT = 0x005A0049  # dest = pattern XOR dest
DSTINVERT = 0x00550009  # dest = (NOT dest)
BLACKNESS = 0x00000042  # dest = BLACK
WHITENESS = 0x00FF0062  # dest = WHITE
NOMIRRORBITMAP = 0x80000000  # Do not Mirror the bitmap in this call
CAPTUREBLT = 0x40000000  # Include layered windows

# Region flags
ERROR = 0
NULLREGION = 1
SIMPLEREGION = 2
COMPLEXREGION = 3
RGN_ERROR = ERROR

# CombineRgn() styles
RGN_AND = 1
RGN_OR = 2
RGN_XOR = 3
RGN_DIFF = 4
RGN_COPY = 5
RGN_MIN = RGN_AND
RGN_MAX = RGN_COPY

# StretchBlt() modes
BLACKONWHITE = 1
WHITEONBLACK = 2
COLORONCOLOR = 3
HALFTONE = 4
MAXSTRETCHBLTMODE = 4
STRETCH_ANDSCANS = BLACKONWHITE
STRETCH_ORSCANS = WHITEONBLACK
STRETCH_DELETESCANS = COLORONCOLOR
STRETCH_HALFTONE = HALFTONE

# PolyFill() modes
ALTERNATE = 1
WINDING = 2
POLYFILL_LAST = 2

# Layout orientation options
LAYOUT_RTL = 0x00000001  # Right to left
LAYOUT_BTT = 0x00000002  # Bottom to top
LAYOUT_VBH = 0x00000004  # Vertical before horizontal
LAYOUT_ORIENTATIONMASK = LAYOUT_RTL + LAYOUT_BTT + LAYOUT_VBH
LAYOUT_BITMAPORIENTATIONPRESERVED = 0x00000008

# Stock objects
WHITE_BRUSH = 0
LTGRAY_BRUSH = 1
GRAY_BRUSH = 2
DKGRAY_BRUSH = 3
BLACK_BRUSH = 4
NULL_BRUSH = 5
HOLLOW_BRUSH = NULL_BRUSH
WHITE_PEN = 6
BLACK_PEN = 7
NULL_PEN = 8
OEM_FIXED_FONT = 10
ANSI_FIXED_FONT = 11
ANSI_VAR_FONT = 12
SYSTEM_FONT = 13
DEVICE_DEFAULT_FONT = 14
DEFAULT_PALETTE = 15
SYSTEM_FIXED_FONT = 16

# Metafile functions
META_SETBKCOLOR = 0x0201
META_SETBKMODE = 0x0102
META_SETMAPMODE = 0x0103
META_SETROP2 = 0x0104
META_SETRELABS = 0x0105
META_SETPOLYFILLMODE = 0x0106
META_SETSTRETCHBLTMODE = 0x0107
META_SETTEXTCHAREXTRA = 0x0108
META_SETTEXTCOLOR = 0x0209
META_SETTEXTJUSTIFICATION = 0x020A
META_SETWINDOWORG = 0x020B
META_SETWINDOWEXT = 0x020C
META_SETVIEWPORTORG = 0x020D
META_SETVIEWPORTEXT = 0x020E
META_OFFSETWINDOWORG = 0x020F
META_SCALEWINDOWEXT = 0x0410
META_OFFSETVIEWPORTORG = 0x0211
META_SCALEVIEWPORTEXT = 0x0412
META_LINETO = 0x0213
META_MOVETO = 0x0214
META_EXCLUDECLIPRECT = 0x0415
META_INTERSECTCLIPRECT = 0x0416
META_ARC = 0x0817
META_ELLIPSE = 0x0418
META_FLOODFILL = 0x0419
META_PIE = 0x081A
META_RECTANGLE = 0x041B
META_ROUNDRECT = 0x061C
META_PATBLT = 0x061D
META_SAVEDC = 0x001E
META_SETPIXEL = 0x041F
META_OFFSETCLIPRGN = 0x0220
META_TEXTOUT = 0x0521
META_BITBLT = 0x0922
META_STRETCHBLT = 0x0B23
META_POLYGON = 0x0324
META_POLYLINE = 0x0325
META_ESCAPE = 0x0626
META_RESTOREDC = 0x0127
META_FILLREGION = 0x0228
META_FRAMEREGION = 0x0429
META_INVERTREGION = 0x012A
META_PAINTREGION = 0x012B
META_SELECTCLIPREGION = 0x012C
META_SELECTOBJECT = 0x012D
META_SETTEXTALIGN = 0x012E
META_CHORD = 0x0830
META_SETMAPPERFLAGS = 0x0231
META_EXTTEXTOUT = 0x0A32
META_SETDIBTODEV = 0x0D33
META_SELECTPALETTE = 0x0234
META_REALIZEPALETTE = 0x0035
META_ANIMATEPALETTE = 0x0436
META_SETPALENTRIES = 0x0037
META_POLYPOLYGON = 0x0538
META_RESIZEPALETTE = 0x0139
META_DIBBITBLT = 0x0940
META_DIBSTRETCHBLT = 0x0B41
META_DIBCREATEPATTERNBRUSH = 0x0142
META_STRETCHDIB = 0x0F43
META_EXTFLOODFILL = 0x0548
META_SETLAYOUT = 0x0149
META_DELETEOBJECT = 0x01F0
META_CREATEPALETTE = 0x00F7
META_CREATEPATTERNBRUSH = 0x01F9
META_CREATEPENINDIRECT = 0x02FA
META_CREATEFONTINDIRECT = 0x02FB
META_CREATEBRUSHINDIRECT = 0x02FC
META_CREATEREGION = 0x06FF

# Metafile escape codes
NEWFRAME = 1
ABORTDOC = 2
NEXTBAND = 3
SETCOLORTABLE = 4
GETCOLORTABLE = 5
FLUSHOUTPUT = 6
DRAFTMODE = 7
QUERYESCSUPPORT = 8
SETABORTPROC = 9
STARTDOC = 10
ENDDOC = 11
GETPHYSPAGESIZE = 12
GETPRINTINGOFFSET = 13
GETSCALINGFACTOR = 14
MFCOMMENT = 15
GETPENWIDTH = 16
SETCOPYCOUNT = 17
SELECTPAPERSOURCE = 18
DEVICEDATA = 19
PASSTHROUGH = 19
GETTECHNOLGY = 20
GETTECHNOLOGY = 20
SETLINECAP = 21
SETLINEJOIN = 22
SETMITERLIMIT = 23
BANDINFO = 24
DRAWPATTERNRECT = 25
GETVECTORPENSIZE = 26
GETVECTORBRUSHSIZE = 27
ENABLEDUPLEX = 28
GETSETPAPERBINS = 29
GETSETPRINTORIENT = 30
ENUMPAPERBINS = 31
SETDIBSCALING = 32
EPSPRINTING = 33
ENUMPAPERMETRICS = 34
GETSETPAPERMETRICS = 35
POSTSCRIPT_DATA = 37
POSTSCRIPT_IGNORE = 38
MOUSETRAILS = 39
GETDEVICEUNITS = 42
GETEXTENDEDTEXTMETRICS = 256
GETEXTENTTABLE = 257
GETPAIRKERNTABLE = 258
GETTRACKKERNTABLE = 259
EXTTEXTOUT = 512
GETFACENAME = 513
DOWNLOADFACE = 514
ENABLERELATIVEWIDTHS = 768
ENABLEPAIRKERNING = 769
SETKERNTRACK = 770
SETALLJUSTVALUES = 771
SETCHARSET = 772
STRETCHBLT = 2048
METAFILE_DRIVER = 2049
GETSETSCREENPARAMS = 3072
QUERYDIBSUPPORT = 3073
BEGIN_PATH = 4096
CLIP_TO_PATH = 4097
END_PATH = 4098
EXT_DEVICE_CAPS = 4099
RESTORE_CTM = 4100
SAVE_CTM = 4101
SET_ARC_DIRECTION = 4102
SET_BACKGROUND_COLOR = 4103
SET_POLY_MODE = 4104
SET_SCREEN_ANGLE = 4105
SET_SPREAD = 4106
TRANSFORM_CTM = 4107
SET_CLIP_BOX = 4108
SET_BOUNDS = 4109
SET_MIRROR_MODE = 4110
OPENCHANNEL = 4110
DOWNLOADHEADER = 4111
CLOSECHANNEL = 4112
POSTSCRIPT_PASSTHROUGH = 4115
ENCAPSULATED_POSTSCRIPT = 4116
POSTSCRIPT_IDENTIFY = 4117
POSTSCRIPT_INJECTION = 4118
CHECKJPEGFORMAT = 4119
CHECKPNGFORMAT = 4120
GET_PS_FEATURESETTING = 4121
GDIPLUS_TS_QUERYVER = 4122
GDIPLUS_TS_RECORD = 4123
SPCLPASSTHROUGH2 = 4568

# --- Structures ---------------------------------------------------------------


# typedef struct _RECT {
#   LONG left;
#   LONG top;
#   LONG right;
#   LONG bottom;
# }RECT, *PRECT;
class RECT(Structure):
    _fields_ = [
        ("left", LONG),
        ("top", LONG),
        ("right", LONG),
        ("bottom", LONG),
    ]


PRECT = POINTER(RECT)
LPRECT = PRECT


# typedef struct tagPOINT {
#   LONG x;
#   LONG y;
# } POINT;
class POINT(Structure):
    _fields_ = [
        ("x", LONG),
        ("y", LONG),
    ]


PPOINT = POINTER(POINT)
LPPOINT = PPOINT


# typedef struct tagBITMAP {
#   LONG   bmType;
#   LONG   bmWidth;
#   LONG   bmHeight;
#   LONG   bmWidthBytes;
#   WORD   bmPlanes;
#   WORD   bmBitsPixel;
#   LPVOID bmBits;
# } BITMAP, *PBITMAP;
class BITMAP(Structure):
    _fields_ = [
        ("bmType", LONG),
        ("bmWidth", LONG),
        ("bmHeight", LONG),
        ("bmWidthBytes", LONG),
        ("bmPlanes", WORD),
        ("bmBitsPixel", WORD),
        ("bmBits", LPVOID),
    ]


PBITMAP = POINTER(BITMAP)
LPBITMAP = PBITMAP

# --- High level classes -------------------------------------------------------

# --- gdi32.dll ----------------------------------------------------------------


# HDC GetDC(
#   __in  HWND hWnd
# );
def GetDC(hWnd):
    _GetDC = windll.gdi32.GetDC
    _GetDC.argtypes = [HWND]
    _GetDC.restype = HDC
    _GetDC.errcheck = RaiseIfZero
    return _GetDC(hWnd)


# HDC GetWindowDC(
#   __in  HWND hWnd
# );
def GetWindowDC(hWnd):
    _GetWindowDC = windll.gdi32.GetWindowDC
    _GetWindowDC.argtypes = [HWND]
    _GetWindowDC.restype = HDC
    _GetWindowDC.errcheck = RaiseIfZero
    return _GetWindowDC(hWnd)


# int ReleaseDC(
#   __in  HWND hWnd,
#   __in  HDC hDC
# );
def ReleaseDC(hWnd, hDC):
    _ReleaseDC = windll.gdi32.ReleaseDC
    _ReleaseDC.argtypes = [HWND, HDC]
    _ReleaseDC.restype = ctypes.c_int
    _ReleaseDC.errcheck = RaiseIfZero
    _ReleaseDC(hWnd, hDC)


# HGDIOBJ SelectObject(
#   __in  HDC hdc,
#   __in  HGDIOBJ hgdiobj
# );
def SelectObject(hdc, hgdiobj):
    _SelectObject = windll.gdi32.SelectObject
    _SelectObject.argtypes = [HDC, HGDIOBJ]
    _SelectObject.restype = HGDIOBJ
    _SelectObject.errcheck = RaiseIfZero
    return _SelectObject(hdc, hgdiobj)


# HGDIOBJ GetStockObject(
#   __in  int fnObject
# );
def GetStockObject(fnObject):
    _GetStockObject = windll.gdi32.GetStockObject
    _GetStockObject.argtypes = [ctypes.c_int]
    _GetStockObject.restype = HGDIOBJ
    _GetStockObject.errcheck = RaiseIfZero
    return _GetStockObject(fnObject)


# DWORD GetObjectType(
#   __in  HGDIOBJ h
# );
def GetObjectType(h):
    _GetObjectType = windll.gdi32.GetObjectType
    _GetObjectType.argtypes = [HGDIOBJ]
    _GetObjectType.restype = DWORD
    _GetObjectType.errcheck = RaiseIfZero
    return _GetObjectType(h)


# int GetObject(
#   __in   HGDIOBJ hgdiobj,
#   __in   int cbBuffer,
#   __out  LPVOID lpvObject
# );
def GetObject(hgdiobj, cbBuffer=None, lpvObject=None):
    _GetObject = windll.gdi32.GetObject
    _GetObject.argtypes = [HGDIOBJ, ctypes.c_int, LPVOID]
    _GetObject.restype = ctypes.c_int
    _GetObject.errcheck = RaiseIfZero

    # Both cbBuffer and lpvObject can be omitted, the correct
    # size and structure to return are automatically deduced.
    # If lpvObject is given it must be a ctypes object, not a pointer.
    # Always returns a ctypes object.

    if cbBuffer is not None:
        if lpvObject is None:
            lpvObject = ctypes.create_string_buffer("", cbBuffer)
    elif lpvObject is not None:
        cbBuffer = sizeof(lpvObject)
    else:  # most likely case, both are None
        t = GetObjectType(hgdiobj)
        if t == OBJ_PEN:
            cbBuffer = sizeof(LOGPEN)
            lpvObject = LOGPEN()
        elif t == OBJ_BRUSH:
            cbBuffer = sizeof(LOGBRUSH)
            lpvObject = LOGBRUSH()
        elif t == OBJ_PAL:
            cbBuffer = _GetObject(hgdiobj, 0, None)
            lpvObject = (WORD * (cbBuffer // sizeof(WORD)))()
        elif t == OBJ_FONT:
            cbBuffer = sizeof(LOGFONT)
            lpvObject = LOGFONT()
        elif t == OBJ_BITMAP:  # try the two possible types of bitmap
            cbBuffer = sizeof(DIBSECTION)
            lpvObject = DIBSECTION()
            try:
                _GetObject(hgdiobj, cbBuffer, byref(lpvObject))
                return lpvObject
            except WindowsError:
                cbBuffer = sizeof(BITMAP)
                lpvObject = BITMAP()
        elif t == OBJ_EXTPEN:
            cbBuffer = sizeof(LOGEXTPEN)
            lpvObject = LOGEXTPEN()
        else:
            cbBuffer = _GetObject(hgdiobj, 0, None)
            lpvObject = ctypes.create_string_buffer("", cbBuffer)
    _GetObject(hgdiobj, cbBuffer, byref(lpvObject))
    return lpvObject


# LONG GetBitmapBits(
#   __in   HBITMAP hbmp,
#   __in   LONG cbBuffer,
#   __out  LPVOID lpvBits
# );
def GetBitmapBits(hbmp):
    _GetBitmapBits = windll.gdi32.GetBitmapBits
    _GetBitmapBits.argtypes = [HBITMAP, LONG, LPVOID]
    _GetBitmapBits.restype = LONG
    _GetBitmapBits.errcheck = RaiseIfZero

    bitmap = GetObject(hbmp, lpvObject=BITMAP())
    cbBuffer = bitmap.bmWidthBytes * bitmap.bmHeight
    lpvBits = ctypes.create_string_buffer("", cbBuffer)
    _GetBitmapBits(hbmp, cbBuffer, byref(lpvBits))
    return lpvBits.raw


# HBITMAP CreateBitmapIndirect(
#   __in  const BITMAP *lpbm
# );
def CreateBitmapIndirect(lpbm):
    _CreateBitmapIndirect = windll.gdi32.CreateBitmapIndirect
    _CreateBitmapIndirect.argtypes = [PBITMAP]
    _CreateBitmapIndirect.restype = HBITMAP
    _CreateBitmapIndirect.errcheck = RaiseIfZero
    return _CreateBitmapIndirect(lpbm)


# ==============================================================================
# This calculates the list of exported symbols.
_all = set(vars().keys()).difference(_all)
__all__ = [_x for _x in _all if not _x.startswith("_")]
__all__.sort()
# ==============================================================================
