Solved

Is ther a problem with the WM_PRINT message

Posted on 1997-12-12
10
769 Views
Last Modified: 2013-12-03
When sending a WM_PRINT message to a window specifying a compatible memory device context,  and using a compatible bitmap, then when using 'bitblt' to copy it on to a picture-box the window has not been correctly drawn - any child windows have been offset by and the backgrounds have not been redrawn, even when specifying the correct flags.
0
Comment
Question by:DavidDunn
  • 5
  • 4
10 Comments
 
LVL 1

Expert Comment

by:ete
ID: 1409502
Could you give a small code fragment to clarify the situation?
0
 
LVL 7

Expert Comment

by:galkin
ID: 1409503
You must specify PRF_CHILDREN in LPARAM when sending WM_PRINT message to the parent window.

0
 

Author Comment

by:DavidDunn
ID: 1409504
I've tried using the various flags. The problem can best be seen when trying to WM_PRINT an MDI form and a Child form together. The child form is offset by a small amount - leaving an unerased border around the MDI client area.
0
 

Author Comment

by:DavidDunn
ID: 1409505
I would like to send you a bitmap file showing you the result, but I don't seem to be able!

0
 

Author Comment

by:DavidDunn
ID: 1409506
The problem occurs only when there is a client and a non-client area to be printed.
The background of the child windows are not being erased even when
PRF_ERASEBKGND is specified. The child windows are offset by a small amount
which looks like its the border width.

Below is the visual basic code which prints a window (given its handle) on to a
picture-box. This code actually uses StretchBlt rather that BitBlt.

Public Sub PrintWindow(ByVal hWnd As Long)

    Dim hWndDC As Long
    Dim WindowRectangle As RECT
    Dim WindowHeight As Long
    Dim WindowWidth As Long

    ' Calculate the width and height of the window
    GetWindowRect hWnd, WindowRectangle
    WindowWidth = WindowRectangle.Right - WindowRectangle.Left
    WindowHeight = WindowRectangle.Bottom - WindowRectangle.Top

    ' Get a DC for the window and create a compatible memory DC
    hWndDC = GetWindowDC(hWnd)
    hCompatibleDC = CreateCompatibleDC(hWndDC)

    ' Create a compatible bitmap and select it into the compatible DC
    hCompatibleBMP = CreateCompatibleBitmap(hWndDC, WindowWidth, WindowHeight)
    SelectObject hCompatibleDC, hCompatibleBMP

    ' PRF_CHECKVISIBLE = &H1&
    ' PRF_CHILDREN = &H10&
    ' PRF_CLIENT = &H4&
    ' PRF_ERASEBKGND = &H8&
    ' PRF_NONCLIENT = &H2&
    ' PRF_OWNED = &H20&
    ' Send WM_PRINT message to window specifying the memory DC as the device context
    ' and setting all the PRF_??? flags
    SendMessage hWnd, WM_PRINT, hCompatibleDC, 63

    ' The compatible bitmap is now stretched to the size of the picture-box (picBox)
    StretchBlt picBox.hdc, 0, 0, picBox.Width / Screen.TwipsPerPixelX, picBox.Height / Screen.TwipsPerPixelY, hCompatibleDC, 0, 0, WindowWidth, WindowHeight, SRCCOPY

    ' Clean up
    ReleaseDC hWnd, hWndDC
    DeleteObject hCompatibleBMP
    DeleteDC hCompatibleDC
   
    picBox.Refresh

End Function

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 7

Accepted Solution

by:
galkin earned 100 total points
ID: 1409507
You problem is very interresting. Unfortunally, I don't know VB but I succeeded in forcing window with child windows to draw itself on memory DC.

This is my code:

CDC memDC;
CDC *pDC = GetDC();
memDC.CreateCompatibleDC(pDC);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(pDC, maxSize.cx, maxSize.cy);
CBitmap *pOldBitmap = (CBitmap *)memDC.SelectObject(&bitmap);
SendMessage(WM_PRINT, (WPARAM)memDC.GetSafeHdc(), PRF_ERASEBKGND|PRF_CLIENT|PRF_NONCLIENT|PRF_CHILDREN);
memDC.SelectObject(pOldBitmap);
ReleaseDC(pDC);
0
 

Author Comment

by:DavidDunn
ID: 1409508
Your code is similar to mine (although you haven't bitblt it to a picture-box
- to check that it has been draw correctly). Try your code with an MDI window
(sending the WM_PRINT message to this window to erase the background and draw
the child windows), with an MDI child window in the client area (with child
windows on this MDI child) and then check the position and background colour
of the windows, hopefully you will be able to see the problem. Try your code
with a window that have a visible non-client area as well as a visible client
area - I notice you use GetDC rather than GetWindowDC.

I Have just tried sending a WM_PRINT to the MDI Window of Microsoft Excel - the
problems still there. When a Sheet (an MDI Child Window) is tiled (so the upper
left corner of the Child window is in the upper left corner of the MDI Client
window, In the memory DC the MDI Child Window is offset by about 3 pixels ie. 3
pixels to the right and 3 pixels down). Also, the border of the MDI window (in
the memory DC) is about twice the size of the actual MDI window's border. If you
have Excel (or any other product with and MDI user interface) try sending the
WM_PRINT message to the MDI Window (not the MDI Client window).
0
 
LVL 7

Expert Comment

by:galkin
ID: 1409509
Yes, you are right, all child windows are really shifted by the width of border(by the way it is subject to check). I don't know the reason but what you can do to workaround the problem is first to let frame to draw on memory DC using WM_PRINT message without PRF_CHILDREN. Then to itterate through all child windows using GetWindow(GW_NEXT) offset window origin by SetWindowOrg according to the top left conner of the child window relative to parent frame. Send WM_PRINT message to each of this window to force each of them to draw itself on the same memory DC.
Yes, it considerably more complicated but it must work.
0
 

Author Comment

by:DavidDunn
ID: 1409510
I've tried your suggestion using SetWindowOrg etc. but it does not work. Have you managed to do it using C++?, If so can you show me the code.
0
 
LVL 7

Expert Comment

by:galkin
ID: 1409511
No I havent tried it myself so I cannot garantee it works. The problem may be caused by the fact parent frame has WS_CLIPCHILDREN style so its DC is automatically excludes all child windows. Since memory DC is compatible with this DC it has the same attributes. I had such a problem and I solved it by the following way. Before forcing child window to draw itself onto memory DC I remomed WS_CLIPCHILDREN style in parent window and restored it after all child windows drew themselves onto this DC.
If it doesn't work you can also create separate memory DC for each child window, force this window to draw itself onto this memory DC and then blit from all child memory DC on one parent memory DC. It is slower since you need to create and destroy memory DC for each window but it must work.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

758 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now