How to call OnEraseBkgnd() to repaint the window in another function? (MFC) - c++

I am trying to call OnEraseBkgnd() to repaint the window in another function.
For example, like the code below:
...
CBitmap Background;
BITMAP bm;
CDC dcMemory;
int width, height;
...
BOOL CSplashDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CDC* dc;
Background.LoadBitmap(IDB_COVER); //Load Bitmap
Background.GetBitmap(&bm); //Load Bitmap into handle
width = 0;
height = 0;
while(width < 300)
{
width += 10;
height += 10;
OnEraseBkgnd(dc); //<--- Here I want to call OnEraseBkgnd()
Sleep(5); //Delay 5 millisecond
}
return TRUE;
}
BOOL CSplashDlg::OnEraseBkgnd(CDC* pDC)
{
///////////////////////////////////
Invalidate(); //I don't know where I should put this function
///////////////////////////////////
dcMemory.CreateCompatibleDC(pDC);
CBitmap *pOldbmp = dcMemory.SelectObject(&Background);
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0, 0, width, height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
return TRUE;
}
In the above example, I want to call OnEraseBkgnd() to repaint the window while executing inside OnInitDialog(). I have searched the Internet and it always says using Invalidate(); or RedrawWindow(); to repaint it and it'll also call the OnEraseBkgnd() function. The question is: How should I use the Invalidate(); or the RedrawWindow();? Where should I put those function?
I have put those two functions in anywhere but it still not works.
EDIT:
I have modified it. Though now Invalidate() and UpdateWindow() are success to call the OnEraseBkgnd() function. But I found another problem: Why didn't the StretchBlt work when I used Invalidate() or UpdateWindow() to repaint it but did the FillSolidRect work?
...
BOOL CMainDlg::OnInitDialog()
{
CSplashDlg Frame;
Frame.width = 0;
Frame.height = 0;
while(Frame.width <= 300)
{
Frame.width += 10;
Frame.height += 10;
Frame.Invalidate(); //<---Here I use both Invalidate() and UpdateWindow()
Frame.UpdateWindow(); //<---Here I use both Invalidate() and UpdateWindow()
Sleep(5); //Delay 5 millisecond
}
CDialog::OnInitDialog();
return TRUE;
}
BOOL CSplashDlg::OnInitDialog()
{
CDialog::OnInitDialog();
width = 0;
height = 0;
Background.LoadBitmap(IDB_COVER); //Load Bitmap
Background.GetBitmap(&bm); //Load Bitmap into handle
return TRUE;
}
BOOL CSplashDlg::OnEraseBkgnd(CDC* pDC)
{
dcMemory.CreateCompatibleDC(pDC);
CBitmap *pOldbmp = dcMemory.SelectObject(&Background);
///////////////////////////////////////////////////////////////
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0, 0, width, height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); //It doesn't work when using this one (StretchBlt)
///////////////////////////////////////////////////////////////
pDC->FillSolidRect(0, 0, width, height, RGB(255,0,0)); //But it works when using this one (FillSolidRect)
///////////////////////////////////////////////////////////////
return TRUE;
}
...

You should never call the likes of OnEraseBkgnd( ) and OnPaint( ). MFC will call these when drawing is needed. Your job is to handle the need to draw in OnEraseBkgnd( ).
Invalidate( ) causes MFC to update the drawing area and then it will call OnEraseBkgnd( ) and OnPaint( ). If you Invalidate( ) in OnPaint( ) or OnEraseBkgnd( ) the program will likely hang as it would cause an endless loop of redrawing the window.
You can call Invalidate( ) in OnInitDialog( ) but it is likely unnecessary.
So take the Invalidate out of OnEraseBkgnd( ), don't call OnEraseBkgnd( ) in OnInitDialog( ) and go from there.
You also have to have
ON_WM_PAINT( )
ON_WM_ERASEBKGND( )
in your message map for those to be called by MFC.
NOTE:
I'm not a believer in reinventing wheels. It has mostly been done before. I have not used a splash screen in my projects, but if I were to, I would start here: Splash Screen C++ Class using MFC.
I didn't download and review the code but with four stars, it should be a good place to start. MFC is not an overnight learn. When I started I read books and tons of searches to learn. You just can not make guesses about how the infrastructure works. Hope this helps...

Related

Redraw shapes in MFC

I'm trying to develop a painter app using MFC with C++.
So I set up a view in which I do the actual painting. However, when I open the color button I get "leftovers" of the menu on my canvas view.. I have no idea how to erase them.. I tried using SaveDC and RestoreDC to restore it to the previous state but no luck there. As I understand it is meant to restore properties of the device context such as pen & brush but it has no use for me...
I also need this feature so when I put up a rectangle, I could present a preview for it, but the "previews` are again presented like leftovers.
My view's OnEraseBkgbd;
BOOL CanvasView::OnEraseBkgnd(CDC* pDC)
{
if (!isBackgroundInit)
{
CRect rect;
GetClientRect(&rect);
CBrush myBrush(RGB(255, 255, 255)); // dialog background color
CBrush* pOld = pDC->SelectObject(&myBrush);
BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOld); // restore old brush
isBackgroundInit = true;
return bRes;
}
return 0;
}
My OnPaint:
void CanvasView::OnPaint()
{
CDialogEx::OnPaint();
//UpdateData(true);
CRect rect;
GetClientRect(&rect);
if (dc == nullptr)
{
dc = new CClientDC(this);
//dc->CreateCompatibleDC(dc);
HDC hdc = CreateCompatibleDC(*dc);
this->hdc = &hdc;
} else
{
BitBlt(*dc, 0, 0, (int)rect.Width(), (int)rect.Height(), *hdc, 0, 0, SRCCOPY);
}
}
How it looked at first:
How it looks when opening a color button:
How it looks after closing the color button menu(leftovers marked with red arrows):
When trying to put up a rectangle:
Any idea how to fix this and really restore drawing?
I am not sure I understand what you are trying to do.
CView has a virtual method called OnDraw. This is the method you must override:
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// first erase the entire client rectangle
CRect cr;
GetClientRect( &cr );
pDC->FillSolidRect( cr, RGB( 255, 255, 255 ) );
// your actual drawing goes here
pDC->Rectangle( 0, 0, 100, 100 );
}
You will also have to write OnEraseBkgnd:
BOOL CMyView::OnEraseBkgnd( CDC* /*pDC*/ )
{
return TRUE; // we fill the client rectangle in OnDraw
}
Also, it looks like you are trying to implement an ad-hoc memory DC. There is already one: CMemDC.

Search icon in edit control overlapped by input area

