Contributor: SWAG SUPPORT TEAM The following TI details a better way to print the contents of a form, by getting the device independent bits in 256 colors from the form, and using those bits to print the form to the printer. In addition, a check is made to see if the screen or printer is a palette device, and if so, palette handling for the device is enabled. If the screen device is a palette device, an additional step is taken to fill the bitmap's palette from the system palette, overcoming some buggy video drivers who don't fill the palette in. Note: Since this code does a screen shot of the form, the form must be the topmost window and the whole from must be viewable when the form shot is made. unit Prntit; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Button1: TButton; Image1: TImage; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses Printers; procedure TForm1.Button1Click(Sender: TObject); var dc: HDC; isDcPalDevice : BOOL; MemDc :hdc; MemBitmap : hBitmap; OldMemBitmap : hBitmap; hDibHeader : Thandle; pDibHeader : pointer; hBits : Thandle; pBits : pointer; ScaleX : Double; ScaleY : Double; ppal : PLOGPALETTE; pal : hPalette; Oldpal : hPalette; i : integer; begin {Get the screen dc} dc := GetDc(0); {Create a compatible dc} MemDc := CreateCompatibleDc(dc); {create a bitmap} MemBitmap := CreateCompatibleBitmap(Dc, form1.width, form1.height); {select the bitmap into the dc} OldMemBitmap := SelectObject(MemDc, MemBitmap); {Lets prepare to try a fixup for broken video drivers} isDcPalDevice := false; if GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE = RC_PALETTE then begin GetMem(pPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY))); FillChar(pPal^, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY)), #0); pPal^.palVersion := $300; pPal^.palNumEntries := GetSystemPaletteEntries(dc, 0, 256, pPal^.palPalEntry); if pPal^.PalNumEntries <> 0 then begin pal := CreatePalette(pPal^); oldPal := SelectPalette(MemDc, Pal, false); isDcPalDevice := true end else FreeMem(pPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY))); end; {copy from the screen to the memdc/bitmap} BitBlt(MemDc, 0, 0, form1.width, form1.height, Dc, form1.left, form1.top, SrcCopy); if isDcPalDevice = true then begin SelectPalette(MemDc, OldPal, false); DeleteObject(Pal); end; {unselect the bitmap} SelectObject(MemDc, OldMemBitmap); {delete the memory dc} DeleteDc(MemDc); {Allocate memory for a DIB structure} hDibHeader := GlobalAlloc(GHND, sizeof(TBITMAPINFO) + (sizeof(TRGBQUAD) * 256)); {get a pointer to the alloced memory} pDibHeader := GlobalLock(hDibHeader); {fill in the dib structure with info on the way we want the DIB} FillChar(pDibHeader^, sizeof(TBITMAPINFO) + (sizeof(TRGBQUAD) * 256), #0); PBITMAPINFOHEADER(pDibHeader)^.biSize := sizeof(TBITMAPINFOHEADER); PBITMAPINFOHEADER(pDibHeader)^.biPlanes := 1; PBITMAPINFOHEADER(pDibHeader)^.biBitCount := 8; PBITMAPINFOHEADER(pDibHeader)^.biWidth := form1.width; PBITMAPINFOHEADER(pDibHeader)^.biHeight := form1.height; PBITMAPINFOHEADER(pDibHeader)^.biCompression := BI_RGB; {find out how much memory for the bits} GetDIBits(dc, MemBitmap, 0, form1.height, nil, TBitmapInfo(pDibHeader^), DIB_RGB_COLORS); {Alloc memory for the bits} hBits := GlobalAlloc(GHND, PBitmapInfoHeader(pDibHeader)^.BiSizeImage); {Get a pointer to the bits} pBits := GlobalLock(hBits); {Call fn again, but this time give us the bits!} GetDIBits(dc, MemBitmap, 0, form1.height, pBits, PBitmapInfo(pDibHeader)^, DIB_RGB_COLORS); {Lets try a fixup for broken video drivers} if isDcPalDevice = true then begin for i := 0 to (pPal^.PalNumEntries - 1) do begin PBitmapInfo(pDibHeader)^.bmiColors[i].rgbRed := pPal^.palPalEntry[i].peRed; PBitmapInfo(pDibHeader)^.bmiColors[i].rgbGreen := pPal^.palPalEntry[i].peGreen; PBitmapInfo(pDibHeader)^.bmiColors[i].rgbBlue := pPal^.palPalEntry[i].peBlue; end; FreeMem(pPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY))); end; {Release the screen dc} ReleaseDc(0, dc); {Delete the bitmap} DeleteObject(MemBitmap); {Start print job} Printer.BeginDoc; {Scale print size} if Printer.PageWidth < Printer.PageHeight then begin ScaleX := Printer.PageWidth; ScaleY := Form1.Height * (Printer.PageWidth / Form1.Width); end else begin ScaleX := Form1.Width * (Printer.PageHeight / Form1.Height); ScaleY := Printer.PageHeight; end; {Just incase the printer drver is a palette device} isDcPalDevice := false; if GetDeviceCaps(Printer.Canvas.Handle, RASTERCAPS) and RC_PALETTE = RC_PALETTE then begin {Create palette from dib} GetMem(pPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY))); FillChar(pPal^, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY)), #0); pPal^.palVersion := $300; pPal^.palNumEntries := 256; for i := 0 to (pPal^.PalNumEntries - 1) do begin pPal^.palPalEntry[i].peRed := PBitmapInfo(pDibHeader)^.bmiColors[i].rgbRed; pPal^.palPalEntry[i].peGreen := PBitmapInfo(pDibHeader)^.bmiColors[i].rgbGreen; pPal^.palPalEntry[i].peBlue := PBitmapInfo(pDibHeader)^.bmiColors[i].rgbBlue; end; pal := CreatePalette(pPal^); FreeMem(pPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY))); oldPal := SelectPalette(Printer.Canvas.Handle, Pal, false); isDcPalDevice := true end; {send the bits to the printer} StretchDiBits(Printer.Canvas.Handle, 0, 0, Round(scaleX), Round(scaleY), 0, 0, Form1.Width, Form1.Height, pBits, PBitmapInfo(pDibHeader)^, DIB_RGB_COLORS, SRCCOPY); {Just incase you printer drver is a palette device} if isDcPalDevice = true then begin SelectPalette(Printer.Canvas.Handle, oldPal, false); DeleteObject(Pal); end; {Clean up allocated memory} GlobalUnlock(hBits); GlobalFree(hBits); GlobalUnlock(hDibHeader); GlobalFree(hDibHeader); {End the print job} Printer.EndDoc; end;