Capture Windows form paint messages

Posted on 2008-06-20
Last Modified: 2013-12-03
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
Question by:superg65
  • 3
  • 2
LVL 22

Expert Comment

Comment Utility
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.

Author Comment

Comment Utility
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.



Author Comment

Comment Utility
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.

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

LVL 22

Expert Comment

Comment Utility
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
LVL 17

Accepted Solution

zzzzzooc earned 500 total points
Comment Utility
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

Author Closing Comment

Comment Utility
Thanks - worked just as I needed.

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

772 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

11 Experts available now in Live!

Get 1:1 Help Now