用一个《WINDOWS程序设计》里面的HELLOWORLD,加上十来句能暴露问题的代码,展现了一个不能理解的问题。代码如下,具体问题见注释:
#include <windows.h>
#pragma comment(lib,"msimg32.lib")        LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
//以下两副图自己指定
HBITMAP hBmpBK = (HBITMAP)LoadImage(NULL,"e:\\test\\bk1.bmp",IMAGE_BITMAP, 0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
HBITMAP hBmpRole = (HBITMAP)LoadImage(NULL,"e:\\test\\rec2.bmp",IMAGE_BITMAP, 0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
        int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,        
                   PSTR szCmdLine, int iCmdShow)        
{        
    static TCHAR szAppName[] = TEXT ("HelloWin") ;        
    HWND   hwnd ;        
    MSG    msg ;        
    WNDCLASS wndclass ; 
   wndclass.style        = CS_HREDRAW | CS_VREDRAW ;        
   wndclass.lpfnWndProc  = WndProc ;        
    wndclass.cbClsExtra   = 0 ;        
    wndclass.cbWndExtra   = 0 ;        
    wndclass.hInstance    = hInstance ;        
    wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;        
  wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;        
   wndclass.hbrBackground= NULL ;        
  wndclass.lpszMenuName = NULL ;        
    wndclass.lpszClassName= szAppName ;            if (!RegisterClass (&wndclass))      
    {        
            MessageBox (  NULL, TEXT ("This program requires Windows NT!"),        
                                  szAppName, MB_ICONERROR) ;        
            return 0 ;        
    }
        
    hwnd = CreateWindow( szAppName,      // window class name        
                   TEXT ("The Hello Program"),   // window caption        
                   WS_SYSMENU,  // window style        
                   CW_USEDEFAULT,// initial x position        
                   CW_USEDEFAULT,// initial y position        
                   800,// initial x size        
                   600,// initial y size        
                   NULL,                 // parent window handle        
               NULL,            // window menu handle        
               hInstance,   // program instance handle        
               NULL) ;      // creation parameters
        
   SetTimer(hwnd,1,300,NULL);        
    ShowWindow (hwnd, iCmdShow) ;        
    UpdateWindow (hwnd) ;        
   
        
    while (GetMessage (&msg, NULL, 0, 0))        
    {        
            TranslateMessage (&msg) ;        
          DispatchMessage (&msg) ;        
    }        
    return msg.wParam ;        
}
        LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)        
{        
    HDC hdc ,hDcBuffer,hDcObj;        
HBITMAP hOldBk,hOldRole;
    PAINTSTRUCT ps ;         int x,y,iRGB,iRGBBk;
    RECT          rect ;       
   
        
    switch (message)        
    {        
    case WM_CREATE:    
        
            return 0 ;
case WM_TIMER:
  InvalidateRect(hwnd,NULL,TRUE);
  return 0;            case   WM_PAINT:        
            hdc = BeginPaint (hwnd, &ps) ;
        
hDcBuffer,hDcObj;
hDcBuffer = CreateCompatibleDC(hdc);
hDcObj = CreateCompatibleDC(hdc); hOldBk = (HBITMAP)SelectObject(hDcBuffer,hBmpBK); BITMAP bitmapBK,bitmapRole;
GetObject(hBmpBK,sizeof(BITMAP),&bitmapBK);
GetObject(hBmpRole,sizeof(BITMAP),&bitmapRole); unsigned char * pb,*pr;
pb = new unsigned char [bitmapBK.bmHeight * bitmapBK.bmWidthBytes];
pr = new unsigned char [bitmapRole.bmHeight * bitmapRole.bmWidthBytes]; GetBitmapBits(hBmpBK,bitmapBK.bmHeight * bitmapBK.bmWidthBytes,pb);
GetBitmapBits(hBmpRole,bitmapRole.bmHeight * bitmapRole.bmWidthBytes,pr); for(y = 0 ; y < bitmapRole.bmHeight;y++)
{
for (x = 0; x < bitmapRole.bmWidthBytes/(bitmapRole.bmBitsPixel/8);x++)
{
iRGB = y * ((bitmapRole.bmWidth * 3 + 1)/2) * 2  + x*3;
iRGBBk = (y+ 150) * ((bitmapBK.bmWidth * 3 + 1)/2) * 2 + x * 3 + 150 * 3;
pr[iRGB] = pb[iRGBBk]-1;           //如果去掉注释以及-1,则目标矩形区域
pr[iRGB+1] = pb[iRGBBk+1]-1;       //为背景相应目标区域,及该区域的显示不变,如果不去掉-1,
pr[iRGB+2] = pb[iRGBBk+2]-1;       //理论上此区域内的图象略有改变且不随刷新而改变,但现在
//改变了。问题就在这!!
}
}
SetBitmapBits(hBmpRole,bitmapRole.bmHeight * bitmapRole.bmWidthBytes,pr); hOldRole = (HBITMAP)SelectObject(hDcObj,hBmpRole); TransparentBlt(hDcBuffer,150,150,bitmapRole.bmWidth,bitmapRole.bmHeight,hDcObj,
0,0,
//(*ihb)->m_lefttop.x,(*ihb)->m_lefttop.y,
bitmapRole.bmWidth,bitmapRole.bmHeight,RGB(255,255,255)); BitBlt(hdc,0,0,800,600,hDcBuffer,0,0,SRCCOPY); SelectObject(hDcBuffer,hOldBk);
SelectObject(hDcObj,hOldRole); DeleteDC(hDcObj);
DeleteDC(hDcBuffer); delete []pb;
delete []pr;     
        
        
EndPaint (hwnd, &ps) ; return 0 ;        
        
    case   WM_DESTROY:        
            PostQuitMessage (0) ;        
            return 0 ;
        
    }        
  return DefWindowProc (hwnd, message, wParam, lParam) ;
        
}