I am trying to make a search edit control in MFC that has an icon displayed in the control window all the time (regardless the state and text of the control). I have written something like this many years ago and worked very well, but the code no longer works on Windows 7 and newer (maybe even Vista, but did not try that). What happens is that the image shown in the control is overlapped with the input area (see the picture below).
The idea behind the code:
have a class derived from CEdit (that handles painting in OnPaint)
the icon is displayed on the right and the edit area is shrunk based on the size of the icon
resizing is done differently for single-line and multiline edits. For single line I call SetMargins and for multiline edits I call SetRect.
this edit resizing is applied in PreSubclassWindow(), OnSize() and OnSetFont()
This is how the edit input size is applied:
void CSymbolEdit::RecalcLayout()
{
int width = GetSystemMetrics( SM_CXSMICON );
if(m_hSymbolIcon)
{
if (GetStyle() & ES_MULTILINE)
{
CRect editRect;
GetRect(&editRect);
editRect.right -= (width + 6);
SetRect(&editRect);
}
else
{
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
}
}
}
The following image shows the problem with the single line edits (the images have been zoomed in for a better view). The yellow background is for highlighting purposes only, in real code I am using the COLOR_WINDOW system color. You can see that when the single line edit has text and has the input the left side image is painted over. This does not happen with the multiline edit where SetRect correctly sets the formatting rectangle.
I have tried using ExcludeClipRect to remove the area of the edit where the image is being displayed.
CRect rc;
GetClientRect(rc);
CPaintDC dc(this);
ExcludeClipRect(dc.m_hDC, rc.right - width - 6, rc.top, rc.right, rc.bottom);
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
This does not seem to have any effect on the result.
For reference, this is the painting method, written years ago and used to work well on Windows XP, but not correct any more.
void CSymbolEdit::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect( &rect );
// Clearing the background
dc.FillSolidRect( rect, GetSysColor(COLOR_WINDOW) );
DWORD dwMargins = GetMargins();
if( m_hSymbolIcon )
{
// Drawing the icon
int width = GetSystemMetrics( SM_CXSMICON );
int height = GetSystemMetrics( SM_CYSMICON );
::DrawIconEx(
dc.m_hDC,
rect.right - width - 1,
1,
m_hSymbolIcon,
width,
height,
0,
NULL,
DI_NORMAL);
rect.left += LOWORD(dwMargins) + 1;
rect.right -= (width + 7);
}
else
{
rect.left += (LOWORD(dwMargins) + 1);
rect.right -= (HIWORD(dwMargins) + 1);
}
CString text;
GetWindowText(text);
CFont* oldFont = NULL;
rect.top += 1;
if(text.GetLength() == 0)
{
if(this != GetFocus() && m_strPromptText.GetLength() > 0)
{
oldFont = dc.SelectObject(&m_fontPrompt);
COLORREF color = dc.GetTextColor();
dc.SetTextColor(m_colorPromptText);
dc.DrawText(m_strPromptText, rect, DT_LEFT|DT_SINGLELINE|DT_EDITCONTROL);
dc.SetTextColor(color);
dc.SelectObject(oldFont);
}
}
else
{
if(GetStyle() & ES_MULTILINE)
CEdit::OnPaint();
else
{
oldFont = dc.SelectObject(GetFont());
dc.DrawText(text, rect, DT_SINGLELINE | DT_INTERNAL | DT_EDITCONTROL);
dc.SelectObject(oldFont);
}
}
}
I have looked at other implementations of similar edit controls and they all have the same fault now.
Obviously, the question is how do I exclude the image area from the input area of the control?
I think what's going on is that CPaintDC calls BeginPaint(), which sends a WM_ERASEBKGND to the edit box. I wasn't able to ignore it, so I guess it's being sent to maybe an internal STATIC window? Not sure.
Calling ExcludeClipRect() in your OnPaint() handler won't do anything because EDIT will reset the clipping region to the whole client area in either BeginPaint() or its own WM_PAINT handler.
However, EDIT sends a WM_CTRCOLOREDIT to its parent just before painting itself, but seemingly after setting the clipping region. So you can call ExcludeClipRect() there. Sounds like an implementation detail which may change with future versions of the common controls. Indeed, it seems to have done so already.
I did a quick test without MFC on Windows 7, here's my window procedure:
LRESULT CALLBACK wnd_proc(HWND h, UINT m, WPARAM wp, LPARAM lp)
{
switch (m)
{
case WM_CTLCOLOREDIT:
{
const auto dc = (HDC)wp;
const auto hwnd = (HWND)lp;
RECT r;
GetClientRect(hwnd, &r);
// excluding the margin, but not the border; this assumes
// a one pixel wide border
r.left = r.right - some_margin;
--r.right;
++r.top;
--r.bottom;
ExcludeClipRect(dc, r.left, r.top, r.right, r.bottom);
return (LRESULT)GetStockObject(DC_BRUSH);
}
}
return ::DefWindowProc(h, m, wp, lp);
}
I then subclassed the EDIT window to draw my own icon in WM_PAINT, and then forwarded the message so I didn't have to draw everything else myself.
LRESULT CALLBACK edit_wnd_proc(
HWND h, UINT m, WPARAM wp, LPARAM lp,
UINT_PTR id, DWORD_PTR data)
{
switch (m)
{
case WM_PAINT:
{
const auto dc = GetDC(h);
// draw an icon
ReleaseDC(h, dc);
break;
}
}
return DefSubclassProc(h, m, wp, lp);
}
Note that I couldn't call BeginPaint() and EndPaint() (the equivalent of constructing a CPaintDC) in WM_PAINT because the border wouldn't get drawn. I'm guessing it has something to do with calling BeginPaint() twice (once manually, once by EDIT) and the handling of WM_ERASEBKGND. YMMV, especially with MFC.
Finally, I set the margins right after creating the EDIT:
SendMessage(
e, EM_SETMARGINS,
EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELPARAM(0, margin));
You might also have to update the margins again if the system font changes.
Have a look at this tutorial... from www.catch22.net. It gives a clear picture of how to insert a button into edit control. Though it is an Win32 example, this can be improvised to MFC as the basic structure of MFC is using win32 apis.
http://www.catch22.net/tuts/win32/2001-05-20-insert-buttons-into-an-edit-control/#
It uses WM_NCCALCSIZE to restrict the text control.

MFC how to save and reuse the current device context CDC

