Other uses for bitmap brushes

Date:October 9, 2003 / year-entry #91
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20031009-00/?p=42213
Comments:    13
Summary:Bitmap brushes used to be these little 8×8 monochrome patterns that you could use for hatching and maybe little houndstooth patterns if you were really crazy. But you can do better. CreatePatternBrush lets you pass in any old bitmap - even a huge one, and it will create a brush from it. The bitmap will...

Bitmap brushes used to be these little 8x8 monochrome patterns that you could use for hatching and maybe little houndstooth patterns if you were really crazy. But you can do better.

CreatePatternBrush lets you pass in any old bitmap - even a huge one, and it will create a brush from it. The bitmap will automatically be tiled, so this is a quick way to get bitmap tiling. Let GDI do all the math for you!

This is particularly handy when you're stuck with a mechanism where you are forced to pass an HBRUSH but you really want to pass an HBITMAP. Convert the bitmap to a brush and return that brush instead.

For example, let's take our scratch program and give it a custom tiled background by using a pattern brush.

HBRUSH CreatePatternBrushFromFile(LPCTSTR pszFile)
{
    HBRUSH hbr = NULL;
    HBITMAP hbm = (HBITMAP)LoadImage(g_hinst, pszFile,
                   IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if (hbm) {
        hbr = CreatePatternBrush(hbm);
        DeleteObject(hbm);
    }
    return hbr;
}

BOOL
InitApp(LPSTR lpCmdLine)
{
    BOOL fSuccess = FALSE;
    HBRUSH hbr = CreatePatternBrushFromFile(lpCmdLine);
    if (hbr) {
        WNDCLASS wc;
    
        wc.style = 0;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = g_hinst;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = hbr;
        wc.lpszMenuName = NULL;
        wc.lpszClassName = CLASSNAME;
    
        fSuccess = RegisterClass(&wc);
        // Do not delete the brush - the class owns it now
    }
    return fSuccess;
}

With a corresponding adjustment to WinMain:

    if (!InitApp(lpCmdLine)) return 0;

Pass the path to a *.bmp file on the command line, and bingo, the window will tile its background with that bitmap. Notice that we did not have to change anything other than the class registration. No muss, no fuss, no bother.

Here's another way you can use bitmap brushes to save yourself a lot of work. Start with a new scratch program and change it as follows:

HBRUSH g_hbr; // the pattern brush we created

HBRUSH CreatePatternBrushFromFile(LPCTSTR pszFile)
{ ... same as above ... }

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
    BeginPath(pps->hdc);
    Ellipse(pps->hdc, 0, 0, 200, 100);
    EndPath(pps->hdc);
    HBRUSH hbrOld = SelectBrush(pps->hdc, g_hbr);
    FillPath(pps->hdc);
    SelectBrush(pps->hdc, hbrOld);
}

And add the following code to WinMain before the call to CreateWindowEx:

    g_hbr = CreatePatternBrushFromFile(lpCmdLine);
    if (!g_hbr) return 0;

This time, since we are managing the brush ourselves we need to remember to

    DeleteObject(g_hbr);

at the end of WinMain before it returns.

This program draws an ellipse filled with your bitmap. The FillPath function uses the currently-selected brush, so we select our bitmap brush (instead of a boring solid brush) and draw with that. Result: A pattern-filled ellipse. Without a bitmap brush, you would have had to do a lot of work manually clipping the bitmap (and tiling it) to the ellipse.


Comments (13)
  1. KiwiBlue says:

    Nice. But if I remember correctly, it was not supported on Win95.

    BTW: can you explain why PaintDesktop fails with memory device context on 2k/XP?

  2. Mal Ross says:

    Neat, but I’m intrigued – what prompted you to post about this? Any particular example you had in mind?

  3. Raymond Chen says:

    You can’t PaintDesktop into a memory DC because PaintDesktop does an EnumDisplayMonitors to render the desktop on each monitor, but a memory DC doesn’t have any monitors.

    There was nothing in particular to inspire this topic. Sometimes I’ll just write about something I think doesn’t get written about enough.

  4. Rodrigo Strauss says:

    I’m programming a GINA, and debugging using the checked version of Winlogon. Look this err message:

    RTL: RtlNtStatusToDosError(0x52e): No Valid Win32 Error Mapping
    RTL: Edit ntosrtlgenerr.c to correct the problem
    RTL: ERROR_MR_MID_NOT_FOUND is being returned
    156.88> Winlogon-Trace-SAS: LOGONNOTIFY message 9

    Can you send the file, so I can correct the problem??? LOL :)
    Yesterday my VS.NET asked me for some .c file from NT kernel. I told him I don’t have, and he said: "ok, take this assembly code instead". :-)

  5. Anthony says:

    I have two questions for Raymond but couldn’t find a way to email him directly. Why has fast alt tab switching in Windows not been working exactly as it should since I can remember. I am a web developer so usually have several apps open when developing. It seems the algorithm for what you last used when alt-tab switching sometimes puts the last app you used at the bottom of the stack, so you have to tab through the 14 other windows just to get to the one you used immediately previous to switching. And to top it off, this action seems intermittent. Sometimes it works great, other times it works as I described. Have you come across this bizarre behaviour at all?

    Also the other thing I wanted to ask about is when you right click on an item in the task bar, you get a pop-up menu with the Close (Alt F4) option listed at the bottom. Standard fair in Windows…right.

    I got into a habit of closing down windows by right clicking then selecting the bottom option. Which works great except for those apps that don’t have Close as the bottom option in the right click menu – they have something else instead. Examples are any HTML Help app, which have “About HTML Help”, and MS Windows own Help window, which has "Go To" as the bottom option…(yeah that’s intuitive).

    I was wondering if you could shed any light on these two idiosyncrasies?

  6. Israel says:

    Anthony-I haven’t any explanation, just this note: Alt-shift-tab iterates the coolswitch list backwards if that happens to you (ie your app moves to the end of the list).

  7. tekumse says:

    Anthony – about tastk switching
    the app moves to the bottom of the stack when minimized. If you just use alt-tab it will be the next.

  8. Joe says:

    Also, for the taskbar context menu, it mirrors the system menu — the menu you get when you click on the application icon of a window. Applications are free to modify this menu as they wish (more or less). Some applications choose to put additional items on this menu.

  9. Alex says:

    2Anthony

    You can hold Ctrl key while selecting items in task bar. Then right click and you’ll get "common denominator" menu for them. So, you’ll be able to close (minimize, etc.) all of them at once.

  10. Jared says:

    "Sometimes I’ll just write about something I think doesn’t get written about enough."

    Hehe. Any chance you take suggestions for stuff that "doesn’t get written about enough"?

  11. Andreas Häber says:

    Alex: thanks for that tip – very nice feature :)

  12. Raymond Chen says:

    If you want to suggest a topic, add a comment or email me. (Note that I get approximately a thousand of pieces of email a week, and that’s not counting the spam, so please don’t be hurt if I don’t personally acknowledge your message. I did get it and I did read it.) Note that I often decide not to comment on a topic because I don’t feel qualified to discuss it, or discussing it would reveal proprietary information, or because I don’t think the topic is of general interest. Again, please don’t be offended if this happens to your topic.

  13. Raymond Chen says:

    Commenting on this article has been closed.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index