Solved

Print a Window

Posted on 2002-07-17
6
396 Views
Last Modified: 2010-04-04
How can I print the contents of a specific 'child-window' on a printer. I'm looking for something like:

Print(WHandle)
0
Comment
Question by:detempel
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
6 Comments
 
LVL 3

Expert Comment

by:LukA_YJK
ID: 7160171
You can use Print method of any Form. Actually it uses GetFormImage: TBitmap and draws that to the printer HDC.
0
 

Author Comment

by:detempel
ID: 7160561
I see my question is not complete. I'm referring to a window outside the Delphi-environment/program. I want to print a (child)-window from ANY application using Delphi.

With Delphi I can look for the right WindowHandle by scanning for text in the title in all ChildWindows from the TopWindow of the application in question.
0
 
LVL 3

Accepted Solution

by:
LukA_YJK earned 200 total points
ID: 7161719
OK... I got it, you can send WM_PRINT message to this Window. To specify Printer HDC as a parameter probably you should use CreateDC with appropriate parameters. Hope it will be helpfull...
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 7

Expert Comment

by:Cynna
ID: 7161811
LukA_YJK,

WM_PRINT won't always work. Some system windows will do OK most of the time, but window of arbitrary application doesn't tipically handle WM_PRINT event for the owner draw area.
Therefore, using WM_PRINT will often lead to 'half-printed' windows, where system drawn elements (like caption bar, menu, etc...) are printed, but application drawn elements are not.

detempel,

I'm afraid you must bring window of interest in the foreground to be able to capture it's bitmap and print it. I pasted together a set of more or less well-known procedures from different NGs and FAQs, and used them in a demo. Copy/paste them and see if it works for you.
Flicker will be unavoidable, due to the pulling/pushing window to/from foreground. Also, window is streched to fit the size of the paper. Adjust this as you see fit.


function GetWindowBitmap(hWindow:hWnd):HBitmap;
var DC,MemDC:HDC;
    bmWidth,bmHeight:Integer;
    TR:tRect;
    bm,obm:HBitmap;
begin
   // full window bitmap
   GetWindowRect(hWindow,TR);
   { note the  +1 }
   bmWidth:=TR.Right-TR.Left+1;
   bmHeight:=TR.Bottom-TR.Top+1;
   // Window DC
   DC:=GetDC(GetDesktopWindow);
   MemDC:=CreateCompatibleDC(DC);
   bm:=CreateCompatibleBitmap(DC,bmWidth,bmHeight);
   // now select the bitmap to memDC
   obm:=SelectObject(MemDC,bm);
   // and copy the window
   BitBlt(MemDC,0,0,bmWidth,bmHeight, DC, TR.Left, TR.Top,SRCCOPY);
   // clean up
   SelectObject(MemDC,obm);
   DeleteDC(MemDC);
   ReleaseDC(GetDesktopWindow, DC);
   // here is your bitmap
   GetWindowBitmap:=bm;
end;

procedure DrawImage(Canvas: TCanvas; DestRect: TRect; ABitmap:
TBitmap);
var
  Header, Bits: Pointer;
  HeaderSize:  DWORD;
  BitsSize: DWORD;
begin
  GetDIBSizes(ABitmap.Handle, HeaderSize, BitsSize);
  Header := AllocMem(HeaderSize);
  Bits := AllocMem(BitsSize);
  try
    GetDIB(ABitmap.Handle, ABitmap.Palette, Header^, Bits^);
    StretchDIBits(Canvas.Handle, DestRect.Left, DestRect.Top,
        DestRect.Right, DestRect.Bottom,
        0, 0, ABitmap.Width, ABitmap.Height, Bits,TBitmapInfo(Header^),
        DIB_RGB_COLORS, SRCCOPY);
  finally
    FreeMem(Header, HeaderSize);
    FreeMem(Bits, BitsSize);
  end;
end;

{ Print a Bitmap using the whole Printerpage }
procedure PrintBitmap(ABitmap: TBitmap);
var
  relheight, relwidth: integer;
