Capture Windows form paint messages

Hi Experts

I have a  standard frame on a form with a background drawn via BitBlt.  The form is maximised and covers the whole desktop area but the frame is only covering a part of my form. If another application gets the focus (ie the user decides to switch apps) and is moved or resized over the frame, the background portion of the frame where the other application has overlayed it gets redrawn. The redrawn portion is painted with the background colour property colour and not my BitBlt  image.

What I want to do is either
a) detect that another app has focus and is redrawn, moved  or sized over my app (in particular over my frame but just over my app would be enough); or
b) detect that part of my frame has been redrawn.

Once I have this I will call a redraw of my frame backgound BitBlt to repair the portion redrawn because of the other app.

I do not understand enough about how Windows redraws the portion under an app that is resizing to know how to do this.

Looking for a subclass/hook solution or ideas on which windows message to look for. No timer stuff please.

Thanks in advance
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Not sure how you BitBlt to Fram since it does not have hDc Properrty. Can you put a PictureBox on the Frame and draw to that instead? Set PictureBox AutoRedraw = True. If it doesn't persist try Picture1.refresh after BitBlt.
superg65Author Commented:
Hi danaseaman

You can create and assign a DC to a lightweight control using the API GetDC

Public Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
dim FrameDC as long
FrameDC = GetDC(fraFrame.hwnd)

Then just BitBlt using that DC.

This problem all comes about from me creating my own transparent frame as VB6 frames don't have transparency (I think the VB.Net stuff has transparent frames but I can't afford the .NET developer edition yet).

I tried some transparent frame activeXs and code off internet but none of them handle the transparency around the frame caption properly. The BitBlt version I created works really well except for the redraw if another app resizes/moves on top of it.

I looked at using a Picturebox in the frame but the frame caption is outside this so misses the transparent BitBlt.

If I can capture some sort of redraw message then can just BitBlt transparent again. Tried using a timer but then issues come up around capturing the background behind the frame again after form redraws. I'm not a fan of timers really - just don't like having code repeatedly firing on a timer event - hard to know what else is going on in a complicated app that the refiring code miight affect.

Am using subclassing to detect when my app loses focus to another app to do frame redraws on reactivation of app - all works fine - just this issue with the foreground window redrawing over my frames.


superg65Author Commented:
Hi Again D

Been thinking a bit more about your PictureBox suggestion. What I haven't tried is BitBltiing the transparency to both the frame AND a picture box inside the frame (with the Picturebox covering the frame client area). Then might be able use the PictureBox to trigger redraws of the transparency on both - maybe throught the Paint event? Will give it a try but still interested in a subclass solution.

The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

Don't you need the hWnd to Subclass?

How about a Frame control that has hWnd, hDc, and AutoRedraw?

jcFrames control version 2.0.1jcFrames control version 2.0.1

Replacent Frame Control for XP

XP Style Frame (JCSR) as Usercontrol

drawing XP style frame on picturebox
Frames aren't meant for displaying backgrounds but if you really want to include that, it should be done through subclassing and not by adding more controls. Subclassing does add some instability but as long as your window-procedure isn't error-prone, it should cause minimal problems.

Here's a little example on how to subclass for WM_PAINT and WM_NCPAINT messages. Not sure which would suit your needs.

Private Sub Form_Load()
    Call Subclass(True, Frame1.hWnd)
End Sub
Private Sub Form_Unload(Cancel As Integer)
    Call Subclass(False, Frame1.hWnd)
End Sub

Option Explicit

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long

Private Const GWL_WNDPROC   As Long = -4

Private Const WM_PAINT  As Long = &HF
Private Const WM_NCPAINT As Long = &H85

Private lngPrevProc As Long
Public Sub Subclass(ByVal blnTrue As Boolean, ByVal hWnd As Long)
    If blnTrue = True Then
        lngPrevProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
        Call SetWindowLong(hWnd, GWL_WNDPROC, lngPrevProc)
    End If
End Sub
Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Select Case uMsg
        Case WM_PAINT
            'draw window.. uncomment the below if you don't want to completely
            'override the default window-procedure.
            'WindowProc = CallWindowProc(lngPrevProc, hWnd, uMsg, wParam, lParam)
        Case WM_NCPAINT
            'draw non-client area
            'hWnd: handle to window receiving msg (frame1)
            'wParam: handle to region (hRGN) specifying where to draw
            Debug.Print "nc"
        Case Else
            WindowProc = CallWindowProc(lngPrevProc, hWnd, uMsg, wParam, lParam)
    End Select
End Function

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
superg65Author Commented:
Thanks - worked just as I needed.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.