Capture Windows form paint messages

Posted on 2008-06-20
Medium Priority
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

ID: 21836671
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

ID: 21839032
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

ID: 21839153
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.

NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.

LVL 22

Expert Comment

ID: 21839191
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 2000 total points
ID: 21839549
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

ID: 31469381
Thanks - worked just as I needed.

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

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

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

850 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