Well simply what I need to do is to create a grid of rectangle and fill any selected case of that grid at the user click. thus I save the parameters (color, position..). The problem is when I try to fill the case at the click event I can't any changes maybe because the device context is changed even if I use GetDC() method. So is there any way to save the current created on OnDraw() method for exmaple and use it somewhere in another function, I tried to use SaveDC() and RestoreDC() but in vain.
Here's some of my code:
void CXThiefManView::OnDraw(CDC* pDC)
{
CXThiefManDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CRect rcClient;
GetClientRect(&rcClient);
// Get the background color of the board
COLORREF clr = pDoc->GetBoardSpace(-1, -1);
// Draw the background first
pDC->FillSolidRect(&rcClient, clr);
// Create the brush for drawing
CBrush br;
br.CreateStockObject(HOLLOW_BRUSH);
CBrush* pbrOld = pDC->SelectObject(&br);
// Draw the squares
for (int row = 0; row < pDoc->GetRows(); row++)
{
for (int col = 0; col < pDoc->GetColumns(); col++)
{
// Get the color for this board space
clr = pDoc->GetBoardSpace(row, col);
// Calculate the size and position of this space
CRect rcBlock;
rcBlock.top = row * pDoc->GetHeight();
rcBlock.left = col * pDoc->GetWidth();
rcBlock.right = rcBlock.left + pDoc->GetWidth();
rcBlock.bottom = rcBlock.top + pDoc->GetHeight();
// Fill in the block with the correct color
pDC->FillSolidRect(&rcBlock, clr);
// Draw the block outline
pDC->Rectangle(&rcBlock);
}
}
saveState = pDC->SaveDC();
DrawItem(pDC, pDoc->GetThiefRow(), pDoc->GetThiefCol(), pDoc->GetThiefColor());
}
void CXThiefManView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
CXThiefManDoc* pDoc = GetDocument();
// the draw item here to fill the case
DrawItem(GetDC(), 5, 5, RGB(0, 0, 0));
}
Underneath all those MFC function, the WINAPI functions of the same name are being called. In WINAPI, GetDC returns a new device context. SaveDC & RestoreDC allow you to save and restore the state (brush, font etc...) of a specific DC handle, but that doesn't cross to other handles.
There's nothing MFC can do about it, nor can you. You have to reconfigure the new DC handle for your needs.
Handle from GetDC has to be released by ReleaseDC. Please see GetDC
Or use CClientDC dc(this) which has automatic cleanup, it's usage is similar, for example Draw(&dc,...);.
As to your main question, you can save the drawing on a bitmap. The bitmap can be saved.
define:
CBitmap m_bitmap;
CDC m_memdc;
initialize the bitmap and dc:
CClientDC dc(this);
m_bitmap.CreateCompatibleBitmap(&dc, 2000, 1200);
//this creates a bitmap as big as the screen...
m_memdc.CreateCompatibleDC(&dc);
m_memdc.SelectObject(m_bitmap);
m_memdc.FillSolidRect(0, 0, 2000, 1200, RGB(255, 255, 255));
//draw on m_memdc, then draw memdc on to dc
Usage:
void CMyWindow::OnPaint()
{
CWnd::OnPaint();
CClientDC dc(this);
CRect rc;
GetClientRect(&rc);
dc.BitBlt(0, 0, rc.Width(), rc.Height(), &m_memdc, 0, 0, SRCCOPY);
}
void CMyWindow::OnMouseMove(UINT k, CPoint p)
{
CClientDC dc(this);
CRect rc;
GetClientRect(&rc);
if (k & MK_LBUTTON)
{
//draw on m_memdc, (instead of drawing on dc)
m_memdc.SetPixel(p.x, p.y, RGB(0,0,0));
m_memdc.SetPixel(p.x, p.y+1, RGB(0,0,255));
//when finished drawing, draw m_memdc on to dc
dc.BitBlt(0, 0, rc.Width(), rc.Height(), &m_memdc, 0, 0, SRCCOPY);
}
}

