{ $Id$ } { ------------------------------------ win32debug.pp - graphic dump utils ------------------------------------ @created(Fri Jun 1th WET 2007) @lastmod($Date$) @author(Marc Weustink ) This unit contains utility functions to show the contents of graphics ***************************************************************************** This file is part of the Lazarus Component Library (LCL) See the file COPYING.modifiedLGPL.txt, included in this distribution, for details about the license. ***************************************************************************** } unit Win32Debug; {$mode objfpc}{$H+} interface uses Windows, SysUtils, Win32Extra; procedure DbgDumpBitmap(ABitmap: HBITMAP; ATitle: String = ''; AUseBitBlt: Boolean = False; AWidth: Integer = -1; AHeight: Integer = -1); procedure DbgDumpDC(ADC: HDC; ATitle: String = ''; AUseBitBlt: Boolean = False; AWidth: Integer = -1; AHeight: Integer = -1); implementation type PDbgDumpInfo = ^TDbgDumpInfo; TDbgDumpInfo = record Width, Height: Integer; OrgWidth, OrgHeight: Integer; Bitmap: HBITMAP; ColorIdx: Byte; UseAlphaBlend: Boolean; end; function DbgWindowProc(Wnd: HWnd; Msg: UINT; WParam: WPAram; LParam: LPARAM): LRESULT; stdcall; function GetInfo: Pointer; begin // grrr.... this function isn't mapped to GetWindowLong {$ifdef CPU64} Result := Pointer(GetWindowLongPtr(wnd, GWL_USERDATA)); {$else} Result := Pointer(GetWindowLong(wnd, GWL_USERDATA)); {$endif} end; const COLORS: array[0..7] of COLORREF = ( $00000000, $000000FF, $0000FF00, $0000FFFF, $00FF0000, $00FF00FF, $00FFFF00, $00FFFFFF ); var Info: PDbgDumpInfo; PS: TPaintStruct; DC: HDC; OldBmp: HBITMAP; Blend: TBlendFunction; br: HBRUSH; begin Result := 0; case Msg of WM_PAINT: begin Info := GetInfo; BeginPaint(Wnd, PS); br := CreateSolidBrush(COLORS[Info^.ColorIdx and $7]); FillRect(PS.hDC, PS.rcPaint, br); DeleteObject(br); DC := CreateCompatibleDC(PS.hdc); OldBmp := SelectObject(DC, Info^.Bitmap); if Info^.UseAlphaBlend then begin Blend.BlendOp := AC_SRC_OVER; Blend.BlendFlags := 0; Blend.SourceConstantAlpha := 255; Blend.AlphaFormat := AC_SRC_ALPHA; Win32Extra.AlphaBlend(PS.hDC, 0, 0, Info^.Width, Info^.Height, DC, 0,0, Info^.OrgWidth, Info^.OrgHeight, Blend); end else begin BitBlt(PS.hDC, 0, 0, Info^.Width, Info^.Height, DC, 0,0, SRCCOPY); end; SelectObject(DC, OldBmp); DeleteDC(DC); EndPaint(Wnd, PS); end; WM_DESTROY: begin Info := GetInfo; DeleteObject(Info^.Bitmap); Dispose(Info); end; WM_LBUTTONUP: begin Info := GetInfo; Info^.ColorIdx := (Info^.ColorIdx + 1) and $7; InvalidateRect(Wnd, nil, False); end; else Result := DefWindowProc(wnd, Msg, WParam, LParam); end; end; var MDbgClassCreated: Boolean = False; procedure DbgCreateClass; var wc: TWndClass; begin if MDbgClassCreated then Exit; FillByte(wc, SizeOf(wc), 0); wc.style := CS_HREDRAW or CS_VREDRAW; wc.lpfnWndProc := @DbgWindowProc; wc.hInstance := hinstance; wc.hbrBackground := GetStockObject(BLACK_BRUSH); wc.lpszClassName := 'LazDbgWindow'; RegisterClass(wc); MDbgClassCreated := True; end; procedure DbgCreateWindow(AInfo: PDbgDumpInfo; const ATitle: String); var window: HWND; w, h: Integer; begin DbgCreateClass; if AInfo^.Width < 50 then W := 50 else w := AInfo^.Width; if AInfo^.Height < 25 then H := 25 else H := AInfo^.Height; window := CreateWindowEx(WS_EX_TOOLWINDOW, 'LazDbgWindow', PChar(ATitle), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, W + 8, H+ 25, 0, 0, HINSTANCE, nil); {$ifdef CPU64} SetWindowLongPtr(window, GWL_USERDATA, PtrInt(AInfo)); {$else} SetWindowLong(window, GWL_USERDATA, PtrInt(AInfo)); {$endif} ShowWindow(window, SW_SHOWNOACTIVATE); end; procedure InternalDumpBitmap(ABitmap: HBITMAP; ADesc, ATitle: String; AWidth: Integer; AHeight: Integer; AUseBitBlt: Boolean); var Info: PDbgDumpInfo; h,w,d: Integer; WinBmp: Windows.TBitmap; begin New(Info); if (ABitmap = 0) or (Windows.GetObject(ABitmap, SizeOf(WinBmp), @WinBmp) = 0) then begin w := 0; h:= 0; d := 0; Info^.Bitmap := 0; if AWidth = -1 then AWidth := 0; if AHeight = -1 then AHeight := 0; end else begin w := WinBmp.bmWidth; h := WinBmp.bmHeight; d := WinBmp.bmBitsPixel; if AWidth = -1 then AWidth := W; if AHeight = -1 then AHeight := H; Info^.Bitmap := CopyImage(ABitmap, IMAGE_BITMAP, AWidth, AHeight, 0); end; Info^.Width := AWidth; Info^.Height := AHeight; Info^.OrgWidth := w; Info^.OrgHeight := h; Info^.UseAlphaBlend := (d > 24) and not AUseBitBlt; ATitle := ATitle + Format(' (%s W:%d H:%d D:%d)', [ADesc, w, h, d]); DbgCreateWindow(Info, ATitle); end; procedure DbgDumpBitmap(ABitmap: HBITMAP; ATitle: String; AUseBitBlt: Boolean; AWidth, AHeight: Integer); begin InternalDumpBitmap(ABitmap, Format('Bitmap:$%x', [ABitmap]), ATitle, AWidth, AHeight, AUseBitBlt); end; procedure DbgDumpDC(ADC: HDC; ATitle: String; AUseBitBlt: Boolean; AWidth, AHeight: Integer); var bmp: HBITMAP; begin bmp := CreateBitmap(1,1,1,1,nil); // select dummy to get selected bitmap bmp := SelectObject(ADC, bmp); InternalDumpBitmap(bmp, Format('DC:$%x', [ADC]), ATitle, AWidth, AHeight, AUseBitBlt); // restore bitmap and delete dummy DeleteObject(SelectObject(ADC, bmp)); end; end.