I am trying to configure a background brush to my window such that when
windows are dragged across it, the brush will cause my window background to
be drawn immediately instead of waiting for a full WM_PAINT. Here's the
catch: my background is not a solid color, but a full-fledged HBITMAP.
Currently, if I use COLOR_WINDOW as my background brush, I see solid white
being painted when windows are dragged across my window. I want a HBITMAP to
be rendered instead.
I know it should be possible because the desktop does this. Does anyone
have any idea how it can be done? My guess is that CreateDIBPatternBrushPt()
should be used. Please correct me if I'm wrong.
Lastly, is there an easy way to generate a "packed DIB" (as mentioned by
CreateDIBPatternBrushPt()) from a HBITMAP handle or do I have to do it
manually?
PS: I am not using .NET; this should be plain win32 programming. I am aware
of TextBrush, but isn't it for .NET only?
Thanks,
Gili Tzabari
This article may be of some help to you:
http://www.microsoft.com/msj/0597/c0597.aspx
Regards,
Sachin Sharma
Any more ideas?
Thanks,
Gili
"Sachin Sharma" <sachin...@hotmail.com> wrote in message
news:OOsHvr3Y...@TK2MSFTNGP11.phx.gbl...
Bitmap brushes have been part of Windows since forever. You've seen
CreateDIBPatternBrushPt. There's also the simpler CreateBrushIndirect --
look at the BS_DIBPATTERN, BS_PATTERN and BS_PATTERN8X8 styles.
--
Tim Robinson (MVP, Windows SDK)
http://mobius.sourceforge.net/
The problem seems to be with setting the window background brush. I can
paint using the brush created by CreateDIBPatternBrushPt() using FillRect()
but once I set it as the window background brush it only paints in white.
Any ideas?
Gili
"Tim Robinson" <tim.at.gaat.f...@invalid.com> wrote in message
news:2l0mtqF...@uni-berlin.de...
I can apply a solid-color brush to my window class and I can see it
affecting my window. It took me a while to find out I have to
SelectObject(DCAssociatedWithWindow, theBrush) or else the brush would
affect the window, even if SetClassLongPtr() is called. Thing is, this does
not work with a pattern brush... so what am I missing here? There doesn't
seem to be any sample code out there for setting a pattern brush for a
window background brush.
Gili
"Tim Robinson" <tim.at.gaat.f...@invalid.com> wrote in message
news:2l0mtqF...@uni-berlin.de...
Even if it doesn't work for reasons of Windows bug/feature/limitation/an
error of yours (which I still suspect is the most likely reason), you
can always handle WM_ERASEBKGND and FillRect from there,
then return... whatever docs say you're supposed to :-). Note that this
is EXACTLY what DefWindowProc does, using the window class brush. And, of
course, you can change the brush at will by changing the pattern used
for the brush.
The article cited by the other poster is fully applicable to any flavor
of Windows -- it's written in 1997. Why do you think it doesn't apply
for newer versions?
--
Jugoslav
___________
www.geocities.com/jdujic
Please reply to the newsgroup.
You can find my real e-mail on my home page above.
Secondly, the article referred to by a previous posters refers to APIs
used in 16-bit windows which are no longer used under win32. Once you drop
those APIs, it no longer talks about changing the window background brush
and so it's no good :(
Gili
"Jugoslav Dujic" <jdu...@yahoo.com> wrote in message
news:2l292gF...@uni-berlin.de...
>
> Handling WM_ERASEBKGND is not enough (I already do that). The problem is
>that under XP if you drag something on top of your window very quickly,
>windows will "quick erase" the background of your window using the
>background brush and only invoke WM_ERASEBKGND much later. As a result,
>there is a noticable delay before the background is properly drawn and
>meanwhile your white background brush is used to temporarly clear the space
>and it looks very ugly seeing a white background being dragged all across
>your window. So as you can see, I really much figure out how to change the
>background brush properly.
>
> Secondly, the article referred to by a previous posters refers to APIs
>used in 16-bit windows which are no longer used under win32. Once you drop
>those APIs, it no longer talks about changing the window background brush
>and so it's no good :(
Try this, which works in my programs:
When you register the class, set the background brush to NULL.
In WM_ERASEBKGND, paint your background, either by displaying your
bitmap directly or using a patterned brush if that is somehow
necessary.
If painting the bitmap is already part of your normal handling of
WM_PAINT, you can just return FALSE in WM_ERASEBKGND.
If your window is a child of another window, you may need to set
WS_CLIPCHILDREN when you create the parent, to avoid the parent's
WM_ERASEBKGND being called before the child window's.
It's often very useful for testing things like this to use two systems
(or at least two monitors), so you can set breakpoints without
obsscuring the window.
HTH
--
Sev
FWIW, I can pretty much confirm what Gili is saying here: if I RegisterClass
a COLOR_WINDOW+1 (white) brush but WM_ERASEBKGND the thing with black, I get
white ghosts when moving another window around the client. With a yellow
class brush, the ghosts are yellow. With a black class brush there are no
ghosts.
--
Jeff Partch [VC++ MVP]
FYI: The desktop has it fixed, somehow, because if you shake windows
very quickly across it, the background image is used as a brush and
WM_PAINT/WM_ERASEBKGND are invoked much later.
I'm dieing to find out who I can ask for help. I can't even find anyone
within Microsoft who knows. If you know anyone who would know let me know...
Gili
"Jeff Partch [MVP]" <je...@mvps.org> wrote in message
news:OZiwyVDZ...@TK2MSFTNGP12.phx.gbl...
Gili
"Severian" <seve...@chlamydia-is-not-a-flower.com> wrote in message
news:oo1oe0l46uo9emain...@4ax.com...
Yes, a NULL brush prevents Windows from erasing the background. On a
slow system with full-window dragging, there can be some delay; but
you'll see the prior window's contents directly replaced with your
bitmap, rather than a white (or background brush) fill, followed by
the paint.
Also, the slower your paint routine, the more Windows will delay; so
it behooves you to optimize your painting routine: for modern display
adapters, it may be faster to use StretchDIBits without any actual
stretching than to use BitBlt or PatBlt.
It will also help to only Blt what is within the rcPaint rectangle in
the PAINTSTRUCT.
Experimentation is required!
--
Sev
Sorry, I take back parts of my response:
1) BitBlt is usually faster, even on very fast video cards.
2) When I move my *own* windows over my image window, it shows no
delay or unrequested background painting; it's only when another app's
windows are moving over it that I see the unexpected painting.
So, I don't know the answer to your problem. There may be some
documented (or undocumented) window message that you could catch to
UpdateWindow().
You might want to use Spy++ to explore the messages received by the
Explorer wallpaper window when other windows are dragged over it.
--
Sev
I finally understand what people are talking about when they get all
upset about Microsoft not providing enough documentation for their APIs or
open-sourcing things. At least when I develop for Java if something
undocumented is happening I can open the JVM source-code and examine exactly
what is going on. With Windows I spend months trying to figure out things
that take me days to do under Java. It is getting ridiculous. There has to
be a better way.
Does Microsoft offer some sort of technical support whereby their
engineers will tell you about the undocumented inners of the Windows API
when you ask them specific questions?
Gili
"Severian" <seve...@chlamydia-is-not-a-flower.com> wrote in message
news:smtoe098kokrcdh4k...@4ax.com...
"Gili" <sitti...@bbs.darktech.org> wrote in message
news:Ob62YGI...@tk2msftngp13.phx.gbl...
> Spy++ indicates only WM_PAINT, WM_ERASEBKGND, WM_NCPAINT are being
>called. If there was some undocumented message arriving on the WindowProc
>I'd expect it to show up but it does not. Something else must be going on.
Using modern display adapters, I see very little extra background
painting when BitBlt'ing from a DDB rather than a DIB, except under a
heavy system load.
Compare the quite ugly desktop painting MS itself does with Active
Desktop enabled (at least on 2000).
I did a little more investigation. The desktop wallpaper is painted
directly by Windows internally, rather than by Explorer. (I killed
Explorer, and the wallpaper remained visible and repainted properly.)
So I seriously doubt you're going to be able to replicate exactly its
painting behavior.
> I finally understand what people are talking about when they get all
>upset about Microsoft not providing enough documentation for their APIs or
>open-sourcing things. At least when I develop for Java if something
>undocumented is happening I can open the JVM source-code and examine exactly
>what is going on. With Windows I spend months trying to figure out things
>that take me days to do under Java. It is getting ridiculous. There has to
>be a better way.
Such is life with a proprietary O/S. I've been dealing with it for
years. I continue to curse MS and their bugs, but since I choose to
develop for Windows I deal with it.
> Does Microsoft offer some sort of technical support whereby their
>engineers will tell you about the undocumented inners of the Windows API
>when you ask them specific questions?
I've no idea. "Inside Windows 2000" was a good overview of NT O/S
internals, but I don't think it dealt with UI too much. I assume it's
been updated for XP, but I haven't looked.
Gili
"Stephen Bye" <.> wrote in message
news:u%23r$MsPZEH...@TK2MSFTNGP09.phx.gbl...
I don't fully understand. Do you mean that if I use a DDB instead of a
DIB, I will get noticably better performance with I BitBlt?
> Compare the quite ugly desktop painting MS itself does with Active
> Desktop enabled (at least on 2000).
What do you mean by ugly desktop painting? As far as I can see,
Microsoft has a null brush configured for their background but *somehow*
they got their repainting code to run blindingly fast. I mean, my code does
a simple BitBlt() from a MemoryDC containing my static HBITMAP and its
around 10x slower than their code for some reason. How could that be? If I
could get my repaint code to be as fast as theirs I wouldn't have to worry
about all this brush issues.
> I did a little more investigation. The desktop wallpaper is painted
> directly by Windows internally, rather than by Explorer. (I killed
> Explorer, and the wallpaper remained visible and repainted properly.)
>
> So I seriously doubt you're going to be able to replicate exactly its
> painting behavior.
Yeah, I found the same myself after investigating for around 2 months. I
was totally new to MFC and Win32 when this all begun. I guess I take comfort
in knowing that Microsoft is hacking some code completely outside my control
and that even ActiveDesktop uses the null brush. My goal has been revised to
fixing my code so it repaints as fast as ActiveDesktop. Can you help me
figure out how the heck they do it so quickly?
Here is what I do when WM_PAINT gets invoked, in greater detail:
1) hdc = BeginPaint()
2) Create a new region "updateRegion"
3) Calculate "updateRegion" as the intersection of the system region and the
clipping region associated with the DC that is being used to paint
4) InvalidateRgn(SysListView32Wnd, updateRegion, false)
5) SendMessage(SysListView32Wnd, WM_PAINT, hdc, 0);
6) EndPaint()
Why? In a nutshell, I am a window sitting on top of SysListView32 and I
need it to draw the icons on top of my update region. The above method is
the easiest and fastest method I could think up of.
Here is what I do when WM_ERASEBKGND gets invoked:
1) GetClipBox((HDC) wParam, &rect)
2) targetWidth = rect.right - rect.left
3) targetHeight = rect.bottom - rect.top
4) BitBlt(targetDC, rect.left, rect.top, targetWidth, targetHeight,
memoryDC, rect.left, rect.top, SRCCOPY);
Lastly, I would love to use Rational Quantify to profile my code,
unfortunately it is running in another process-space and I don't know of a
way to tell Quantify to attach itself to the SysListView32 process-space
threads I spawn. Any ideas?
Thanks,
Gili
>> Using modern display adapters, I see very little extra background
>> painting when BitBlt'ing from a DDB rather than a DIB, except under a
>> heavy system load.
>
> I don't fully understand. Do you mean that if I use a DDB instead of a
>DIB, I will get noticably better performance with I BitBlt?
Yes. a DDB is a Device Dependent Bitmap, usually created with
CreateCompatibleBitmap(). It is already in the format needed to copy
the bits directly to the display. DIBs must be converted to the
display format, either by Windows, the driver, or the video card.
>> Compare the quite ugly desktop painting MS itself does with Active
>> Desktop enabled (at least on 2000).
>
> What do you mean by ugly desktop painting? As far as I can see,
>Microsoft has a null brush configured for their background but *somehow*
>they got their repainting code to run blindingly fast. I mean, my code does
>a simple BitBlt() from a MemoryDC containing my static HBITMAP and its
>around 10x slower than their code for some reason. How could that be? If I
>could get my repaint code to be as fast as theirs I wouldn't have to worry
>about all this brush issues.
Depending on the display adapter, if the HBITMAP is a DIB section
rather than a DDB, it may slow painting considerably.
>> I did a little more investigation. The desktop wallpaper is painted
>> directly by Windows internally, rather than by Explorer. (I killed
>> Explorer, and the wallpaper remained visible and repainted properly.)
>>
>> So I seriously doubt you're going to be able to replicate exactly its
>> painting behavior.
>
> Yeah, I found the same myself after investigating for around 2 months. I
>was totally new to MFC and Win32 when this all begun. I guess I take comfort
>in knowing that Microsoft is hacking some code completely outside my control
>and that even ActiveDesktop uses the null brush.
As I said, because Windows is doing it internally, exactly when
needed! It's not exactly hacking anything when the O/S does what it is
designed to do.
Processes have to wait for time slices; internally, Windows can
essentially do what it pleases, when it pleases.
>My goal has been revised to
>fixing my code so it repaints as fast as ActiveDesktop. Can you help me
>figure out how the heck they do it so quickly?
I don't know enough about Active Desktop (except that I don't use it)
to be much help.
> Here is what I do when WM_PAINT gets invoked, in greater detail:
>
>1) hdc = BeginPaint()
>2) Create a new region "updateRegion"
>3) Calculate "updateRegion" as the intersection of the system region and the
>clipping region associated with the DC that is being used to paint
>4) InvalidateRgn(SysListView32Wnd, updateRegion, false)
>5) SendMessage(SysListView32Wnd, WM_PAINT, hdc, 0);
I would replace this with UpdateWindow(SysListView32Wnd). You may also
want to experiment with RedrawWindow(), replacing 4 and 5 with
something like:
RedrawWindow(SysListView32Wnd, NULL, updateRegion,
RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
>6) EndPaint()
>
> Why? In a nutshell, I am a window sitting on top of SysListView32 and I
>need it to draw the icons on top of my update region. The above method is
>the easiest and fastest method I could think up of.
>
> Here is what I do when WM_ERASEBKGND gets invoked:
>
>1) GetClipBox((HDC) wParam, &rect)
>2) targetWidth = rect.right - rect.left
>3) targetHeight = rect.bottom - rect.top
>4) BitBlt(targetDC, rect.left, rect.top, targetWidth, targetHeight,
>memoryDC, rect.left, rect.top, SRCCOPY);
It *might* help to minimize bit copying by decomposing the region into
separate rectangles. Often when dragging, the region to display is
something like:
+-------------------------+
+ +
+ +----------------------+
+ +
+ +
+ +
+ +
+--+
While the BitBlt will be clipped to this area, it might be faster to
do two Blts, one for the wide rectangle and one for the narrow.
This is not a trivial task, though, and I don't know that it will
actually improve performance.
> Lastly, I would love to use Rational Quantify to profile my code,
>unfortunately it is running in another process-space and I don't know of a
>way to tell Quantify to attach itself to the SysListView32 process-space
>threads I spawn. Any ideas?
Just work with a window displaying an image in your own process and
profile when dragging another application's window over it.
--
Sev
Ok, so now I'm creating a DDB and placing it inside a memoryDC that is
compatible with the targetDC I will BitBlt into. So far so good. The problem
is: how do I get at the underlying bits of the new bitmap? With
CreateDIBSection() it returned a pointer to he raw data, with
CreateCompatibleBitmap() it does not. Any ideas?
Thanks,
Gili
"Gili" <sitti...@bbs.darktech.org> wrote in message
news:eGp7zgbZ...@tk2msftngp13.phx.gbl...
Or maybe are you saying we BitBlt() from DIB to DDB once (i.e. read the
original image, convert to DDB) then from that point on we only use the DDB
BitBlt() to the DC which is faster... Is there a better way?
Gili
"Stephen Bye" <.> wrote in message
news:%23AxbXqb...@TK2MSFTNGP11.phx.gbl...
The major problem here is that the HDC I pass in is *not* one that
paints on SysListView32Wnd; rather, I pass it a DC of my window so it'll
paint on top of me. If I use RedrawWindow() or UpdateWindow(),
SysListView32Wnd will simply draw on top of itself and that's no good. Is it
so bad to invoke WM_PAINT directly?
Another question is this... I've got my window on top of SysListView32
and normally it has CLIP_SIBLINGS enabled which causes it to get an empty
system region whenever its WM_PAINT gets invoked (since the system region is
the intersection of the visible region and the update region and the visible
region is empty since it clipped out the sibling -- my window -- which
completely covers it). The problem is that I don't like removing
CLIP_SIBLINGS from the SysListView32 class. For one, SysListView32 is a
window class used by other non-desktop windows such as Explorer
file-browsing windows. All I'm really interested in is calling
SysListView32's WM_PAINT and getting its update region independant of its
visible region. Do you know of any way to get that? I can't use
GetUpdateRegion() because if you use it after BeginPaint() it is empty and
if you use it before BeginPaint() it isn't guaranteed to be the real update
region that gets used when BeginPaint() is invoked (some instruction could
execute between the two). Any ideas?
Gili
"Gili" <sitti...@bbs.darktech.org> wrote in message
news:OSL9L0bZ...@TK2MSFTNGP12.phx.gbl...
You can use GetDIBits and SetDIBits.
--
-GJC [MS Windows SDK MVP]
-Software Consultant (Embedded systems and Real Time Controls)
- http://www.mvps.org/ArcaneIncantations/consulting.htm
-gcha...@mvps.org
How often is the data changing? How much of the bitmap is affected?
You can use GDI commands to paint in the memory DC, including
StretchDIBits and friends, to update all or portions of the DDB.
--
Sev
>> > Here is what I do when WM_PAINT gets invoked, in greater detail:
>> >
>> >1) hdc = BeginPaint()
>> >2) Create a new region "updateRegion"
>> >3) Calculate "updateRegion" as the intersection of the system region and
>the
>> >clipping region associated with the DC that is being used to paint
>> >4) InvalidateRgn(SysListView32Wnd, updateRegion, false)
>>
>> >5) SendMessage(SysListView32Wnd, WM_PAINT, hdc, 0);
>>
>> I would replace this with UpdateWindow(SysListView32Wnd). You may also
>> want to experiment with RedrawWindow(), replacing 4 and 5 with
>> something like:
>>
>> RedrawWindow(SysListView32Wnd, NULL, updateRegion,
>> RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
>
> The major problem here is that the HDC I pass in is *not* one that
>paints on SysListView32Wnd; rather, I pass it a DC of my window so it'll
>paint on top of me. If I use RedrawWindow() or UpdateWindow(),
>SysListView32Wnd will simply draw on top of itself and that's no good. Is it
>so bad to invoke WM_PAINT directly?
I don't know if it is bad or not.
For WM_PAINT, neither wparam or lparam is used. They are used for
WM_PRINT and WM_PRINTCLIENT. If this is working with WM_PAINT, you are
depending on undocumented behavior in SysListView32Wnd.
> Another question is this... I've got my window on top of SysListView32
>and normally it has CLIP_SIBLINGS enabled which causes it to get an empty
>system region whenever its WM_PAINT gets invoked (since the system region is
>the intersection of the visible region and the update region and the visible
>region is empty since it clipped out the sibling -- my window -- which
>completely covers it). The problem is that I don't like removing
>CLIP_SIBLINGS from the SysListView32 class. For one, SysListView32 is a
>window class used by other non-desktop windows such as Explorer
>file-browsing windows. All I'm really interested in is calling
>SysListView32's WM_PAINT and getting its update region independant of its
>visible region. Do you know of any way to get that? I can't use
>GetUpdateRegion() because if you use it after BeginPaint() it is empty and
>if you use it before BeginPaint() it isn't guaranteed to be the real update
>region that gets used when BeginPaint() is invoked (some instruction could
>execute between the two). Any ideas?
I don't know the answers to all of these questions, but I don't
understand why your window is on top of the SysListView32. Shouldn't
it be beneath it?
IIRC, you said you are running this code in the context of the process
that owns SysListView32, so I would think you could either make it the
parent, or a sibling under it in the z-order.
If I were you, I would spend a lot of time with Spy++ and Active
Desktop, seeing who owns which windows, what their relationships and
flags are, and what messages they process.
--
Sev
I also noticed that the desktop window is owned by the CSRSS process
(at least on Win2k), which runs at above-normal priority. I don't know
if Windows will allow you to run your code in this process's context
or not, but it may help.
--
Sev
You're talking about the root (desktop) window. You cannot,
unfortunately, subclass it. I don't think priority is the problem, though,
because I could just place myself into the same process-space as
SysListView32 and up my own priority.
Gili
This copies data from/to buffers instead of letting me edit in-place.
Thanks anyway,
Gili
My question is this... I create two memoryDCs using CreateCompatibleDC()
but both of them are compatible with my windowDC. Now, when I place my DIB
into a memoryDC that is compatible with the window DC does it convert the
DIB to DDB when you do anything with it (like BitBlt)? That is, what is the
point of surrounding a DIB with a DC that has a different format? Isn't it
going to convert the DIB no matter what you do with it? I assume this means
it is also impossible to BitBlt from DIB to DIB because the MemoryDCs you
surround it with will have a device-dependant format.
Gili
That's the best you can do with a DDB because on modern hardware, they
exist in the memory on the video adapter, not main computer memory.
Gili
"Severian" <seve...@chlamydia-is-not-a-flower.com> wrote in message
news:gapte0pukb3cr3o05...@4ax.com...