How to draw on the windows desktop using the GDI API? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Draw on screen with GDI+ (or GDI) similar to Inspect
I'm attempting to write a snake game that has no windows, but freezes the foreground and draws the snake on top of it. When the game ends the foreground should be unfrozen.
I have written some testing code that is supposed to draw a square on the foreground, but all it seems to do is freeze the desktop for a second and freeze the window in the foreground until I minimize, maximize, close it, or bring another window into the foreground, and it doesn't draw anything. In the code, I try to store a bitmap of the desktop so that I can essentially reset it to it's original state and paint the square in a different position. Can anybody spot the problem with my code?
//Handle to the desktop window
HWND hDesktopWindow = GetDesktopWindow();
//Lock the window to prevent other applications drawing on it
if(!LockWindowUpdate(hDesktopWindow)){
return 1;
}
//Calling GetDC with argument NULL retrieves the desktop's DC
HDC hdcDesktop = GetDCEx(hDesktopWindow, NULL, DCX_CACHE | DCX_LOCKWINDOWUPDATE);
//Create a compatible DC to allow us to store a bitmap of the desktop
HDC hdcCompatible;
if((hdcCompatible = CreateCompatibleDC(hdcDesktop)) == NULL){
return 1;
}
//Create a compatible bitmap with the same dimensions as the desktop
HBITMAP hScrBitmap;
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
if((hScrBitmap = CreateCompatibleBitmap(hdcDesktop, cx, cy)) == NULL){
return 1;
}
//Select the bitmap into the compatible DC
SelectObject(hdcCompatible, hScrBitmap);
//Copy the Desktop into the bitmap
if(!BitBlt(hdcCompatible, 0, 0, cx, cy, hdcDesktop, 0, 0, SRCCOPY)){
return 1;
}
//Create a DC compatible with the bitmaps DC for drawing the rectangle
HDC hdcRectangle;
if(!CreateCompatibleDC((HDC)hScrBitmap)){
return 1;
}
//Create a compatible bitmap for the rectangle to be drawn in
HBITMAP hRectangleBitmap;
if(!CreateCompatibleBitmap(hdcRectangle, 100, 100)){
return 1;
}
//Fill the rectangle bitmap
if(!FloodFill(hdcRectangle, 0, 0, RGB(255,0,0))){
return 1;
}
//Copy the rectangle onto the desktop bitmap
if(!BitBlt(hdcCompatible, 100, 100, 100, 100, hdcRectangle, 0, 0, SRCCOPY)){
return 1;
}
//Copy the bitmap onto the actual desktop
if(!BitBlt(hdcDesktop, 0, 0, cx, cy, hdcCompatible, 0, 0, SRCCOPY)){
return 1;
}
//Allow time to view the result
Sleep(1000);
//Allow other applications to draw on the desktop again
LockWindowUpdate(NULL);
//Cleanup
ReleaseDC(hDesktopWindow, hdcDesktop);
DeleteDC(hdcCompatible);
DeleteObject(hScrBitmap);
Any help would be greatly appreciated :)
Trying to do this directly on the desktop is going to be problematic. You'd be better off by taking a snapshot of the desktop, then create a window that's the size of the whole desktop, copy the snapshot to the window, and do all your drawing there. (This was a common trick done in old screensavers that did things like "erode" the desktop.)
You don't own the desktop window, so you'll always have problems with invalidation and repaints.
if(!CreateCompatibleDC((HDC)hScrBitmap)){
return 1;
}
When you write C code like this then a single-point-of-return tends to be very important. A call like this is going to return FALSE, can't cast a HBITMAP to HDC, and the show is over badly. No diagnostic and no call to unlock again.
Favor the C++ RAII pattern to ensure that you always unlock:
class DesktopLocker {
public:
DesktopLocker() { LockWindowUpdate(GetDesktopWindow()); }
~DesktopLocker() { LockWindowUpdate(NULL); }
};
void foo() {
DesktopLocker lock;
// etc...
}
There's not much wisdom of painting directly to the desktop window, there's little guarantee that whatever you draw will last. Sleeping and locking updates are just band-aids. Take a look at the source of Rainmeter, it's well done.

Shrink the bitmap to required dimension

