Selecting a bitmap into a DC

Discussion in 'MFC' started by ever_thus, Jan 10, 2007.

  1. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    I need to take an image from a bitmap file and display it in my GUI. To load the image I use LoadImage with LR_LOADFROMFILE. Then I select it into a memory DC and finally call BitBlt to get it onto the screen.

    My problem seems to be that when I select it into memory DC it does not get selected. I assume this because SelectObject is returning NULL. I cannot get any further information as SelectObject does not appear to set GetLastError (which is not mentioned in the documentation for SelectObject).

    I wonder if SelectObject will work on an object loaded with LoadImage. The documentation on SelectObject list the functions with which the GDI object must be created; LoadImage is not among them. However a bit of browsing comes up with loads of examples of objects created with LoadImage being selected into DCs. In any case, if LoadImage will not work what should I be using?

    I'm somewhat new to GDI, so any help would be appreciated.
     
  2. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    Can you share the code you are having problem with.

    Here is the simple one which loads an image and draws on the DC in the paint of the DialogBased app
    In InitDialog
    Code:
    m_hBmp = ::LoadImage(NULL,"E:\\flowers.bmp",IMAGE_BITMAP,NULL,NULL,LR_LOADFROMFILE|LR_DEFAULTSIZE);
    
    In Paint
    Code:
    CDC dcSrc;
    dcSrc.CreateCompatibleDC(NULL);
    dcSrc.SelectObject(m_hBmp);
    dc.StretchBlt(0,0,100,100,&dcSrc,0,0,100,100,SRCCOPY);
    
    Of course the 0,0,100,100 should be adjusted with your rect.
     
  3. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    It's scattered around the code but here are the relevant bits:

    In the constructor
    Code:
    mnubmp = (HBITMAP) LoadImage (0, bmpsrc, IMAGE_BITMAP, bmplen, height, LR_LOADFROMFILE);
    where bmpsrc is a char* parameter. All other variables are instance variables with valid values. LoadImage returns a valid handle.

    In the draw method
    Code:
    HDC hdcMem = CreateCompatibleDC (dis->hDC);
    HGDIOBJ hbmpOld = SelectObject (hdcMem, mnubmp);
    HGDIOBJ brushOld = SelectObject (hdcMem, brush);
    FillRect (dis->hDC, &dis->rcItem, (HBRUSH) brush);
    ExtFloodFill (hdcMem, 0, 0, GetPixel (hdcMem, 0, 0), FLOODFILLSURFACE);
    BitBlt (dis->hDC, dis->rcItem.left + ((maxbmplen + BMP_PADD - bmplen) /2), dis->rcItem.top + ((dis->rcItem.bottom - dis->rcItem.top - height) / 2),maxbmplen, height, hdcMem, 0, 0, SRCCOPY);
    where dis is a DRAWITEMSTRUCT* parameter and brush is a HBRUSH parameter. All other variables are instance variables with valid values. mnubmp retains its valid value. CreateCompatibleDC return a valid handle; the first SelectObject returns NULL.
     
  4. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    Have you tried my one.
     
  5. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    Same problem!!! Is there something wrong with my system?

    Whew! First time using MFC. It's so much more complicated than the old fashoined way.
     
  6. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    My one is working perfectly fine. Have you changed the url to the bmp file correctly.
     
  7. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    Yes. The debugger reveals that LoadImage is working fine. It's SelectObject that isn't.
     
  8. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    Check the error with GetLastError
     
  9. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    Ok, it appears SelectObject does set GetLastError. My mistake.

    The first time the draw methos is called CreateCompatibleDC set GetLastError to 0 (success). On subsequent calls it sets it to 87 (invalid parameter). However it still returns a non NULL HDC. SelectObject consistently sets GetLastError to 0, but returns a NULL HGDIOBJ.

    Curiouser and curiouser. What's going on here.
     
  10. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    I should point out that I'm releasing all unused DCs, so I don't think memory leaks are the problem. Here's the code (from the draw method).

    Code:
    SelectObject (hdcMem, hbmpOld);
    SelectObject (hdcMem, brushOld);
    DeleteObject (brush);
    DeleteDC (hdcMem);
     
  11. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    You follow the steps and see if the things works and in MFC take one step at a time as that will help you know what the prob is. You will not be able to make a very good app with the hello world but slowly you will be.

    1. Take a Dialog based application.
    2. Declare a varible in the Dialog header class as HANDLE m_hBmp.
    3. Go to the OnInitDialog and add the following line at the last
    Code:
    m_hBmp = ::LoadImage(NULL,"E:\\flowers.bmp",IMAGE_BITMAP,NULL,NULL,LR_LOADFROMFILE|LR_DEFAULT  SIZE);
    Remember to put the correct bmp file path.
    4. Now put the following in the OnPaint method
    Code:
    CDC dcSrc;
    dcSrc.CreateCompatibleDC(NULL);
    dcSrc.SelectObject(m_hBmp);
    dc.StretchBlt(0,0,100,100,&dcSrc,0,0,100,100,SRCCOPY);
    above the CDialog::OnPaint() and comment out the CDialog::OnPaint. Also rememeber its in the else part of the IsIconic part.

    See if it works.

    Now substitute your code slowly into the working app and find where is the prob.
     
  12. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    Dude, I did all of the above. As I said, your example app still didn't work.
     
  13. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83
    Then probably you need an error issue as the steps I wrote is done by me and its working.
     
  14. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    You're probably right. Thanks for your help anyway.
     
  15. rcook

    rcook New Member

    Joined:
    Jan 29, 2007
    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    0
    Look, I'm fairly new at this, but are you sure SelectObject is not supposed to be returning NULL? According to my docs, it returns the handle of whatever was selected before, and if that was nothing, then NULL might be reasonable. According to what I'm reading, it isn't supposed to be a valid handle, necessarily.

    And whether or not that works, can you tell me where LR_LOADFROMFILE is defined? I can't find it anywhere.

    rc
     
  16. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    SlectObject should return the default bitmap initialized for the DC. If I'm wrong then I really don't know what's failing, because the bitmaps aren't getting displayed.

    LR_LOADFROMFILE is defined in winuser.h, but including windows.h will include it too.
     
  17. ever_thus

    ever_thus New Member

    Joined:
    Jan 3, 2007
    Messages:
    53
    Likes Received:
    0
    Trophy Points:
    0
    OK!! After much frustration I found the real problem. The object containing the image is allocated like so:

    Code:
    menu_items.push_back (MenuItem (OLE2T (i_bmpsrc.bstrVal), OLE2T (i_mnustr.bstrVal), OLE2T (i_cmdstr1.bstrVal), OLE2T (i_cmdstr2.bstrVal)));
    (where menu_items is a vector and the parameters are read in from an XML file).

    MenuItem has a destructor lwith the following line:

    Code:
    DeleteObject (mnubmp);
    The problem is that as soon as the anonymous MenuItem goes out of scope (at the right parens), although the object continues to exist (because of the copy in menu_items), the destructor is called. I know this because a MessageBox put into the destructor executes at that point.

    However, now that I've found the problem I don't know what to do about it. The push_back is called in a function that returns as soon as the XML parser is cleaned up, so the argument to push_back will necessarily go out of scope.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice