// // bbar.cpp // // Implementation of CBBar // Drop down connection status + utility bar // // Copyright(C) Microsoft Corporation 2000 // Author: Nadim Abdo (nadima) // // #include "adcg.h" #ifdef USE_BBAR #define TRC_GROUP TRC_GROUP_UI #define TRC_FILE "bbar" #include #include "bbar.h" #include "commctrl.h" #ifndef OS_WINCE #define BBAR_CLASSNAME _TEXT("BBARCLASS") #else #define BBAR_CLASSNAME _T("BBARCLASS") #endif #define IDM_MINIMIZE 101 #define IDM_RESTORE 102 #define IDM_CLOSE 103 #define IDM_PIN 104 // // BBar is 50% of parent's width // #define BBAR_PERCENT_WIDTH 50 #define BBAR_NUM_BUTTONS 3 #define BBAR_BUTTON_WIDTH 12 #define BBAR_BUTTON_HEIGHT 11 #define BBAR_BUTTON_SPACE 3 #define BBAR_MIN_HEIGHT 16 // // Two pixels of vertical space are // unavailable (due to lines at bottom) // #define BBAR_VERT_SPACE_NO_USE 3 #define COLOR_BLACK RGB(0,0,0) #define COLOR_DKGREY RGB(128,128,128) #ifndef OS_WINCE #define BBAR_TIMERID_ANIM 0 #else #define BBAR_TIMERID_ANIM (WM_USER + 1001) #endif #define BBAR_TIMERID_AUTOHIDE 1 // // Total animation period for animation (E.g lower) // in milliseconds // #define BBAR_ANIM_TIME 300 #define BBAR_AUTOHIDE_TIME 1400 #define BBAR_FIRST_AUTOHIDE_TIME 5000 CBBar::CBBar(HWND hwndParent, HINSTANCE hInstance, CUI* pUi, BOOL fBBarEnabled) { DC_BEGIN_FN("CBBar"); _hwndBBar = NULL; _hwndParent = hwndParent; _hInstance = hInstance; _state = bbarNotInit; _pUi = pUi; _fBlockZOrderChanges = FALSE; _nBBarVertOffset = 0; _ptLastAutoHideMousePos.x = -0x0FF; _ptLastAutoHideMousePos.y = -0x0FF; _nBBarAutoHideTime = 0; _hwndPinBar = NULL; _hwndWinControlsBar = NULL; _fPinned = FALSE; _nPinUpImage = 0; _nPinDownImage = 0; _hbmpLeftImage = NULL; _hbmpRightImage = NULL; _fBBarEnabled = fBBarEnabled; _fLocked = FALSE; _fShowMinimize = TRUE; _fShowRestore = TRUE; SetDisplayedText(_T("")); DC_END_FN(); } CBBar::~CBBar() { } BOOL CBBar::StartupBBar(int desktopX, int desktopY, BOOL fStartRaised) { BOOL bRet = FALSE; DC_BEGIN_FN("StartupBBar"); if(bbarNotInit == _state) { // First drop interval is long _nBBarAutoHideTime = BBAR_FIRST_AUTOHIDE_TIME; bRet = Initialize( desktopX, desktopY, fStartRaised ); if(!bRet) { return FALSE; } } else { // First drop interval is long _nBBarAutoHideTime = BBAR_AUTOHIDE_TIME; //re-init existing bbar BringWindowToTop( _hwndBBar ); ShowWindow( _hwndBBar, SW_SHOWNOACTIVATE); // // Bring the window to the TOP of the Z order // SetWindowPos( _hwndBBar, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); bRet = TRUE; } // // Note: The bbar is used as a security feature so we do the initial // drop even if the bbar feature is not enabled. It's only subsequent // drops (e.g. on the timer) that are disabled if bbar is OFF // if(_pUi->UI_IsFullScreen()) { //First autohide interval is long //to make sure user gets to notice the bbar StartLowerBBar(); } DC_END_FN(); return bRet; } // // Destroy the window and reset bbar state // for another session // BOOL CBBar::KillAndCleanupBBar() { BOOL fRet = TRUE; DC_BEGIN_FN("KillAndCleanupBBar"); if(_state != bbarNotInit) { TRC_NRM((TB,_T("Cleaning up the bbar"))); if(_hwndBBar) { if(::DestroyWindow( _hwndBBar )) { _state = bbarNotInit; _hwndBBar = NULL; _fBlockZOrderChanges = FALSE; if(!UnregisterClass( BBAR_CLASSNAME, _hInstance )) { TRC_ERR((TB,_T("UnregisterClass bbar class failed 0x%x"), GetLastError())); } } else { TRC_ERR((TB,_T("DestroyWindow bbar failed 0x%x"), GetLastError())); fRet = FALSE; } if (_hbmpLeftImage) { DeleteObject(_hbmpLeftImage); _hbmpLeftImage = NULL; } if (_hbmpRightImage) { DeleteObject(_hbmpRightImage); _hbmpRightImage = NULL; } } } DC_END_FN(); return fRet; } BOOL CBBar::StartLowerBBar() { INT parentWidth = 0; RECT rc; DC_BEGIN_FN("StartLowerBBar"); if(_state == bbarRaised) { // // Kick off a timer to lower the bar // TRC_ASSERT(0 == _nBBarVertOffset, (TB,_T("_nBBarVertOffset (%d) should be 0"), _nBBarVertOffset)); TRC_ASSERT(_hwndBBar, (TB,_T("_hwndBBar is NULL"))); // // Set the last cursor pos at the time // the bbar is lowered to prevent it from being // autohidden if the mouse doesn't move // GetCursorPos(&_ptLastAutoHideMousePos); // // Main window size could have changed // so make sure the bbar is centered // before lowering it. // (keep constant bbar width) if(_pUi->_UI.hwndMain) { GetClientRect(_pUi->_UI.hwndMain, &rc); parentWidth = rc.right - rc.left; if(!parentWidth) { return FALSE; } _rcBBarLoweredAspect.left = parentWidth / 2 - _sizeLoweredBBar.cx / 2; _rcBBarLoweredAspect.right = parentWidth / 2 + _sizeLoweredBBar.cx / 2; #ifdef DISABLE_SHADOW_IN_FULLSCREEN _pUi->UI_OnNotifyBBarRectChange(&_rcBBarLoweredAspect); _pUi->UI_OnNotifyBBarVisibleChange(1); #endif } #ifndef OS_WINCE if(!SetTimer( _hwndBBar, BBAR_TIMERID_ANIM, BBAR_ANIM_TIME / _sizeLoweredBBar.cy, NULL )) { TRC_ERR((TB,_T("SetTimer failed - 0x%x"), GetLastError())); return FALSE; } _state = bbarLowering; #else ImmediateLowerBBar(); #endif return TRUE; } else { TRC_NRM((TB,_T("StartLowerBBar called when bar in wrong state 0x%x"), _state)); return FALSE; } DC_END_FN(); } BOOL CBBar::StartRaiseBBar() { DC_BEGIN_FN("StartRaiseBBar"); if(_state == bbarLowered && !_fPinned && !_fLocked) { // // Kick off a timer to lower the bar // TRC_ASSERT(_sizeLoweredBBar.cy == _nBBarVertOffset, (TB,_T("_nBBarVertOffset (%d) should be %d"), _nBBarVertOffset, _sizeLoweredBBar.cy)); TRC_ASSERT(_hwndBBar, (TB,_T("_hwndBBar is NULL"))); #ifndef OS_WINCE if(!SetTimer( _hwndBBar, BBAR_TIMERID_ANIM, BBAR_ANIM_TIME / _sizeLoweredBBar.cy, NULL )) { TRC_ERR((TB,_T("SetTimer failed - 0x%x"), GetLastError())); return FALSE; } _state = bbarRaising; #else ImmediateRaiseBBar(); #endif return TRUE; } else { TRC_NRM((TB,_T("StartRaiseBBar called when bar in wrong state 0x%x"), _state)); return FALSE; } DC_END_FN(); return TRUE; } BOOL CBBar::Initialize(int desktopX, int desktopY, BOOL fStartRaised) { #ifndef OS_WINCE RECT rc; #endif HWND hwndBBar; int parentWidth = desktopX; int bbarHeight = 0; int bbarWidth = 0; DC_BEGIN_FN("Initialize"); TRC_ASSERT( bbarNotInit == _state, (TB,_T("bbar already initialized - state:0x%x"), _state)); // // Compute BBAR position based on remote desktop size // #ifndef OS_WINCE bbarHeight = GetSystemMetrics( SM_CYMENUSIZE ) + 2; #else bbarHeight = GetSystemMetrics( SM_CYMENU ) + 2; #endif bbarHeight = max(bbarHeight, BBAR_MIN_HEIGHT); _rcBBarLoweredAspect.bottom = bbarHeight; _rcBBarLoweredAspect.left = (LONG)( (100 - BBAR_PERCENT_WIDTH) / 200.0 * parentWidth ); _rcBBarLoweredAspect.right = parentWidth - _rcBBarLoweredAspect.left; _rcBBarLoweredAspect.top = 0; bbarWidth = _rcBBarLoweredAspect.right - _rcBBarLoweredAspect.left; _sizeLoweredBBar.cx = bbarWidth; _sizeLoweredBBar.cy = bbarHeight; hwndBBar = CreateWnd( _hInstance, _hwndParent, &_rcBBarLoweredAspect ); if(hwndBBar) { if( fStartRaised ) { // // Move the bar up by it's height to raise it // if(SetWindowPos(hwndBBar, NULL, _rcBBarLoweredAspect.left, //x -_sizeLoweredBBar.cy, //y 0,0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE )) { TRC_NRM((TB,_T("BBAR SetWindowPos failed - 0x%x"), GetLastError())); } } BringWindowToTop( hwndBBar ); ShowWindow( hwndBBar, SW_SHOWNOACTIVATE); // // Create the polygon region for the bounds of the BBar window // This cuts the corners off the edges. // POINT pts[4]; int xOffset = parentWidth / 2 - _rcBBarLoweredAspect.left; pts[3].x = -bbarWidth/2 + xOffset; pts[3].y = 0; pts[2].x = bbarWidth/2 + xOffset; pts[2].y = 0; pts[1].x = bbarWidth/2 - bbarHeight + xOffset; pts[1].y = bbarHeight; pts[0].x = -bbarWidth/2 + bbarHeight + xOffset; pts[0].y = bbarHeight; #ifndef OS_WINCE // // Polygon does not self intersect so winding mode is not // relevant // HRGN hRgn = CreatePolygonRgn( pts, 4, ALTERNATE ); #else HRGN hRgn = GetBBarRgn(pts); #endif if(hRgn) { if(!SetWindowRgn( hwndBBar, hRgn, TRUE)) { TRC_ERR((TB,_T("SetWindowRgn failed - 0x%x"), GetLastError())); // // In the success case the system will free // the region handle when it is done with it. // Here however, the call failed... // DeleteObject( hRgn ); } } else { // // Not fatal, continue // TRC_ERR((TB,_T("CreatePolygonRgn failed - 0x%x"), GetLastError())); } // // Bring the window to the TOP of the Z order // if(!SetWindowPos( hwndBBar, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE )) { TRC_ERR((TB,_T("SetWindowPos failed - 0x%x"), GetLastError())); return FALSE; } // // Compute the rectangle for displayed text // // First figure out how much space to trim in the // x direction // int xDelta = _sizeLoweredBBar.cy * 2 + //diagonal corners BBAR_NUM_BUTTONS * (BBAR_BUTTON_WIDTH + BBAR_BUTTON_SPACE); //button space GetClientRect( hwndBBar, &_rcBBarDisplayTextArea); if(!InflateRect( &_rcBBarDisplayTextArea, -xDelta, 0 )) { TRC_ABORT((TB,_T("InflateRect failed 0x%x"), GetLastError())); return FALSE; } // Shave off from the bottom _rcBBarDisplayTextArea.bottom -= 1; if (!CreateToolbars()) { TRC_ERR((TB,_T("CreateToolbars failed"))); return FALSE; } // // Trigger a repaint of the background // InvalidateRect( hwndBBar, NULL, TRUE); } else { TRC_ERR((TB,_T("CreateWnd for BBar failed"))); return FALSE; } if( fStartRaised ) { SetState( bbarRaised ); _nBBarVertOffset = 0; } else { SetState( bbarLowered ); _nBBarVertOffset = _sizeLoweredBBar.cy; } DC_END_FN(); return TRUE; } // // DIBs use RGBQUAD format: // 0xbb 0xgg 0xrr 0x00 // // Reasonably efficient code to convert a COLORREF into an // RGBQUAD. // #define RGB_TO_RGBQUAD(r,g,b) (RGB(b,g,r)) #define CLR_TO_RGBQUAD(clr) (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr))) // // Internal helper that loads a bitmap and remaps it's colors // to the system colors. Use this instead of LoadImage with the // LR_LOADMAP3DCOLORS flag because that fn doesn't work well on NT4. // HBITMAP _LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc, BOOL bMono) { struct COLORMAP { // use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily DWORD rgbqFrom; int iSysColorTo; }; static const COLORMAP sysColorMap[] = { // mapping from color in DIB to system color { RGB_TO_RGBQUAD(0x00, 0x00, 0x00), COLOR_BTNTEXT }, // black { RGB_TO_RGBQUAD(0x80, 0x80, 0x80), COLOR_BTNSHADOW }, // dark grey { RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0), COLOR_BTNFACE }, // bright grey { RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF), COLOR_BTNHIGHLIGHT } // white }; const int nMaps = 4; HGLOBAL hglb; if ((hglb = LoadResource(hInst, hRsrc)) == NULL) return NULL; LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb); if (lpBitmap == NULL) return NULL; // make copy of BITMAPINFOHEADER so we can modify the color table const int nColorTableSize = 16; UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD); LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER) LocalAlloc(LPTR, nSize); if (lpBitmapInfo == NULL) return NULL; memcpy(lpBitmapInfo, lpBitmap, nSize); // color table is in RGBQUAD DIB format DWORD* pColorTable = (DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize); for (int iColor = 0; iColor < nColorTableSize; iColor++) { // look for matching RGBQUAD color in original for (int i = 0; i < nMaps; i++) { if (pColorTable[iColor] == sysColorMap[i].rgbqFrom) { if (bMono) { // all colors except text become white if (sysColorMap[i].iSysColorTo != COLOR_BTNTEXT) pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255); } else pColorTable[iColor] = CLR_TO_RGBQUAD( GetSysColor(sysColorMap[i].iSysColorTo)); break; } } } int nWidth = (int)lpBitmapInfo->biWidth; int nHeight = (int)lpBitmapInfo->biHeight; HDC hDCScreen = GetDC(NULL); HBITMAP hbm = CreateCompatibleBitmap(hDCScreen, nWidth, nHeight); if (hbm != NULL) { HDC hDCGlyphs = CreateCompatibleDC(hDCScreen); HBITMAP hbmOld = (HBITMAP)SelectObject(hDCGlyphs, hbm); LPBYTE lpBits; lpBits = (LPBYTE)(lpBitmap + 1); lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD); StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY); SelectObject(hDCGlyphs, hbmOld); DeleteDC(hDCGlyphs); } ReleaseDC(NULL, hDCScreen); // free copy of bitmap info struct and resource itself LocalFree(lpBitmapInfo); #ifndef OS_WINCE FreeResource(hglb); #endif return hbm; } BOOL CBBar::CreateToolbars() { DC_BEGIN_FN("CreateToolbars"); // // Create toolbars // INT ret = 0; UINT imgIdx = 0; INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_BAR_CLASSES; if(!InitCommonControlsEx( &icex )) { TRC_ERR((TB,_T("InitCommonControlsEx failed 0x%x"), GetLastError())); return FALSE; } // // Right bar (close window,disconnect etc) // { TBBUTTON tbButtons [] = { {0, IDM_MINIMIZE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, #ifndef OS_WINCE {0, IDM_RESTORE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, #endif {0, IDM_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0} }; TBBUTTON tbRealButtons[3]; HWND hwndRightToolbar = CreateToolbarEx( GetHwnd(), WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE, IDB_BBAR_TOOLBAR_RIGHT, 0, _hInstance, 0, NULL, 0, 12, 12, 16, 16, sizeof(TBBUTTON) ); if(!hwndRightToolbar) { TRC_ERR((TB,_T("CreateToolbarEx failed 0x%x"), GetLastError())); return FALSE; } // // Add images // if (!AddReplaceImage(hwndRightToolbar, IDB_BBAR_TOOLBAR_RIGHT, #ifndef OS_WINCE 3, //image makes up 3 buttons #else 2, //2 buttons on CE #endif &_hbmpRightImage, &imgIdx)) { TRC_ERR((TB,_T("AddReplaceImage for rt toolbar failed"))); return FALSE; } // // Associate images with buttons // tbButtons[0].iBitmap = imgIdx; tbButtons[1].iBitmap = imgIdx + 1; #ifndef OS_WINCE tbButtons[2].iBitmap = imgIdx + 2; #endif // // Not all buttons are to be added, figure out which here // and setup the real buttons array // ULONG nNumButtons = 0; if (_fShowMinimize) { tbRealButtons[nNumButtons++] = tbButtons[0]; } if (_fShowRestore) { tbRealButtons[nNumButtons++] = tbButtons[1]; } // Always show the close button #ifndef OS_WINCE tbRealButtons[nNumButtons++] = tbButtons[2]; #endif // // Add the buttons // ret = SendMessage( hwndRightToolbar, TB_ADDBUTTONS, nNumButtons, (LPARAM)(LPTBBUTTON) &tbRealButtons ); if(-1 == ret) { TRC_ERR((TB,_T("TB_ADDBUTTONS failed"))); return FALSE; } // // Move the toolbar // if(!MoveWindow( hwndRightToolbar, _sizeLoweredBBar.cx - _sizeLoweredBBar.cy - ((BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH)*(nNumButtons+1)), 0, ((BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH)*(nNumButtons+1)), BBAR_BUTTON_HEIGHT*2, TRUE)) { TRC_ERR((TB,_T("MoveWindow failed"))); return FALSE; } if(!ShowWindow ( hwndRightToolbar, SW_SHOWNORMAL) ) { TRC_ERR((TB,_T("ShowWindow failed"))); return FALSE; } _hwndWinControlsBar = hwndRightToolbar; } // // Left bar (pin) // { TBBUTTON tbButtons [] = { {0, IDM_PIN, TBSTATE_ENABLED | (_fPinned ? TBSTATE_PRESSED : 0), TBSTYLE_BUTTON, 0L, 0} }; HWND hwndLeftToolbar = CreateToolbarEx( GetHwnd(), WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NORESIZE, IDB_BBAR_TOOLBAR_LEFT, 0, _hInstance, 0, NULL, 0, 12, 12, 16, 16, sizeof(TBBUTTON) ); if(!hwndLeftToolbar) { TRC_ERR((TB,_T("CreateToolbarEx failed 0x%x"), GetLastError())); return FALSE; } // // Add images // if (!AddReplaceImage(hwndLeftToolbar, IDB_BBAR_TOOLBAR_LEFT, 2, //image makes up 2 buttons &_hbmpLeftImage, &imgIdx)) { TRC_ERR((TB,_T("AddReplaceImage for lt toolbar failed"))); return FALSE; } _nPinUpImage = imgIdx; _nPinDownImage = imgIdx + 1; // // Associate images with buttons // tbButtons[0].iBitmap = _fPinned ? _nPinDownImage : _nPinUpImage; // // Add the button // ret = SendMessage( hwndLeftToolbar, TB_ADDBUTTONS, 1, (LPARAM)(LPTBBUTTON) &tbButtons ); if(-1 == ret) { TRC_ERR((TB,_T("TB_ADDBUTTONS failed"))); return FALSE; } // // Move the toolbar // if(!MoveWindow( hwndLeftToolbar, _sizeLoweredBBar.cy + BBAR_BUTTON_SPACE, 0, (BBAR_BUTTON_SPACE + BBAR_BUTTON_WIDTH) * 2, BBAR_BUTTON_HEIGHT*2, TRUE)) { TRC_ERR((TB,_T("MoveWindow failed"))); return FALSE; } if(!ShowWindow ( hwndLeftToolbar, SW_SHOWNORMAL) ) { TRC_ERR((TB,_T("ShowWindow failed"))); return FALSE; } _hwndPinBar = hwndLeftToolbar; } DC_END_FN(); return TRUE; } // // ReloadImages for the toolbar including // refreshing the colors // BOOL CBBar::ReloadImages() { BOOL rc = FALSE; #ifndef OS_WINCE INT ret; #endif DC_BEGIN_FN("ReloadImages"); if (!_hwndWinControlsBar || !_hwndPinBar) { TRC_ERR((TB,_T("Toolbars not initialized"))); DC_QUIT; } // // Replace images // if (!AddReplaceImage(_hwndWinControlsBar, IDB_BBAR_TOOLBAR_RIGHT, 3, //image makes up 3 buttons &_hbmpRightImage, NULL)) { TRC_ERR((TB,_T("AddReplaceImage for rt toolbar failed"))); return FALSE; } if (!AddReplaceImage(_hwndPinBar, IDB_BBAR_TOOLBAR_LEFT, 2, //image makes up 3 buttons &_hbmpLeftImage, NULL)) { TRC_ERR((TB,_T("AddReplaceImage for lt toolbar failed"))); return FALSE; } DC_EXIT_POINT: DC_END_FN(); return rc; } // // Adds or replaces an image to a toolbar // Params: // hwndToolbar - toolbar to act on // rsrcId - resource ID of the bitmap // nCells - number of image cells // phbmpOldImage - [IN/OUT] handle to previous image, on return is // set to current image // pImgIndex - [OUT] index to the first image added // BOOL CBBar::AddReplaceImage(HWND hwndToolbar, UINT rsrcId, UINT nCells, HBITMAP* phbmpOldImage, PUINT pImgIndex) { BOOL rc = FALSE; INT ret = 0; HBITMAP hbmpNew = NULL; HRSRC hBmpRsrc = NULL; DC_BEGIN_FN("AddReplaceImage"); // // Replace images // hBmpRsrc = FindResource(_hInstance, MAKEINTRESOURCE(rsrcId), RT_BITMAP); if (hBmpRsrc) { hbmpNew = _LoadSysColorBitmap(_hInstance, hBmpRsrc, FALSE); if (hbmpNew) { if (NULL == *phbmpOldImage) { TBADDBITMAP tbAddBitmap; tbAddBitmap.hInst = NULL; tbAddBitmap.nID = (UINT_PTR)hbmpNew; ret = SendMessage( hwndToolbar, TB_ADDBITMAP, nCells, (LPARAM)(LPTBADDBITMAP)&tbAddBitmap ); } else { TBREPLACEBITMAP tbRplBitmap; tbRplBitmap.hInstOld = NULL; tbRplBitmap.nIDOld = (UINT_PTR)*phbmpOldImage; tbRplBitmap.hInstNew = NULL; tbRplBitmap.nIDNew = (UINT_PTR)hbmpNew; tbRplBitmap.nButtons = nCells; ret = SendMessage(hwndToolbar, TB_REPLACEBITMAP, 0, (LPARAM)(LPTBADDBITMAP)&tbRplBitmap); } if (-1 != ret) { //Delete the old bitmap if (*phbmpOldImage) { DeleteObject(*phbmpOldImage); } *phbmpOldImage = hbmpNew; if (pImgIndex) { *pImgIndex = ret; } } else { TRC_ERR((TB,_T("TB_ADDBITMAP failed"))); DC_QUIT; } } else { TRC_ERR((TB,_T("LoadSysColorBitmap failed rsrcid:%d"), rsrcId)); DC_QUIT; } } else { TRC_ERR((TB,_T("Unable to find rsrc: %d"), rsrcId)); DC_QUIT; } rc = TRUE; DC_EXIT_POINT: DC_END_FN(); return rc; } // // Create the window // params: // hInstance - app instance // _hwndBBarParent - parent window // szClassName - window class name (will create) // dwStyle - window style // returns: // window handle // HWND CBBar::CreateWnd(HINSTANCE hInstance,HWND _hwndBBarParent, LPRECT lpInitialRect) { BOOL rc = FALSE; #ifndef OS_WINCE WNDCLASSEX wndclass; #else WNDCLASS wndclass; #endif WNDCLASS tmpwc; DC_BEGIN_FN("CreateWnd"); TRC_ASSERT(hInstance, (TB, _T("hInstance is null"))); TRC_ASSERT(lpInitialRect, (TB, _T("lpInitialRect is null"))); if(!hInstance || !lpInitialRect) { return NULL; } TRC_ASSERT(!_hwndBBar, (TB,_T("Double create window. Could be leaking!!!"))); _hInstance = hInstance; #ifndef OS_WINCE wndclass.cbSize = sizeof (wndclass); #endif wndclass.style = CS_DBLCLKS; wndclass.lpfnWndProc = CBBar::StaticBBarWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_INFOBK); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = BBAR_CLASSNAME; #ifndef OS_WINCE wndclass.hIconSm = NULL; #endif SetLastError(0); if(!GetClassInfo( hInstance, BBAR_CLASSNAME, &tmpwc)) { #ifndef OS_WINCE if ((0 == RegisterClassEx(&wndclass)) && #else if ((0 == RegisterClass(&wndclass)) && #endif (ERROR_CLASS_ALREADY_EXISTS != GetLastError())) { TRC_ERR((TB,_T("RegisterClassEx failed: %d"),GetLastError())); return NULL; } } _hwndBBar = CreateWindowEx(0, BBAR_CLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, lpInitialRect->left, lpInitialRect->top, lpInitialRect->right - lpInitialRect->left, lpInitialRect->bottom - lpInitialRect->top, _hwndBBarParent, NULL, hInstance, this); if(_hwndBBar) { // put a reference to the current object into the hwnd // so we can access the object from the WndProc SetLastError(0); if(!SetWindowLongPtr(_hwndBBar, GWLP_USERDATA, (LONG_PTR)this)) { if(GetLastError()) { TRC_ERR((TB,_T("SetWindowLongPtr failed 0x%x"), GetLastError())); return NULL; } } } else { TRC_ERR((TB,_T("CreateWindow failed 0x%x"), GetLastError())); return NULL; } DC_END_FN(); return _hwndBBar; } LRESULT CALLBACK CBBar::StaticBBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DC_BEGIN_FN("StatiCBBarProc"); // pull out the pointer to the container object associated with this hwnd CBBar *pwnd = (CBBar *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if(pwnd) { return pwnd->BBarWndProc( hwnd, uMsg, wParam, lParam); } else { return DefWindowProc (hwnd, uMsg, wParam, lParam); } DC_END_FN(); } LRESULT CALLBACK CBBar::BBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DC_BEGIN_FN("BBarWndProc"); switch (uMsg) { case WM_ERASEBKGND: { return OnEraseBkgnd(hwnd, uMsg, wParam, lParam); } break; case WM_LBUTTONDBLCLK: { OnCmdRestore(); return 0L; } break; case WM_PAINT: { return OnPaint(hwnd, uMsg, wParam, lParam); } break; case WM_SYSCOLORCHANGE: { InvalidateRect( hwnd, NULL, TRUE); return 0L; } break; case WM_TIMER: { if( BBAR_TIMERID_ANIM == wParam) { #ifndef OS_WINCE if(_state == bbarLowering || _state == bbarRaising) { BOOL fReachedEndOfAnimation = FALSE; int delta = (bbarLowering == _state ) ? 1 : -1; _nBBarVertOffset+= delta; if(SetWindowPos(_hwndBBar, NULL, _rcBBarLoweredAspect.left, //x _nBBarVertOffset - _sizeLoweredBBar.cy, //y 0,0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE )) { TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"), GetLastError())); } if(_state == bbarLowering) { if(_nBBarVertOffset >= _sizeLoweredBBar.cy) { _nBBarVertOffset = _sizeLoweredBBar.cy; _state = bbarLowered; fReachedEndOfAnimation = TRUE; OnBBarLowered(); } } else if(_state == bbarRaising) { if(_nBBarVertOffset <= 0) { _nBBarVertOffset = 0; _state = bbarRaised; fReachedEndOfAnimation = TRUE; OnBBarRaised(); } } if(fReachedEndOfAnimation) { if(!KillTimer( _hwndBBar, BBAR_TIMERID_ANIM )) { TRC_ERR((TB,_T("KillTimer failed - 0x%x"), GetLastError())); } } } #endif } else if (BBAR_TIMERID_AUTOHIDE == wParam) { // // If the mouse is within the hotzone // then don't autohide. Otherwise kill the autohide // timer and kick off a bbar raise // if(_state == bbarLowered) { POINT pt; RECT rc; GetCursorPos(&pt); // // Don't hide if mouse hasn't moved // if(_ptLastAutoHideMousePos.x != pt.x && _ptLastAutoHideMousePos.y != pt.y) { _ptLastAutoHideMousePos.x = pt.x; _ptLastAutoHideMousePos.y = pt.y; // // Get window rect in screen coordinates // GetWindowRect( _hwndBBar, &rc); // // Don't hide if the cursor is within // the bbar rect // if(!PtInRect(&rc, pt)) { // Stop the autohide timer because we're going // to hide if(!KillTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE )) { TRC_ERR((TB,_T("KillTimer failed - 0x%x"), GetLastError())); } StartRaiseBBar(); } } else { // // Don't autohide the bbar because the mouse // has not moved, this prevents the raise/lower // loop problem because the hotzone (see IH) region and // auto-hide prevention regions are different // (by design). // TRC_NRM((TB, _T("Autohide timer fired but mouse not moved"))); } } } return 0L; } break; #ifndef OS_WINCE case WM_WINDOWPOSCHANGING: { if(_fBlockZOrderChanges) { LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam; lpwp->flags |= SWP_NOZORDER; } return 0L; } break; #endif case WM_COMMAND: { switch(LOWORD(wParam)) { case IDM_MINIMIZE: { OnCmdMinimize(); } break; case IDM_RESTORE: { OnCmdRestore(); } break; case IDM_CLOSE: { OnCmdClose(); } break; case IDM_PIN: { OnCmdPin(); } break; } return 0L; } break; default: { return DefWindowProc( hwnd, uMsg, wParam, lParam); } break; } DC_END_FN(); } VOID CBBar::SetState(BBarState newState) { DC_BEGIN_FN("SetState"); TRC_NRM((TB,_T("BBar old state: 0x%x - new state: 0x%x"), _state, newState)); _state = newState; DC_END_FN(); } LRESULT CBBar::OnEraseBkgnd(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { RECT rc; HDC hDC = NULL; HBRUSH hBrToolTipBgCol = NULL; #ifndef OS_WINCE HGDIOBJ hPrevBr = NULL; COLORREF prevCol; #endif HPEN hPenNew = NULL, hPenOld = NULL, hPenOri = NULL; DC_BEGIN_FN("OnEraseBkgnd"); hDC = (HDC)wParam; GetClientRect( hwnd, &rc ); // // Repaint the background as follows // 1) fill the window with the TOOLTIP bg color // 2) draw the edges in solid black // 3) add a grey line to the bottom horizontal edge because it looks // really cool // hBrToolTipBgCol = (HBRUSH) GetSysColorBrush(COLOR_INFOBK); FillRect(hDC, &rc, hBrToolTipBgCol); #ifdef OS_WINCE //On CE, the toolbar sends an extra WM_ERASEBKGND message to the parent with its DC in wParam. //The origin of that DC, is the where the toolbar is located. So we want to use supplied DC for FillRect //but not for drawing lines hDC = GetDC(hwnd); #endif hPenNew = CreatePen( PS_SOLID, 0 , COLOR_BLACK); if (NULL != hPenNew) { hPenOri = SelectPen(hDC, hPenNew); } // // Left diagonal corner (assumes 45degree line) // MoveToEx( hDC, 0, 0, NULL); LineTo( hDC, _sizeLoweredBBar.cy, _sizeLoweredBBar.cy ); // // Right diagonal corner (assumes 45degree line) // (bias by one pixel to end up inside the clipping region) // MoveToEx( hDC, _sizeLoweredBBar.cx - 1, 0, NULL); LineTo( hDC, _sizeLoweredBBar.cx - _sizeLoweredBBar.cy -1, _sizeLoweredBBar.cy ); // // Bottom black line // bias by 1 pixel up to lie inside clip region // MoveToEx( hDC, _sizeLoweredBBar.cy, _sizeLoweredBBar.cy - 1, NULL); LineTo( hDC, _sizeLoweredBBar.cx - _sizeLoweredBBar.cy, _sizeLoweredBBar.cy - 1); if (NULL != hPenOri) { SelectPen(hDC, hPenOri); } if (NULL != hPenNew) { DeleteObject(hPenNew); hPenNew = NULL; } // // Thin grey line above bottom gray line // hPenNew = CreatePen( PS_SOLID, 0 , COLOR_DKGREY); if (NULL != hPenNew) { hPenOri = SelectPen(hDC, hPenNew); } MoveToEx( hDC, _sizeLoweredBBar.cy - 1, _sizeLoweredBBar.cy - 2, NULL); LineTo( hDC, _sizeLoweredBBar.cx - _sizeLoweredBBar.cy + 1, _sizeLoweredBBar.cy - 2); // // Restore DC // #ifndef OS_WINCE if (NULL != hPenOri) { SelectPen( hDC, hPenOri); } #else SelectPen( hDC, GetStockObject(BLACK_PEN)); #endif if (NULL != hPenNew) { DeleteObject( hPenNew); hPenNew = NULL; } #ifdef OS_WINCE ReleaseDC(hwnd, hDC); #endif DC_END_FN(); return TRUE; } VOID CBBar::SetDisplayedText(LPTSTR szText) { HRESULT hr; DC_BEGIN_FN("SetDisplayedText"); if(szText) { hr = StringCchCopy(_szDisplayedText, SIZE_TCHARS(_szDisplayedText), szText); if (FAILED(hr)) { TRC_ERR((TB,_T("StringCopy for dispayed text failed: 0x%x"),hr)); } } else { _szDisplayedText[0] = NULL; } if(_hwndBBar && _state != bbarNotInit) { //Trigger a repaint InvalidateRect( _hwndBBar, NULL, TRUE); } DC_END_FN(); } LRESULT CBBar::OnPaint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; DC_BEGIN_FN("OnPaint"); if(_state != bbarNotInit) { COLORREF oldCol; INT oldMode; HFONT hOldFont; COLORREF oldTextCol; // // Draw the displayed text // BeginPaint( hwnd, &ps); oldCol = SetBkColor( ps.hdc, GetSysColor(COLOR_INFOBK)); oldMode = SetBkMode( ps.hdc, OPAQUE); oldTextCol = SetTextColor( ps.hdc, GetSysColor(COLOR_INFOTEXT)); hOldFont = (HFONT)SelectObject( ps.hdc, #ifndef OS_WINCE GetStockObject( DEFAULT_GUI_FONT)); #else GetStockObject( SYSTEM_FONT)); #endif DrawText(ps.hdc, _szDisplayedText, _tcslen(_szDisplayedText), &_rcBBarDisplayTextArea, DT_CENTER | DT_VCENTER | DT_SINGLELINE); SetBkColor( ps.hdc, oldCol); SetBkMode( ps.hdc, oldMode); SetTextColor( ps.hdc, oldTextCol); SelectObject( ps.hdc, hOldFont); EndPaint( hwnd, &ps); } DC_END_FN(); return 0; } // // Internal event handler for bbar lowered // VOID CBBar::OnBBarLowered() { DC_BEGIN_FN("OnBBarLowered"); // // Kick off the autohide timer // TRC_ASSERT(_state == bbarLowered, (TB,_T("_state should be lowered...0x%x"), _state)); TRC_ASSERT(_nBBarAutoHideTime, (TB,_T("_nBBarAutoHideTime is 0"))); if(bbarLowered == _state) { if (!_fPinned || !_fLocked) { if(!SetTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE, _nBBarAutoHideTime, NULL )) { TRC_ERR((TB,_T("SetTimer failed - 0x%x"), GetLastError())); // // Bail out // return; } // After bbar has lowered once reset // the autohide interval time to the shorter // interval. _nBBarAutoHideTime = BBAR_AUTOHIDE_TIME; } } DC_END_FN(); } // // Internal event handler for bbar raised // VOID CBBar::OnBBarRaised() { DC_BEGIN_FN("OnBBarRaised"); #ifdef DISABLE_SHADOW_IN_FULLSCREEN _pUi->UI_OnNotifyBBarVisibleChange(0); #endif DC_END_FN(); } VOID CBBar::OnBBarHotzoneFired() { DC_BEGIN_FN("OnBBarHotzoneFired"); // // Only allow the bbar to drop on the timer if it's enabled // if (_fBBarEnabled && _state == bbarRaised && _pUi->UI_IsFullScreen()) { StartLowerBBar(); } DC_END_FN(); } VOID CBBar::OnCmdMinimize() { DC_BEGIN_FN("OnCmdLock"); TRC_NRM((TB,_T("BBAR Command Minimize"))); TRC_ASSERT( bbarNotInit != _state, (TB,_T("bbar not initalized - state:0x%x"), _state)); if(bbarNotInit != _state && _pUi->UI_IsFullScreen()) { _pUi->UI_RequestMinimize(); } DC_END_FN(); } VOID CBBar::OnCmdRestore() { DC_BEGIN_FN("OnCmdLock"); TRC_NRM((TB,_T("BBAR Command Restore"))); TRC_ASSERT( bbarNotInit != _state, (TB,_T("bbar not initalized - state:0x%x"), _state)); if(bbarNotInit != _state) { _pUi->UI_ToggleFullScreenMode(); } DC_END_FN(); } VOID CBBar::OnCmdClose() { DC_BEGIN_FN("OnCmdClose"); TRC_NRM((TB,_T("BBAR Command Close"))); TRC_ASSERT( bbarNotInit != _state, (TB,_T("bbar not initalized - state:0x%x"), _state)); if (bbarNotInit != _state) { // // Dispatch a close request to the core // if (!_pUi->UI_UserRequestedClose()) { // Request for clean close down (including firing of events // asking container if they really want to close) has failed // so trigger an immediate disconnection without user prompts TRC_ALT((TB,_T("UI_UserRequestedClose failed, disconnect now!"))); _pUi->UI_UserInitiatedDisconnect(NL_DISCONNECT_LOCAL); } } DC_END_FN(); } VOID CBBar::OnCmdPin() { DC_BEGIN_FN("OnCmdPin"); TRC_NRM((TB,_T("BBAR Command Pin"))); TRC_ASSERT( bbarNotInit != _state, (TB,_T("bbar not initalized - state:0x%x"), _state)); TRC_ASSERT(_hwndPinBar, (TB,_T("Left bar not created"))); if (bbarNotInit != _state) { // // The pin button acts like a toggle // _fPinned = !_fPinned; SendMessage(_hwndPinBar, TB_PRESSBUTTON, IDM_PIN, MAKELONG(_fPinned,0)); SendMessage(_hwndPinBar, TB_CHANGEBITMAP, IDM_PIN, MAKELPARAM( _fPinned ?_nPinDownImage : _nPinUpImage, 0)); if(!_fPinned && bbarLowered == _state ) { // We just unpinned trigger an OnLowered event // to startup the autohide timers OnBBarLowered(); } } DC_END_FN(); } // // Notification from core that we entered fullscreen mode // VOID CBBar::OnNotifyEnterFullScreen() { DC_BEGIN_FN("OnNotifyEnterFullScreen"); // // Lower bbar to give a visual cue // if(_state != bbarNotInit) { StartLowerBBar(); } DC_END_FN(); } // // Notification from core that we left fullscreen mode // VOID CBBar::OnNotifyLeaveFullScreen() { DC_BEGIN_FN("OnNotifyLeaveFullScreen"); // // Disable the bbar in windowed mode // if(_state != bbarNotInit) { //Kill timers KillTimer( _hwndBBar, BBAR_TIMERID_AUTOHIDE); KillTimer( _hwndBBar, BBAR_TIMERID_ANIM); //Immediate raise of the bbar if(_state != bbarRaised) { ImmediateRaiseBBar(); } } DC_END_FN(); } // // Raise the bbar without much fanfare (i.e animations) // this is used to quickly 'hide' the bbar // BOOL CBBar::ImmediateRaiseBBar() { DC_BEGIN_FN("ImmediateRaiseBBar"); if(_state != bbarNotInit && _state != bbarRaised) { _nBBarVertOffset = 0; _state = bbarRaised; if(SetWindowPos(_hwndBBar, NULL, _rcBBarLoweredAspect.left, //x _nBBarVertOffset - _sizeLoweredBBar.cy, //y 0,0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE )) { TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"), GetLastError())); } OnBBarRaised(); } DC_END_FN(); return TRUE; } #ifdef OS_WINCE // // Lower the bbar without much fanfare (i.e animations) // this is used to quickly 'show' the bbar // BOOL CBBar::ImmediateLowerBBar() { DC_BEGIN_FN("ImmediateLowerBBar"); if(_state != bbarNotInit && _state != bbarLowered) { _nBBarVertOffset = _sizeLoweredBBar.cy; _state = bbarLowered; if(!SetWindowPos(_hwndBBar, NULL, _rcBBarLoweredAspect.left, //x _nBBarVertOffset - _sizeLoweredBBar.cy, //y 0,0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE )) { TRC_ALT((TB,_T("SetWindowPos failed - 0x%x"), GetLastError())); } OnBBarLowered(); } DC_END_FN(); return TRUE; } #endif VOID CBBar::OnSysColorChange() { DC_BEGIN_FN("OnSysColorChange"); if (_state != bbarNotInit) { // // Force a reload of the images // so they get updated for the new system colors // ReloadImages(); } DC_END_FN(); } #ifdef OS_WINCE //Assumes four points in the array HRGN CBBar::GetBBarRgn(POINT *pts) { DC_BEGIN_FN("CBBar::GetBBarRgn"); HRGN hRgn=NULL, hRgn1=NULL; int nRect, nTotalRects, nStart; RGNDATA *pRgnData = NULL; RECT *pRect = NULL; BOOL bSuccess = FALSE; TRC_ASSERT((pts[2].x - pts[1].x == pts[0].x - pts[3].x), (TB,_T("Invalid points!"))); nTotalRects = (pts[2].x - pts[1].x + 1) /2; pRgnData = (RGNDATA *)LocalAlloc(0, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects)); if (!pRgnData) return NULL; pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); pRgnData->rdh.iType = RDH_RECTANGLES; pRgnData->rdh.nCount = nTotalRects; pRgnData->rdh.nRgnSize = (sizeof(RECT)*nTotalRects); pRect = (RECT *)pRgnData->Buffer; hRgn = CreateRectRgn(pts[0].x + 1, pts[3].y, pts[1].x, pts[1].y); if (!hRgn) DC_QUIT; SetRect(&(pRgnData->rdh.rcBound), 0, 0, pts[0].x, pts[0].y); //The left triangle nStart = pts[3].x + 1; for (nRect = 0; nRect < nTotalRects; nRect++) { SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, nStart); TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom)); nStart += 2; } hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData); if (!hRgn1) DC_QUIT; if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR)) DC_QUIT; DeleteObject(hRgn1); //The left triangle offset by one pixel to avoid a striped triangle nStart = pts[3].x + 2; for (nRect = 0; nRect < nTotalRects; nRect++) { SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, nStart); TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom)); nStart += 2; } hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData); if (!hRgn1) DC_QUIT; if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR)) DC_QUIT; DeleteObject(hRgn1); //The right triangle nStart = pts[1].x - 1; for (nRect = 0; nRect < nTotalRects; nRect++) { SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, pts[2].x - nStart); TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom)); nStart += 2; } hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData); if (!hRgn1) DC_QUIT; if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR)) DC_QUIT; DeleteObject(hRgn1); //The right triangle offset by one pixel to avoid a striped triangle nStart = pts[1].x; for (nRect = 0; nRect < nTotalRects; nRect++) { SetRect(&pRect[nRect], nStart, pts[3].y, nStart + 1, pts[2].x - nStart); TRC_DBG((TB,_T("pRect[%d]={%d,%d,%d,%d}"), nRect, pRect[nRect].left, pRect[nRect].top, pRect[nRect].right, pRect[nRect].bottom)); nStart += 2; } hRgn1 = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT)*nTotalRects), pRgnData); if (!hRgn1) DC_QUIT; if (ERROR == CombineRgn(hRgn, hRgn, hRgn1, RGN_OR)) DC_QUIT; DeleteObject(hRgn1); hRgn1 = NULL; bSuccess = TRUE; DC_EXIT_POINT: LocalFree(pRgnData); if (hRgn1) DeleteObject(hRgn1); if (!bSuccess && hRgn) { DeleteObject(hRgn); hRgn = NULL; } DC_END_FN(); return hRgn; } #endif //OS_WINCE #endif // USE_BBAR