I have a bitmap of large dimension (2000 x 2000) i need to shrink that bitmap to a small dimension (150 x 150). i have written a code for it, but its not working. Can anybody help in finding the problem? The problem is the destination bitmap is just blank. I am selecting wrong DC's? I have made sure that both the source and destinations are correct. After doing bitblt do i need to do some more thing to destination bitmap?
BOOL ReSizeBitmap(CBitmap *pBitmap, CBitmap *pNewBitmap)
{
// Get new bitmap size
BITMAP bmOld;
if( !pBitmap->GetBitmap(&bmOld) )
{
return FALSE;
}
CRect rcPrev(0, 0, bmOld.bmWidth, bmOld.bmHeight);
int newWidth = 150;
int newHeight = 150;
if( newWidth < 1 || newHeight < 1 )
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
BOOL bResult = FALSE;
try
{
CDC dcDest;
CDC dcSource;
dcSource.CreateCompatibleDC(NULL);
dcDest.CreateCompatibleDC(NULL);
CBitmap* pSourceOld = dcSource.SelectObject(pBitmap);
CBitmap* pDestold = dcDest.SelectObject(pNewBitmap);
if( !pNewBitmap->CreateCompatibleBitmap(
&dcDest, newWidth, newHeight) )
{
return FALSE;
}
int oldStretchMode = dcDest.SetStretchBltMode(HALFTONE);
bResult = dcDest.StretchBlt(
0, 0, 150, 150,
&dcSource, 0, 0, bmOld.bmWidth, bmOld.bmHeight,
SRCCOPY);
dcDest.SetStretchBltMode(oldStretchMode);
dcSource.SelectObject(pSourceOld);
dcDest.SelectObject(pDestold);
bResult = TRUE;
}
catch(CResourceException* /*e*/)
{
}
return bResult;
}
Well even if the code works there is some cleaniing up to do.
RAII is one of the idiom you realy need when you are working in MFC!
if( !pNewBitmap->CreateCompatibleBitmap(&dcDest, newWidth, newHeight) )
{
return FALSE;
}
When you return FALSE or there is an exception you haven't called
cSource.SelectObject(pSourceOld);
dcDest.SelectObject(pDestold);
to cleanup before you left the function.
Create a small helper class to cleanup all the time, you don't have to worry about return or throw statements.
class SelectObjectAndCleanUp
{
CDC& deviceContext;
CBitmap *const oldSource;
public:
SelectObjectCleanUp( CDC& deviceContext, CBitmap* source )
: deviceContext(deviceContext),
oldSource( deviceContext.SelectObject(source) ) {
}
~SelectObjectCleanUp() {
deviceContext.SelectObject(oldSource)
}
};
// use of the helper
SelectObjectCleanUp sourceSelectionAndCleanup(dcSource, pBitmap );
SelectObjectCleanUp destionationSelectionAndCleanup(dcDest, pNewBitmap );
I'm not too familiar with C++, but are you selecting the new bitmap into your new DC before it's created? Also, when you call CreateCompatibleBitmap, I think you want to use your screen DC (the one you used to create the destination DC), not your compatible memory DC. So, get the screen DC with GetDC, and pass that into both CreateCompatibleDC AND CreateCompatibleBitmap.
There is a great free C++ image library called CxImage that is open source under the zlib license.
No need to reinvent the wheel.
Download http://www.gdiwatch.com/, it may show you where the error is (it can be made to work with vs 2008, too - just copy the registry keys manually from the vs2005 to vs2008 directories)
Have you tried doing the CreateCompatibleBitmap() before the SelectObject() call?
Does GetBitmap() of the new bitmap return the correct size, i.e. is the new bitmap valid?
The rest seem ok, it should work like this I believe. Does it work with other StretchBltModes?
Thanks to all of the guys who peeped and suggested solutions, any how after some debugging i found the problem. Here is the solution!!!
CBitmap *SrcBmp;
HBITMAP hBmp;
hBmp= (HBITMAP)LoadImage( NULL, L"c:\\source.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
SrcBmp = CBitmap::FromHandle(hBmp);
BITMAP BmpInfo;
SrcBmp->GetBitmap(&BmpInfo);
CDC SrcDC;
SrcDC.CreateCompatibleDC(NULL);
CBitmap DestBmp;
DestBmp.CreateCompatibleBitmap(&SrcDC,150,150);
CDC DestDC;
DestDC.CreateCompatibleDC(NULL);
CBitmap *pOldBmp1 = SrcDC.SelectObject(SrcBmp);
CBitmap *pOldBmp2 = DestDC.SelectObject(&DestBmp);
DestDC.StretchBlt(0,0,150,150,&SrcDC,0,0,BmpInfo.bmWidth,BmpInfo.bmHeight,SRCCOPY);
CImage image;
image.Attach(DestBmp);
image.Save(_T("C:\\test.bmp"), Gdiplus::ImageFormatBMP);
SrcDC.SelectObject(pOldBmp1);
DestDC.SelectObject(pOldBmp2);