begin
  screen.cursor := crHourglass;
  Printer.BeginDoc;
  if ((ABitmap.width / ABitmap.height) > (printer.pagewidth /printer.pageheight)) then
  begin
    { Stretch Bitmap to width of Printerpage }
    relwidth := printer.pagewidth;
    relheight := MulDiv(ABitmap.height, printer.pagewidth,ABitmap.width);
  end else
  begin
    { Stretch Bitmap to height of Printerpage }
    relwidth := MulDiv(ABitmap.width, printer.pageheight, ABitmap.height);
    relheight := printer.pageheight;
  end;
  DrawImage(Printer.Canvas, Rect(0, 0, relWidth, relHeight), ABitmap);
  Printer.EndDoc;
  screen.cursor := crDefault;
end;


procedure PrintWindow(WinHandle: HWnd);
var currentWin: HWnd;
    b: TBitmap;
begin
  b:=TBitmap.Create;
  currentWin:=GetForegroundWindow;
  SetForegroundWindow(WinHandle);
  while GetForegroundWindow<>WinHandle do Sleep(0);
   b.Handle:=GetWindowBitmap(WinHandle);
  SetForegroundWindow(currentWin);
  PrintBitmap(b);
  b.Free;
end;




// DEMO:
//-----------
procedure TForm1.Button1Click(Sender: TObject);
begin // Prints the notepad window
  if FindWindow('Notepad',nil)<>0 then
     PrintWindow(FindWindow('Notepad',nil))
  else ShowMessage('Notepad window not found!');
end;
0
 
LVL 3

Expert Comment

by:LukA_YJK
ID: 7166396
Cynna, thanks for interesting fact about WM_PRINT. But maybe my first comment is not a bad idea. We can Use the Source ;) in Forms.pas Actually the implementation of GetFormImage is different in different versions. But I liked Delphi 2.0 version, seems it is TForm independent. Let me quote the following piece of code:

function TForm.GetFormImage: TBitmap;
var
  ScreenDC, PrintDC: HDC;
  OldBits, PrintBits: HBITMAP;
  PaintLParam: Longint;

  procedure PrintHandle(Handle: HWND);
  var
    R: TRect;
    Child: HWND;
    SavedIndex: Integer;
  begin
    if IsWindowVisible(Handle) then
    begin
      SavedIndex := SaveDC(PrintDC);
      Windows.GetClientRect(Handle, R);
      MapWindowPoints(Handle, Self.Handle, R, 2);
      with R do
      begin
        SetWindowOrgEx(PrintDC, -Left, -Top, nil);
        IntersectClipRect(PrintDC, 0, 0, Right - Left, Bottom - Top);
      end;
      SendMessage(Handle, WM_ERASEBKGND, PrintDC, 0);
      SendMessage(Handle, WM_PAINT, PrintDC, PaintLParam);
      Child := GetWindow(Handle, GW_CHILD);
      if Child <> 0 then
      begin
        Child := GetWindow(Child, GW_HWNDLAST);
        while Child <> 0 do
        begin
          PrintHandle(Child);
          Child := GetWindow(Child, GW_HWNDPREV);
        end;
      end;
      RestoreDC(PrintDC, SavedIndex);
    end;
  end;

begin
  Result := nil;
  ScreenDC := GetDC(0);
  PaintLParam := 0;
  try
    PrintDC := CreateCompatibleDC(ScreenDC);
    try
      PrintBits := CreateCompatibleBitmap(ScreenDC, ClientWidth, ClientHeight);
      try
        OldBits := SelectObject(PrintDC, PrintBits);
        try
          { Clear the contents of the bitmap }
          FillRect(PrintDC, ClientRect, Brush.Handle);

          { Paint form into a bitmap }
          PrintHandle(Handle);
        finally
          SelectObject(PrintDC, OldBits);
        end;
        Result := TBitmap.Create;
        Result.Handle := PrintBits;
        PrintBits := 0;
      except
        Result.Free;
        if PrintBits <> 0 then DeleteObject(PrintBits);
        raise;
      end;
    finally
      DeleteDC(PrintDC);
    end;
  finally
    ReleaseDC(0, ScreenDC);
  end;
end;

Maybe we should omit coordinate mapping and printing Child windows. It seems the Force is strong with detempel, so it will not be a problem to print obtained bitmap... Hope it will be helpfull...
0
 

Author Comment

by:detempel
ID: 7166975
Thanks for your efforts in helping me. For the moment I won't have to solve this problem so I want to give my points at this moment and close the question.

Erik.
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi Firemonkey Need Sample for Online Shopping Example. 2 191
find a node in VST 2 78
Delphi Yen format 3 58
Twebbrowser add css to the header 3 37
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

735 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question