解决方案 »

  1.   

    这里搞错了,都是用hBmpRole,因为它是全局变量,所以改变了。但即便代码如下,问题依旧:
    #include <windows.h>
    #pragma comment(lib,"msimg32.lib")        LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
    //以下两副图自己指定
    HBITMAP hBmpBK = (HBITMAP)LoadImage(NULL,"e:\\test\\bk1.bmp",IMAGE_BITMAP, 0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    HBITMAP hBmpRole = (HBITMAP)LoadImage(NULL,"e:\\test\\rec2.bmp",IMAGE_BITMAP, 0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
            int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,        
                       PSTR szCmdLine, int iCmdShow)        
    {        
        static TCHAR szAppName[] = TEXT ("HelloWin") ;        
        HWND   hwnd ;        
        MSG    msg ;        
        WNDCLASS wndclass ; 
       wndclass.style        = CS_HREDRAW | CS_VREDRAW ;        
       wndclass.lpfnWndProc  = WndProc ;        
        wndclass.cbClsExtra   = 0 ;        
        wndclass.cbWndExtra   = 0 ;        
        wndclass.hInstance    = hInstance ;        
        wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;        
      wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;        
       wndclass.hbrBackground= NULL ;        
      wndclass.lpszMenuName = NULL ;        
        wndclass.lpszClassName= szAppName ;            if (!RegisterClass (&wndclass))      
        {        
                MessageBox (  NULL, TEXT ("This program requires Windows NT!"),        
                                      szAppName, MB_ICONERROR) ;        
                return 0 ;        
        }
            
        hwnd = CreateWindow( szAppName,      // window class name        
                       TEXT ("The Hello Program"),   // window caption        
                       WS_SYSMENU,  // window style        
                       CW_USEDEFAULT,// initial x position        
                       CW_USEDEFAULT,// initial y position        
                       800,// initial x size        
                       600,// initial y size        
                       NULL,                 // parent window handle        
                   NULL,            // window menu handle        
                   hInstance,   // program instance handle        
                   NULL) ;      // creation parameters
            
       SetTimer(hwnd,1,300,NULL);        
        ShowWindow (hwnd, iCmdShow) ;        
        UpdateWindow (hwnd) ;        
       
            
        while (GetMessage (&msg, NULL, 0, 0))        
        {        
                TranslateMessage (&msg) ;        
              DispatchMessage (&msg) ;        
        }        
        return msg.wParam ;        
    }
            LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)        
    {        
        HDC hdc ,hDcBuffer,hDcObj;        
    HBITMAP hOldBk,hOldRole,hFinal;
        PAINTSTRUCT ps ;         int x,y,iRGB,iRGBBk;
        RECT          rect ;       
       
            
        switch (message)        
        {        
        case WM_CREATE:    
            
                return 0 ;
    case WM_TIMER:
      InvalidateRect(hwnd,NULL,TRUE);
      return 0;            case   WM_PAINT:        
                hdc = BeginPaint (hwnd, &ps) ;
            
    hDcBuffer,hDcObj;
    hDcBuffer = CreateCompatibleDC(hdc);
    hDcObj = CreateCompatibleDC(hdc);
    hOldBk = (HBITMAP)SelectObject(hDcBuffer,hBmpBK); BITMAP bitmapBK,bitmapRole;
    GetObject(hBmpBK,sizeof(BITMAP),&bitmapBK);
    GetObject(hBmpRole,sizeof(BITMAP),&bitmapRole); hFinal = CreateCompatibleBitmap (hDcBuffer,bitmapRole.bmWidth,bitmapRole.bmHeight) ; unsigned char * pb,*pr;
    pb = new unsigned char [bitmapBK.bmHeight * bitmapBK.bmWidthBytes];
    pr = new unsigned char [bitmapRole.bmHeight * bitmapRole.bmWidthBytes]; GetBitmapBits(hBmpBK,bitmapBK.bmHeight * bitmapBK.bmWidthBytes,pb);
    GetBitmapBits(hBmpRole,bitmapRole.bmHeight * bitmapRole.bmWidthBytes,pr); for(y = 0 ; y < bitmapRole.bmHeight;y++)
    {
    for (x = 0; x < bitmapRole.bmWidthBytes/(bitmapRole.bmBitsPixel/8);x++)
    {
    iRGB = y * ((bitmapRole.bmWidth * 3 + 1)/2) * 2  + x*3;
    iRGBBk = (y+ 150) * ((bitmapBK.bmWidth * 3 + 1)/2) * 2 + x * 3 + 150 * 3;
    pr[iRGB] = pb[iRGBBk]-1;           //如果去掉注释以及-1,则目标矩形区域
    pr[iRGB+1] = pb[iRGBBk+1]-1;       //为背景相应目标区域,及该区域的显示不变,如果不去掉-1,
    pr[iRGB+2] = pb[iRGBBk+2]-1;       //理论上此区域内的图象略有改变且不随刷新而改变,但现在
    //改变了。问题就在这!!
    }
    }
    SetBitmapBits(hFinal,bitmapRole.bmHeight * bitmapRole.bmWidthBytes,pr); hOldRole = (HBITMAP)SelectObject(hDcObj,hFinal); TransparentBlt(hDcBuffer,150,150,bitmapRole.bmWidth,bitmapRole.bmHeight,hDcObj,
    0,0,
    //(*ihb)->m_lefttop.x,(*ihb)->m_lefttop.y,
    bitmapRole.bmWidth,bitmapRole.bmHeight,RGB(255,255,255)); BitBlt(hdc,0,0,800,600,hDcBuffer,0,0,SRCCOPY); SelectObject(hDcBuffer,hOldBk);
    SelectObject(hDcObj,hOldRole); DeleteDC(hDcObj);
    DeleteDC(hDcBuffer); delete []pb;
    delete []pr;     
            
            
    EndPaint (hwnd, &ps) ; return 0 ;        
            
        case   WM_DESTROY:        
                PostQuitMessage (0) ;        
                return 0 ;
            
        }        
      return DefWindowProc (hwnd, message, wParam, lParam) ;
            
    }
            
      

  2.   

    好吧,原因找到了:还是因为HBITMAP变量是全局变量,而把它跟HDC关联后,对HDC的操作也影响到它。