www.pudn.com > ExpBar_src.zip > colheader.c


/* 
 * file           : colheader.c 
 * language       : ANSI/ISO C 
 * plattform      : Win32 (Windows 98/Me/NT/2000/XP) 
 * description    : implements collapsible header for the xp-style explorer bar 
 * 
 * revision history: 
 * ================= 
 * 
 * date:       author:           description: 
 * -------------------------------------------------------------------------- 
 * 02/17/2004  Ingo A. Kubbilun  first published version 1.0 
 */ 
 
#include  
#include  
#include  
 
#define CHS_NOAUTOSIZE          CHS_reserved 
 
#define ISRECT(_r)              ((((_r).right-(_r).left)>0) && (((_r).bottom-(_r).top)>0)) 
 
static void APIPRIVATE AlphaBlendHeaderBitmap ( HDC hDC, HDC hDCMem, HBITMAP hBitmap, LPRECT lpRC, int iBmpWidth, int iBmpHeight ); 
 
static void APIPRIVATE GetHitTestRect ( HWND hwnd, PCHSTRUCT pCHS, LPRECT lpRC ) 
{ 
 
  if (GetWindowLong(hwnd,GWL_STYLE) & CHS_NOAUTOSIZE) 
    GetClientRect(hwnd,lpRC); 
  else 
  { 
    memcpy(lpRC,&pCHS->rcBackground,sizeof(RECT)); 
  } 
} 
 
static BOOL APIPRIVATE HitTest ( HWND hwnd, PCHSTRUCT pCHS, POINT pt ) 
{ 
  RECT        rc; 
 
  if (GetWindowLong(hwnd,GWL_STYLE) & CHS_NOAUTOSIZE) 
  { 
    GetClientRect(hwnd,&rc); 
    return PtInRect(&rc,pt); 
  } 
  else 
  { 
    if (PtInRect(&pCHS->rcBackground,pt)) return TRUE; 
    return PtInRect(&pCHS->rcIcon,pt); 
  } 
} 
 
static void APIPRIVATE ResizeTTControl ( HWND hwnd, PCHSTRUCT pCHS ) 
{ 
  TOOLINFO          ti; 
 
  if ((pCHS) && (CH_HAVE_TOOLTIP_SAFE(pCHS))) 
  { 
    memset(&ti,0,sizeof(ti)); 
    ti.cbSize   = sizeof(TOOLINFO); 
    ti.uFlags   = TTF_TRANSPARENT; 
    ti.hwnd     = hwnd; 
    ti.lpszText = LPSTR_TEXTCALLBACK; 
    ti.uId      = 1; 
    GetHitTestRect(hwnd,pCHS,&ti.rect); 
    SendMessage(pCHS->hwndToolTip,TTM_DELTOOL,0,(LPARAM)&ti); 
    SendMessage(pCHS->hwndToolTip,TTM_ADDTOOL,0,(LPARAM)&ti); 
  } 
} 
 
static void APIPRIVATE CheckNeedRepaint ( HWND hwnd, PCHSTRUCT pCHS ) 
{ 
  int       iState = ITEMSTATE_COLD; 
  POINT     pt; 
 
  if (!pCHS->bEnabled) 
    iState = ITEMSTATE_DISABLED; 
  else 
  { 
    if (pCHS->bKeyDown) 
      iState = ITEMSTATE_PRESSED; 
    else 
    { 
      pt.x = pCHS->iMouseX; 
      pt.y = pCHS->iMouseY; 
      if (HitTest(hwnd,pCHS,pt)) 
      { 
        if (pCHS->bLButtonDown) 
          iState = ITEMSTATE_PRESSED; 
        else 
          iState = ITEMSTATE_HOT; 
      } 
      else 
      if (GetCapture()==hwnd) 
        iState = ITEMSTATE_HOT; 
    } 
  } 
 
  if (pCHS->iState!=iState) 
  { 
    pCHS->iState = iState; 
    InvalidateRect(hwnd,NULL,TRUE); 
  } 
} 
 
// iRequiredWidth only used if !(lStyle & CHS_NOAUTOSIZE) !!! 
static BOOL APIENTRY GetItemSize ( HWND hwnd, PCHSTRUCT pCHS, PSIZE pSI, int iRequiredWidth ) 
{ 
  LONG              lStyle   = GetWindowLong(hwnd,GWL_STYLE); 
  LONG              lExStyle = GetWindowLong(hwnd,GWL_EXSTYLE); 
  UINT              uAlign   = pCHS->chf.uAlign; 
  RECT              rcClient,rcText; 
  SIZE              si; 
  int               iDelta,iArrHeight,iTextHeight,iTextWidth,iSingleTextHeight; 
  HDC               hDC; 
  HGDIOBJ           hOldObj; 
  TCHAR             szText[256]; 
  SIZE              siText,siSingleLine; 
  UINT              uDTStyle; 
 
  si.cx = si.cy = 0; 
 
  if (lExStyle & WS_EX_RIGHT) 
  { 
    if (uAlign==CH_LEFT) uAlign=CH_RIGHT; 
    else 
    if (uAlign==CH_RIGHT) uAlign=CH_LEFT; 
  } 
 
  if (lStyle & CHS_NOAUTOSIZE) 
  { 
    GetClientRect(hwnd,&rcClient); 
    pSI->cx = rcClient.right-rcClient.left; 
    pSI->cy = rcClient.bottom-rcClient.top; 
  } 
  else 
  { 
    if (iRequiredWidth==-1) 
      GetClientRect(hwnd,&rcClient); 
    else 
      rcClient.right  = iRequiredWidth; 
    rcClient.left     = rcClient.top = 0; 
    rcClient.bottom   = 32767; 
  } 
  memcpy(&pCHS->rcBackground,&rcClient,sizeof(RECT)); 
 
  // Calculate icon rect (if any) 
 
  memset(&pCHS->rcIcon,0,sizeof(RECT)); 
  if ((lStyle & CHS_PANEHEADER) && (pCHS->chf.hIList)) 
  { 
    if (ImageList_GetIconSize(pCHS->chf.hIList,&si.cx,&si.cy)) 
    { 
      pCHS->rcIcon.left   = rcClient.left+2; 
      pCHS->rcIcon.top    = rcClient.top; 
      pCHS->rcIcon.right  = pCHS->rcIcon.left+si.cx; 
      pCHS->rcIcon.bottom = pCHS->rcIcon.top+si.cy; 
    } 
  } 
 
  if (si.cx) 
    rcClient.left = pCHS->rcIcon.right; 
 
  if ((!pCHS->chf.hIList) && (pCHS->iLeftMargin))  
    rcClient.left += pCHS->iLeftMargin; 
  else 
    rcClient.left += ((int)pCHS->chf.uBorderLeft); 
 
  rcClient.right -= ((int)pCHS->chf.uBorderRight); 
 
  memset(&pCHS->rcButton,0,sizeof(RECT)); 
  memset(&pCHS->rcText,0,sizeof(RECT)); 
 
  // Calculate button rect 
 
  if (lStyle & CHS_PANEHEADER) 
  { 
    if (lStyle & CHS_SPECIALGROUP)  // special pane header 
    { 
      pCHS->rcButton.right = rcClient.right; 
      pCHS->rcButton.left  = pCHS->rcButton.right-g_sEBI.headerspecial.iBmpArrowWidth; 
      iArrHeight           = g_sEBI.headerspecial.iBmpArrowHeight; 
    } 
    else  // normal pane header 
    { 
      pCHS->rcButton.right = rcClient.right; 
      pCHS->rcButton.left  = pCHS->rcButton.right-g_sEBI.headernormal.iBmpArrowWidth; 
      iArrHeight           = g_sEBI.headernormal.iBmpArrowHeight; 
    } 
  } 
  else  // group header 
  { 
    if (g_sEBI.bPreXP) 
    { 
      pCHS->rcButton.right = rcClient.right; 
      pCHS->rcButton.left  = pCHS->rcButton.right-g_sEBI.iBmpPreXPArrowWidth; 
      iArrHeight           = g_sEBI.iBmpPreXPArrowHeight; 
    } 
    else 
    { 
      pCHS->rcButton.right = rcClient.right; 
      pCHS->rcButton.left  = pCHS->rcButton.right-g_sEBI.headernormal.iBmpArrowWidth; 
      iArrHeight           = g_sEBI.headernormal.iBmpArrowHeight; 
    } 
  } 
 
  rcClient.right  = pCHS->rcButton.left-pCHS->chf.uGap; 
 
  hDC = GetDC(hwnd); 
  if (hDC) 
  { 
    memset(&rcText,0,sizeof(RECT)); 
    hOldObj = SelectObject(hDC,pCHS->hFontHot); 
    szText[0]=0x00; 
    GetWindowText(hwnd,szText,256); 
 
    if (lStyle & CHS_WORDBREAK)         // multiline, use current control width 
    { 
      rcText.left   = 0; 
      rcText.right  = rcClient.right-rcClient.left; 
      if (lStyle & CHS_FOCUSRECT) 
        rcText.right -= 2; 
      uDTStyle = DT_EXTERNALLEADING|DT_WORDBREAK; 
    } 
    else 
    { 
      if (lStyle & CHS_END_ELLIPSIS)    // singleline, use current control width 
      { 
        rcText.left   = 0; 
        rcText.right  = rcClient.right-rcClient.left; 
        if (lStyle & CHS_FOCUSRECT) 
          rcText.right -= 2; 
        uDTStyle = DT_END_ELLIPSIS|DT_SINGLELINE; 
      } 
      else                              // singleline, ignore current control width 
      { 
        rcText.left   = 0; 
        rcText.right  = 0; 
        rcText.top    = 0; 
        rcText.bottom = 0; 
        uDTStyle = DT_SINGLELINE|DT_NOCLIP; 
      } 
    } 
 
    uDTStyle |= DT_CALCRECT|DT_LEFT|DT_TOP; 
    if (lExStyle & WS_EX_RTLREADING) uDTStyle |= DT_RTLREADING; 
 
    siText.cy           = DrawTextEx(hDC,szText,lstrlen(szText),&rcText,uDTStyle,NULL); 
    siText.cx           = rcText.right; 
    rcText.left         = 
    rcText.right        = 
    rcText.top          = 
    rcText.bottom       = 0; 
    uDTStyle = DT_SINGLELINE|DT_NOCLIP|DT_CALCRECT|DT_LEFT|DT_TOP; 
    if (lExStyle & WS_EX_RTLREADING) uDTStyle |= DT_RTLREADING; 
    siSingleLine.cy     = DrawTextEx(hDC,szText,lstrlen(szText),&rcText,uDTStyle,NULL); 
    siSingleLine.cx     = rcText.right; 
 
    iTextHeight = siText.cy; 
    iSingleTextHeight = siSingleLine.cy; 
    if (lStyle & CHS_FOCUSRECT) 
    { 
      iTextHeight += 2; 
      iSingleTextHeight += 2; 
    } 
 
    pCHS->rcButton.top    = 
    pCHS->rcText.top      = (int)pCHS->chf.uBorderTop; 
 
    pCHS->rcText.bottom   = pCHS->rcText.top+iTextHeight; 
    pCHS->rcButton.bottom = pCHS->rcButton.top+iArrHeight; 
 
    pCHS->bMultiLine = (siText.cy>=(siSingleLine.cy<<1)) ? TRUE : FALSE; 
    if (!pCHS->bMultiLine) 
    { 
      if (iArrHeight>iSingleTextHeight) 
      { 
        iDelta = (iArrHeight-iSingleTextHeight)>>1; 
        pCHS->rcText.top+=iDelta; 
        pCHS->rcText.bottom+=iDelta; 
      } 
    } 
 
    rcClient.bottom = pCHS->rcText.bottom>pCHS->rcButton.bottom ? pCHS->rcText.bottom : pCHS->rcButton.bottom; 
    rcClient.bottom += (int)pCHS->chf.uBorderBottom; 
    pCHS->rcBackground.bottom = rcClient.bottom; 
 
    // horizontal alignment 
 
    iTextWidth = siText.cx; 
    if (lStyle & CHS_FOCUSRECT) 
      iTextWidth += 2; 
 
    switch(uAlign) 
    { 
      case CH_CENTER: 
        iDelta = ((rcClient.right-rcClient.left)-iTextWidth)>>1; 
        if (iDelta<0) iDelta=0; 
        pCHS->rcText.left  = rcClient.left+iDelta; 
        pCHS->rcText.right = pCHS->rcText.left+iTextWidth; 
        if (pCHS->rcText.right>rcClient.right) 
          pCHS->rcText.right = rcClient.right; 
        break; 
 
      case CH_RIGHT: 
        pCHS->rcText.right = rcClient.right; 
        pCHS->rcText.left  = pCHS->rcText.right-iTextWidth; 
        if (pCHS->rcText.leftrcText.left = rcClient.left; 
        break; 
 
      default: 
        pCHS->rcText.left  = rcClient.left; 
        pCHS->rcText.right = pCHS->rcText.left+iTextWidth; 
        if (pCHS->rcText.right>rcClient.right) 
          pCHS->rcText.right = rcClient.right; 
        break; 
    } 
    SelectObject(hDC,hOldObj); 
    ReleaseDC(hwnd,hDC); 
  } 
 
  if (si.cy) 
  { 
    iDelta = si.cy-(rcClient.bottom-rcClient.top); 
    if (iDelta>0) 
    { 
      rcClient.top              += iDelta; 
      rcClient.bottom           += iDelta; 
      pCHS->rcBackground.top    += iDelta; 
      pCHS->rcBackground.bottom += iDelta; 
      pCHS->rcText.top += iDelta; 
      pCHS->rcText.bottom += iDelta; 
      pCHS->rcButton.top += iDelta; 
      pCHS->rcButton.bottom += iDelta; 
    } 
  } 
 
  ResizeTTControl(hwnd,pCHS); 
 
  if (lStyle & CHS_NOAUTOSIZE) 
    return TRUE; 
 
  pSI->cx = pCHS->rcBackground.right; 
  pSI->cy = pCHS->rcBackground.bottom; 
 
  return TRUE; 
} 
 
LRESULT CALLBACK CollapsibleHeaderWndProc ( HWND     hwnd, 
                                            UINT     uMsg, 
                                            WPARAM   wParam, 
                                            LPARAM   lParam ) 
{ 
 
  switch(uMsg) 
  { 
    case WM_LBUTTONDOWN: 
    case WM_LBUTTONUP: 
      if (CH_HAVE_DONTRELAYLBDNUP) 
        break; 
    case WM_MBUTTONDOWN: 
    case WM_MBUTTONUP: 
    case WM_RBUTTONDOWN: 
    case WM_RBUTTONUP: 
    case WM_MOUSEMOVE: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        MSG       msg; 
 
        if (!pCHS) break; 
 
        if (CH_HAVE_TOOLTIP_SAFE(pCHS)) 
        { 
          msg.hwnd    = hwnd; 
          msg.message = uMsg; 
          msg.wParam  = wParam; 
          msg.lParam  = lParam; 
          msg.pt.x    = ((int)(short)LOWORD(lParam)); 
          msg.pt.y    = ((int)(short)HIWORD(lParam)); 
          ClientToScreen(hwnd,&msg.pt); 
          SendMessage(pCHS->hwndToolTip,TTM_RELAYEVENT,(WPARAM)0,(LPARAM)&msg); 
        } 
        break; 
      } 
  } 
 
  switch(uMsg) 
  { 
    case WM_GETORIGDIMENSIONS: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (pCHS) 
        { 
          *((int*)wParam) = pCHS->iOrigWidth; 
          *((int*)lParam) = pCHS->iOrigHeight; 
        } 
        else 
        { 
          *((int*)wParam) = 0; 
          *((int*)lParam) = 0; 
        } 
        return 0L; 
      } 
 
    case WM_CREATE: 
      { 
        PCHSTRUCT         pCHS   = (PCHSTRUCT)malloc(sizeof(CHSTRUCT)); 
        LONG              lStyle = GetWindowLong(hwnd,GWL_STYLE); 
        LOGFONT           lf; 
        SIZE              si; 
 
        if (!pCHS) return -1L; 
 
        memset(pCHS,0,sizeof(CHSTRUCT)); 
 
        { 
          RECT rcClient; 
          GetClientRect(hwnd,&rcClient); 
          pCHS->iOrigWidth  = rcClient.right; 
          pCHS->iOrigHeight = rcClient.bottom; 
        } 
 
        pCHS->cbSize    = sizeof(CHSTRUCT); 
        pCHS->iMouseX   = -1; 
        pCHS->iMouseY   = -1; 
        pCHS->bActive   = TRUE; 
        pCHS->bExpanded = lStyle & CHS_CREATEEXPANDED ? TRUE : FALSE; 
        pCHS->bEnabled  = IsWindowEnabled(hwnd); 
        if (!pCHS->bEnabled) 
          pCHS->iState  = ITEMSTATE_DISABLED; 
        else 
          pCHS->iState  = ITEMSTATE_COLD; 
 
        if (CH_HAVE_TOOLTIP) 
        { 
          pCHS->hwndToolTip = CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, 
                                             TOOLTIPS_CLASS, 
                                             NULL, 
                                             WS_POPUP|TTS_NOPREFIX, 
                                             CW_USEDEFAULT, 
                                             CW_USEDEFAULT, 
                                             CW_USEDEFAULT, 
                                             CW_USEDEFAULT, 
                                             hwnd, 
                                             NULL, 
                                             NULL, 
                                             NULL); 
          if (!pCHS->hwndToolTip) 
          { 
            free(pCHS); 
            return -1L; 
          } 
          SetWindowPos(pCHS->hwndToolTip,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 
 
          ResizeTTControl(hwnd,pCHS); 
        } 
 
        if (CH_HAVE_TOOLTIP_SAFE(pCHS)) 
          SendMessage(pCHS->hwndToolTip,TTM_ACTIVATE,(WPARAM)((pCHS->bEnabled && pCHS->bActive) ? TRUE : FALSE),0L); 
 
        pCHS->hLightPen  = CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DHILIGHT)); 
        pCHS->hShadowPen = CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DSHADOW)); 
 
        memset(&lf,0,sizeof(LOGFONT)); 
        if (lStyle & CHS_PANEHEADER) 
        { 
          if (lStyle & CHS_SPECIALGROUP) 
          { 
            pCHS->chf.cbSize        = sizeof(CHFORMAT); 
            pCHS->chf.iFontSize     = g_sEBI.headerspecial.iFontSize; 
#ifdef UNICODE 
            MultiByteToWideChar(CP_ACP,0,g_sEBI.headerspecial.szFontFace,-1,pCHS->chf.szFontFace,MAX_PATH); 
#else 
            strcpy(pCHS->chf.szFontFace,g_sEBI.headerspecial.szFontFace); 
#endif 
            pCHS->chf.iFWNormal     = g_sEBI.headerspecial.iFontWeightHeader; 
            pCHS->chf.iFWHot        = g_sEBI.headerspecial.iFontWeightHeader; 
            pCHS->chf.crNormal      = g_sEBI.headerspecial.crHeaderNormal; 
            pCHS->chf.crHot         = g_sEBI.headerspecial.crHeaderHot; 
            if (g_sEBI.headerspecial.uAlignment & TDA_CENTER) 
              pCHS->chf.uAlign = CH_CENTER; 
            else 
            if (g_sEBI.headerspecial.uAlignment & TDA_RIGHT) 
              pCHS->chf.uAlign = CH_RIGHT; 
            else 
              pCHS->chf.uAlign = CH_LEFT; 
 
            pCHS->chf.uBorderTop    = 1; 
            pCHS->chf.uBorderBottom = 1; 
            pCHS->chf.uBorderLeft   = 4; 
            pCHS->chf.uGap          = 4; 
            pCHS->chf.uBorderRight  = 4; 
            pCHS->chf.hCursor       = LoadCursor(NULL,IDC_HAND); 
          } 
          else 
          { 
            pCHS->chf.cbSize        = sizeof(CHFORMAT); 
            pCHS->chf.iFontSize     = g_sEBI.headernormal.iFontSize; 
#ifdef UNICODE 
            MultiByteToWideChar(CP_ACP,0,g_sEBI.headernormal.szFontFace,-1,pCHS->chf.szFontFace,MAX_PATH); 
#else 
            strcpy(pCHS->chf.szFontFace,g_sEBI.headernormal.szFontFace); 
#endif 
            pCHS->chf.iFWNormal     = g_sEBI.headernormal.iFontWeightHeader; 
            pCHS->chf.iFWHot        = g_sEBI.headernormal.iFontWeightHeader; 
            pCHS->chf.crNormal      = g_sEBI.headernormal.crHeaderNormal; 
            pCHS->chf.crHot         = g_sEBI.headernormal.crHeaderHot; 
            if (g_sEBI.headernormal.uAlignment & TDA_CENTER) 
              pCHS->chf.uAlign = CH_CENTER; 
            else 
            if (g_sEBI.headernormal.uAlignment & TDA_RIGHT) 
              pCHS->chf.uAlign = CH_RIGHT; 
            else 
              pCHS->chf.uAlign = CH_LEFT; 
 
            pCHS->chf.uBorderTop    = 1; 
            pCHS->chf.uBorderBottom = 1; 
            pCHS->chf.uBorderLeft   = 4; 
            pCHS->chf.uGap          = 4; 
            pCHS->chf.uBorderRight  = 4; 
            pCHS->chf.hCursor       = LoadCursor(NULL,IDC_HAND); 
          } 
        } 
        else  // group header 
        { 
          pCHS->chf.cbSize        = sizeof(CHFORMAT); 
          pCHS->chf.iFWNormal     = FW_BOLD; 
          pCHS->chf.iFWHot        = FW_BOLD; 
          pCHS->chf.crNormal      = GetSysColor(COLOR_BTNTEXT); 
          pCHS->chf.crHot         = GetSysColor(COLOR_HOTLIGHT); 
          pCHS->chf.uAlign        = CH_LEFT; 
 
          pCHS->chf.uGap          = 4; 
 
          pCHS->chf.hCursor       = LoadCursor(NULL,IDC_HAND); 
 
          GetLogFont(GetStockObject(DEFAULT_GUI_FONT),&lf); 
          goto CreateFonts; 
        } 
 
        lf.lfHeight         = pCHS->chf.iFontSize; 
        lf.lfCharSet        = DEFAULT_CHARSET; 
        lf.lfQuality        = DEFAULT_QUALITY; 
        lf.lfPitchAndFamily = DEFAULT_PITCH; 
        __strcpy(lf.lfFaceName,pCHS->chf.szFontFace); 
 
        CreateFonts: 
        lf.lfWeight         = pCHS->chf.iFWNormal; 
        lf.lfItalic         = pCHS->chf.bItalicNormal; 
        lf.lfUnderline      = pCHS->chf.bULNormal; 
        pCHS->hFontNormal = CreateFontIndirect(&lf); 
 
        lf.lfWeight         = pCHS->chf.iFWHot; 
        lf.lfItalic         = pCHS->chf.bItalicHot; 
        lf.lfUnderline      = pCHS->chf.bULHot; 
 
        pCHS->hFontHot = CreateFontIndirect(&lf); 
 
        SetWindowLong(hwnd,GWL_USERDATA,(LONG)pCHS); 
 
        if (GetItemSize(hwnd,pCHS,&si,-1)) 
        { 
          SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); 
          ResizeTTControl(hwnd,pCHS); 
        } 
 
        return 0L; 
      } 
 
    case WM_DESTROY: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if ((pCHS) && (pCHS->cbSize==sizeof(CHSTRUCT))) 
        { 
          if (pCHS->hwndToolTip) 
            DestroyWindow(pCHS->hwndToolTip); 
          if (pCHS->hFontHot) 
            DeleteObject(pCHS->hFontHot); 
          if (pCHS->hFontNormal) 
            DeleteObject(pCHS->hFontNormal); 
          if (pCHS->hLightPen) 
            DeleteObject(pCHS->hLightPen); 
          if (pCHS->hShadowPen) 
            DeleteObject(pCHS->hShadowPen); 
           
          free(pCHS); 
          SetWindowLong(hwnd,GWL_USERDATA,(LONG)0L); 
        } 
        break; 
      } 
 
    case WM_SETFONT: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        LOGFONT   lf; 
        SIZE      si; 
        LONG      lStyle = GetWindowLong(hwnd,GWL_STYLE); 
 
        if ((!pCHS) || (lStyle & CHS_PANEHEADER)) return 0L; 
         
        if (pCHS->hFontNormal) 
        { 
          DeleteObject(pCHS->hFontNormal); 
          pCHS->hFontNormal = NULL; 
        } 
        if (pCHS->hFontHot) 
        { 
          DeleteObject(pCHS->hFontHot); 
          pCHS->hFontHot = NULL; 
        } 
 
        if (GetLogFont( wParam ? ((HFONT)wParam) : ((HFONT)GetStockObject(DEFAULT_GUI_FONT)),&lf) ) 
        { 
          lf.lfWeight         = pCHS->chf.iFWNormal; 
          lf.lfItalic         = pCHS->chf.bItalicNormal; 
          lf.lfUnderline      = pCHS->chf.bULNormal; 
          pCHS->hFontNormal = CreateFontIndirect(&lf); 
 
          lf.lfWeight         = pCHS->chf.iFWHot; 
          lf.lfItalic         = pCHS->chf.bItalicHot; 
          lf.lfUnderline      = pCHS->chf.bULHot; 
 
          pCHS->hFontHot = CreateFontIndirect(&lf); 
 
          if (GetItemSize(hwnd,pCHS,&si,-1)) 
          { 
            SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOREDRAW); 
            ResizeTTControl(hwnd,pCHS); 
          } 
 
          if (LOWORD(lParam)) 
            InvalidateRect(hwnd,NULL,TRUE); 
        } 
        return 0L; 
      } 
 
    case CHM_GETTTCTRL: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return (LPARAM)NULL; 
 
        return (LPARAM)pCHS->hwndToolTip; 
      } 
 
    case CHM_SETSTATE: // wParam = (BOOL)bExpand, lParam = (BOOL)bRepaint 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        pCHS->bExpanded = (BOOL)wParam; 
 
        if (CH_HAVE_PLAYSOUND) 
          PlaySoundThemeSound( pCHS->bExpanded ? TEXT(".Default\\Maximize") : TEXT(".Default\\Minimize") ); 
 
        if (lParam) 
          InvalidateRect(hwnd,NULL,TRUE); 
         
        return 0L; 
      } 
 
    case CHM_GETSTATE: // returns: (BOOL)bExpanded 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return FALSE; 
 
        return pCHS->bExpanded; 
      } 
 
    case WM_NCHITTEST: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        POINT     pt; 
 
        if (!pCHS) break; 
        pt.x = (int)((short)LOWORD(lParam)); 
        pt.y = (int)((short)HIWORD(lParam)); 
        ScreenToClient(hwnd,&pt); 
        if (HitTest(hwnd,pCHS,pt)) 
          return HTCLIENT; 
        else 
          return HTNOWHERE; 
      } 
 
    case WM_SETCURSOR: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return FALSE; 
        if (!pCHS->bActive) break; 
 
        if (LOWORD(lParam)==HTCLIENT) 
          SetCursor(pCHS->chf.hCursor ? pCHS->chf.hCursor : LoadCursor(NULL,IDC_HAND)); 
        else 
          SetCursor(LoadCursor(NULL,IDC_ARROW)); 
 
        return TRUE; 
      } 
 
    case WM_ERASEBKGND: 
        return TRUE; 
 
    case CHM_SETICON: // wParam = HIMAGELIST, lParam = idx 
      { 
        PCHSTRUCT pCHS   = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        SIZE      si; 
 
        if (!pCHS) return FALSE; 
 
        pCHS->chf.hIList = (HIMAGELIST)wParam; 
        pCHS->chf.iIIdx  = (int)lParam; 
 
        if (GetItemSize(hwnd,pCHS,&si,-1)) 
          SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); 
 
        InvalidateRect(hwnd,NULL,TRUE); 
        return TRUE; 
      } 
 
    case CHM_SETFORMAT: // lParam = pointer to memory with CHFORMAT structure 
      { 
        PCHSTRUCT pCHS   = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        PCHFORMAT pCHF   = (PCHFORMAT)lParam; 
        LONG      lStyle = GetWindowLong(hwnd,GWL_STYLE); 
        SIZE      si; 
        LOGFONT   lf; 
 
        if (!pCHS) return FALSE; 
 
        if (IsBadReadPtr((LPCVOID)lParam,sizeof(CHFORMAT))) // return to original 
        { 
          if (lStyle & CHS_PANEHEADER) 
          { 
            pCHS->chf.uBorderTop    = 1; 
            pCHS->chf.uBorderBottom = 1; 
            pCHS->chf.uBorderLeft   = 4; 
            pCHS->chf.uGap          = 4; 
            pCHS->chf.uBorderRight  = 4; 
            pCHS->chf.hCursor       = LoadCursor(NULL,IDC_HAND); 
            pCHS->chf.hIList        = NULL; 
            pCHS->chf.iIIdx         = 0; 
          } 
          else 
          { 
            pCHS->chf.cbSize        = sizeof(CHFORMAT); 
            pCHS->chf.iFWNormal     = FW_BOLD; 
            pCHS->chf.iFWHot        = FW_BOLD; 
            pCHS->chf.crNormal      = GetSysColor(COLOR_BTNTEXT); 
            pCHS->chf.crHot         = GetSysColor(COLOR_HOTLIGHT); 
            pCHS->chf.uAlign        = CH_LEFT; 
 
            pCHS->chf.uBorderTop    = 0; 
            pCHS->chf.uBorderBottom = 0; 
            pCHS->chf.uBorderLeft   = 0; 
            pCHS->chf.uGap          = 4; 
            pCHS->chf.uBorderRight  = 0; 
 
            pCHS->chf.hCursor       = LoadCursor(NULL,IDC_HAND); 
 
            GetLogFont(GetStockObject(DEFAULT_GUI_FONT),&lf); 
            goto CreateFonts2; 
          } 
          goto DoUpdate; 
        } 
 
        if (pCHF->cbSize!=sizeof(CHFORMAT))  
          return FALSE; 
 
        if (lStyle & CHS_PANEHEADER) 
        { 
          pCHS->chf.uBorderTop    = pCHF->uBorderTop; 
          pCHS->chf.uBorderBottom = pCHF->uBorderBottom; 
          pCHS->chf.uBorderLeft   = pCHF->uBorderLeft; 
          pCHS->chf.uGap          = pCHF->uGap; 
          pCHS->chf.uBorderRight  = pCHF->uBorderRight; 
          pCHS->chf.hCursor       = pCHF->hCursor; 
          pCHS->chf.hIList        = pCHF->hIList; 
          pCHS->chf.iIIdx         = pCHF->iIIdx; 
        } 
        else 
        { 
          memcpy(&pCHS->chf,pCHF,sizeof(CHFORMAT)); 
 
          if (pCHS->hFontHot) DeleteObject(pCHS->hFontHot); 
          if (pCHS->hFontNormal) DeleteObject(pCHS->hFontNormal); 
 
          if (!pCHS->chf.iFontSize) 
          { 
            GetLogFont(GetStockObject(DEFAULT_GUI_FONT),&lf); 
            goto CreateFonts2; 
          } 
          else 
          { 
            lf.lfHeight         = pCHS->chf.iFontSize; 
            lf.lfCharSet        = DEFAULT_CHARSET; 
            lf.lfQuality        = DEFAULT_QUALITY; 
            lf.lfPitchAndFamily = DEFAULT_PITCH; 
            __strcpy(lf.lfFaceName,pCHS->chf.szFontFace); 
 
            CreateFonts2: 
            lf.lfWeight         = pCHS->chf.iFWNormal; 
            lf.lfItalic         = pCHS->chf.bItalicNormal; 
            lf.lfUnderline      = pCHS->chf.bULNormal; 
            pCHS->hFontNormal = CreateFontIndirect(&lf); 
 
            lf.lfWeight         = pCHS->chf.iFWHot; 
            lf.lfItalic         = pCHS->chf.bItalicHot; 
            lf.lfUnderline      = pCHS->chf.bULHot; 
 
            pCHS->hFontHot = CreateFontIndirect(&lf); 
          } 
        } 
 
        DoUpdate: 
        if (GetItemSize(hwnd,pCHS,&si,-1)) 
          SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); 
 
        InvalidateRect(hwnd,NULL,TRUE); 
        return TRUE; 
      } 
 
    case CHM_GETFORMAT: // wParam = sizeof(CHFORMAT), lParam = pointer to memory to store CHFORMAT struct. 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return FALSE; 
 
        if (wParam!=sizeof(CHFORMAT)) return FALSE; 
 
        if (IsBadWritePtr((LPVOID)lParam,sizeof(CHFORMAT))) return FALSE; 
 
        memcpy((LPVOID)lParam,&pCHS->chf,sizeof(CHFORMAT)); 
 
        return TRUE; 
      } 
 
    case WM_THEMECHANGED: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        LOGFONT   lf; 
        LONG      lStyle = GetWindowLong(hwnd,GWL_STYLE); 
        SIZE      si; 
 
        if (!pCHS) return 0L; 
 
        memset(&lf,0,sizeof(LOGFONT)); 
        if (lStyle & CHS_PANEHEADER) 
        { 
          if (lStyle & CHS_SPECIALGROUP) 
          { 
            pCHS->chf.iFontSize     = g_sEBI.headerspecial.iFontSize; 
#ifdef UNICODE 
            MultiByteToWideChar(CP_ACP,0,g_sEBI.headerspecial.szFontFace,-1,pCHS->chf.szFontFace,MAX_PATH); 
#else 
            strcpy(pCHS->chf.szFontFace,g_sEBI.headerspecial.szFontFace); 
#endif 
            pCHS->chf.iFWNormal     = g_sEBI.headerspecial.iFontWeightHeader; 
            pCHS->chf.iFWHot        = g_sEBI.headerspecial.iFontWeightHeader; 
            pCHS->chf.crNormal      = g_sEBI.headerspecial.crHeaderNormal; 
            pCHS->chf.crHot         = g_sEBI.headerspecial.crHeaderHot; 
            if (g_sEBI.headerspecial.uAlignment & TDA_CENTER) 
              pCHS->chf.uAlign = CH_CENTER; 
            else 
            if (g_sEBI.headerspecial.uAlignment & TDA_RIGHT) 
              pCHS->chf.uAlign = CH_RIGHT; 
            else 
              pCHS->chf.uAlign = CH_LEFT; 
          } 
          else 
          { 
            pCHS->chf.iFontSize     = g_sEBI.headernormal.iFontSize; 
#ifdef UNICODE 
            MultiByteToWideChar(CP_ACP,0,g_sEBI.headernormal.szFontFace,-1,pCHS->chf.szFontFace,MAX_PATH); 
#else 
            strcpy(pCHS->chf.szFontFace,g_sEBI.headernormal.szFontFace); 
#endif 
            pCHS->chf.iFWNormal     = g_sEBI.headernormal.iFontWeightHeader; 
            pCHS->chf.iFWHot        = g_sEBI.headernormal.iFontWeightHeader; 
            pCHS->chf.crNormal      = g_sEBI.headernormal.crHeaderNormal; 
            pCHS->chf.crHot         = g_sEBI.headernormal.crHeaderHot; 
            if (g_sEBI.headernormal.uAlignment & TDA_CENTER) 
              pCHS->chf.uAlign = CH_CENTER; 
            else 
            if (g_sEBI.headernormal.uAlignment & TDA_RIGHT) 
              pCHS->chf.uAlign = CH_RIGHT; 
            else 
              pCHS->chf.uAlign = CH_LEFT; 
          } 
        } 
        else  // group header 
        { 
          return 0L; 
        } 
 
        if (pCHS->hFontNormal) DeleteObject(pCHS->hFontNormal); 
        if (pCHS->hFontHot) DeleteObject(pCHS->hFontHot); 
 
        lf.lfHeight         = pCHS->chf.iFontSize; 
        lf.lfCharSet        = DEFAULT_CHARSET; 
        lf.lfQuality        = DEFAULT_QUALITY; 
        lf.lfPitchAndFamily = DEFAULT_PITCH; 
        __strcpy(lf.lfFaceName,pCHS->chf.szFontFace); 
 
        lf.lfWeight         = pCHS->chf.iFWNormal; 
        lf.lfItalic         = pCHS->chf.bItalicNormal; 
        lf.lfUnderline      = pCHS->chf.bULNormal; 
        pCHS->hFontNormal = CreateFontIndirect(&lf); 
 
        lf.lfWeight         = pCHS->chf.iFWHot; 
        lf.lfItalic         = pCHS->chf.bItalicHot; 
        lf.lfUnderline      = pCHS->chf.bULHot; 
 
        pCHS->hFontHot = CreateFontIndirect(&lf); 
 
        if (GetItemSize(hwnd,pCHS,&si,-1)) 
          SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); 
 
        InvalidateRect(hwnd,NULL,TRUE); 
        return 0L; 
      } 
 
    case WM_SYSCOLORCHANGE: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        LONG      lStyle = GetWindowLong(hwnd,GWL_STYLE); 
 
        if (!pCHS) return 0L; 
 
        if (pCHS->hLightPen) DeleteObject(pCHS->hLightPen); 
        if (pCHS->hShadowPen) DeleteObject(pCHS->hShadowPen); 
        pCHS->hLightPen  = CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DHILIGHT)); 
        pCHS->hShadowPen = CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DSHADOW)); 
 
        if ((!(lStyle & CHS_PANEHEADER)) && (!pCHS->bColorSet)) 
        { 
          pCHS->chf.crNormal = GetSysColor(COLOR_BTNTEXT); 
          pCHS->chf.crHot    = GetSysColor(COLOR_HOTLIGHT); 
        } 
 
        return 0L; 
      } 
 
    case WM_SIZE: 
    { 
      PCHSTRUCT         pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
      SIZE              si; 
 
      if (!pCHS) return FALSE; 
 
      GetItemSize(hwnd,pCHS,&si,-1); 
      break; 
    } 
 
    case WM_CALCDIMENSIONS: // wParam = LPSIZE, lParam = width of control in px (-1 = get current width) 
      { 
        PCHSTRUCT         pCHSSave,pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        BOOL              bReturn; 
 
        if (!pCHS) return FALSE; 
 
        if (IsBadWritePtr((VOID *)wParam,sizeof(SIZE))) 
          return FALSE; 
 
        pCHSSave = (PCHSTRUCT)malloc(sizeof(CHSTRUCT)); 
        if (!pCHSSave) return FALSE; 
        memcpy(pCHSSave,pCHS,sizeof(CHSTRUCT)); 
        bReturn = GetItemSize(hwnd,pCHS,(PSIZE)wParam,(int)lParam); 
        memcpy(pCHS,pCHSSave,sizeof(CHSTRUCT)); 
        return bReturn; 
      } 
 
    case WM_ENABLE: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        pCHS->bEnabled = (wParam ? TRUE : FALSE); 
        CheckNeedRepaint(hwnd,pCHS); 
 
        if (CH_HAVE_TOOLTIP_SAFE(pCHS)) 
          SendMessage(pCHS->hwndToolTip,TTM_ACTIVATE,(WPARAM)((pCHS->bEnabled && pCHS->bActive) ? TRUE : FALSE),0L); 
 
        return 0L; 
      } 
 
    case CHM_ACTIVATE:  // wParam = BOOL 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        pCHS->bActive = (BOOL)wParam; 
 
        if (!pCHS->bActive) 
        { 
          if (pCHS->bEnabled) 
          { 
            pCHS->iState        = ITEMSTATE_COLD; 
            pCHS->bLButtonDown  = FALSE; 
            pCHS->iMouseX       = -1; 
            pCHS->iMouseY       = -1; 
            InvalidateRect(hwnd,NULL,TRUE); 
          } 
        } 
 
        if (CH_HAVE_TOOLTIP_SAFE(pCHS)) 
          SendMessage(pCHS->hwndToolTip,TTM_ACTIVATE,(WPARAM)((pCHS->bEnabled && pCHS->bActive) ? TRUE : FALSE),0L); 
 
        return 0L; 
      } 
 
    case WM_KEYDOWN: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        if ((wParam==VK_SPACE) && (pCHS->bFocus) && (pCHS->bEnabled) && (pCHS->bActive) && (GetCapture()!=hwnd)) 
        { 
          pCHS->bKeyDown = TRUE; 
          CheckNeedRepaint(hwnd,pCHS); 
        } 
        return 0L; 
      } 
 
    case WM_KEYUP: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        if ((wParam==VK_SPACE) && (pCHS->bFocus) && (pCHS->bEnabled) && (pCHS->bActive) && (pCHS->bKeyDown)) 
        { 
          pCHS->bKeyDown = FALSE; 
          CheckNeedRepaint(hwnd,pCHS); 
 
          if (pCHS->bEnabled) 
          { 
            //NMHDR       nmh; 
 
            pCHS->bExpanded ^= TRUE; 
            if (CH_HAVE_PLAYSOUND) 
              PlaySoundThemeSound( pCHS->bExpanded ? TEXT(".Default\\Maximize") : TEXT(".Default\\Minimize") ); 
/* 
            nmh.code     = pCHS->bExpanded ? CHN_EXPANDED : CHN_COLLAPSED; 
            nmh.hwndFrom = hwnd; 
            nmh.idFrom   = GetWindowLong(hwnd,GWL_ID); 
            SendMessage(GetParent(hwnd),WM_NOTIFY,(WPARAM)hwnd,(LPARAM)&nmh); 
*/ 
            SendMessage(GetParent(hwnd), 
                        WM_COMMAND, 
                        MAKELONG( ((WORD)GetWindowLong(hwnd,GWL_ID)), (WORD)(pCHS->bExpanded ? CHN_EXPANDED : CHN_COLLAPSED) ), 
                        (LPARAM)hwnd); 
          } 
        } 
        return 0L; 
      } 
 
    case WM_LBUTTONDOWN: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
        if ((!pCHS->bActive) || (!pCHS->bEnabled)) return 0L; 
 
        pCHS->iMouseX      = (int)((short)LOWORD(lParam)); 
        pCHS->iMouseY      = (int)((short)HIWORD(lParam)); 
        pCHS->bLButtonDown = TRUE; 
        if ((!CH_HAVE_NSFOC) && (pCHS->bEnabled)) SetFocus(hwnd); 
        SetCapture(hwnd); 
        CheckNeedRepaint(hwnd,pCHS); 
        return 0L; 
      } 
 
    case WM_LBUTTONUP: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        RECT      rcClient; 
        POINT     pt; 
 
        if (!pCHS) return 0L; 
        if ((!pCHS->bActive) || (!pCHS->bEnabled)) return 0L; 
 
        pCHS->iMouseX = (int)((short)LOWORD(lParam)); 
        pCHS->iMouseY = (int)((short)HIWORD(lParam)); 
        if (pCHS->bLButtonDown) 
        { 
          pCHS->bLButtonDown = FALSE; 
          CheckNeedRepaint(hwnd,pCHS); 
 
          pt.x = pCHS->iMouseX; 
          pt.y = pCHS->iMouseY; 
          GetClientRect(hwnd,&rcClient); 
          if (PtInRect(&rcClient,pt)) 
          { 
            ReleaseCapture(); 
            if ((pCHS->bEnabled) /*&& (pCHS->iState==ITEMSTATE_HOT)*/) 
            { 
//              NMHDR       nmh; 
 
              pCHS->bExpanded ^= TRUE; 
              if (CH_HAVE_PLAYSOUND) 
                PlaySoundThemeSound( pCHS->bExpanded ? TEXT(".Default\\Maximize") : TEXT(".Default\\Minimize") ); 
/* 
              nmh.code     = pCHS->bExpanded ? CHN_EXPANDED : CHN_COLLAPSED; 
              nmh.hwndFrom = hwnd; 
              nmh.idFrom   = GetWindowLong(hwnd,GWL_ID); 
              SendMessage(GetParent(hwnd),WM_NOTIFY,(WPARAM)hwnd,(LPARAM)&nmh); 
*/ 
              SendMessage(GetParent(hwnd), 
                          WM_COMMAND, 
                          MAKELONG( ((WORD)GetWindowLong(hwnd,GWL_ID)), (WORD)(pCHS->bExpanded ? CHN_EXPANDED : CHN_COLLAPSED) ), 
                          (LPARAM)hwnd); 
            } 
          } 
          else 
            ReleaseCapture(); 
        } 
        return 0L; 
      } 
 
    case WM_MOUSELEAVE: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        pCHS->iMouseX     = -1; 
        pCHS->iMouseY     = -1; 
        pCHS->bTrackMouse = FALSE; 
        CheckNeedRepaint(hwnd,pCHS); 
 
        return 0L; 
      } 
 
    case WM_MOUSEMOVE: 
      { 
        PCHSTRUCT       pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        TRACKMOUSEEVENT tme; 
 
        if (!pCHS) return 0L; 
        if ((!pCHS->bActive) || (!pCHS->bEnabled)) return 0L; 
 
        if (!pCHS->bTrackMouse) 
        { 
          pCHS->bTrackMouse = TRUE; 
          tme.cbSize        = sizeof(TRACKMOUSEEVENT); 
          tme.dwFlags       = TME_LEAVE; 
          tme.dwHoverTime   = 0; 
          tme.hwndTrack     = hwnd; 
          TrackMouseEvent(&tme); 
        } 
 
        pCHS->iMouseX = (int)((short)LOWORD(lParam)); 
        pCHS->iMouseY = (int)((short)HIWORD(lParam)); 
        CheckNeedRepaint(hwnd,pCHS); 
 
        return 0L; 
      } 
 
    case WM_SETFOCUS: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) break; 
 
        pCHS->bFocus = TRUE; 
 
        if (CH_HAVE_FOCUSRECT) 
        { 
          InvalidateRect(hwnd,NULL,TRUE); 
          return 0L; 
        } 
        else 
          break; 
      } 
 
    case WM_KILLFOCUS: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) break; 
 
        pCHS->bFocus   = FALSE; 
        pCHS->bKeyDown = FALSE; 
 
        if (CH_HAVE_FOCUSRECT) 
        { 
          InvalidateRect(hwnd,NULL,TRUE); 
          return 0L; 
        } 
        else 
          break; 
      } 
 
    case WM_CAPTURECHANGED: 
      { 
        PCHSTRUCT pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
 
        if (!pCHS) return 0L; 
 
        pCHS->bLButtonDown = FALSE; 
        pCHS->bTrackMouse  = FALSE; 
        pCHS->iMouseX      = -1; 
        pCHS->iMouseY      = -1; 
        CheckNeedRepaint(hwnd,pCHS); 
 
        return 0L; 
      } 
 
    case WM_NOTIFY: 
    { 
      int       idCtrl = (int)wParam; 
      LPNMHDR   lpnmh  = (LPNMHDR)lParam; 
      PCHSTRUCT pCHS   = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
      HWND      hwndOrig; 
      UINT      idOrig; 
 
      if (!pCHS) break; 
 
      if ((lpnmh->hwndFrom==pCHS->hwndToolTip) && (lpnmh->code==TTN_GETDISPINFO)) 
      { 
        LPNMTTDISPINFO lpnmttdi = (LPNMTTDISPINFO)lParam; 
 
        hwndOrig        = lpnmh->hwndFrom; 
        idOrig          = lpnmh->idFrom; 
        lpnmh->hwndFrom = hwnd; 
        lpnmh->idFrom   = GetWindowLong(hwnd,GWL_ID); 
        lpnmh->code     = CHN_GETDISPINFO; 
        SendMessage(GetParent(hwnd),WM_NOTIFY,(WPARAM)hwnd,(LPARAM)lpnmh); 
        lpnmh->hwndFrom = hwndOrig; 
        lpnmh->idFrom   = idOrig; 
        lpnmh->code     = TTN_GETDISPINFO; 
        return 0L; 
      } 
      break; 
    } 
 
    case WM_PAINT: 
      { 
        PCHSTRUCT     pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        PAINTSTRUCT   ps; 
        HDC           hDC; 
        POINT         pt = {0,0}; 
 
        if (!pCHS) return 0L; 
 
        hDC = BeginPaint(hwnd,&ps); 
        if (hDC) 
          ColHeaderPaintDC(hwnd,hDC,pt,TRUE,-1); 
        EndPaint(hwnd,&ps); 
        return 0L; 
      } 
 
    case WM_PRINTCLIENT: 
      { 
        HDC               hDC    = (HDC)wParam; 
        UINT              uFlags = (UINT)lParam; 
        POINT             pt = {0,0}; 
 
        if (hDC) 
        { 
          if (!((!IsWindowVisible(hwnd)) && (uFlags & PRF_CHECKVISIBLE))) 
            ColHeaderPaintDC(hwnd,hDC,pt,uFlags & PRF_ERASEBKGND ? TRUE : FALSE,-1); 
          return TRUE; 
        } 
        return FALSE; 
      } 
 
    case CHM_SETLEFTMARGIN: 
      { 
        PCHSTRUCT     pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
        SIZE          si; 
 
        if (pCHS) 
        { 
          pCHS->iLeftMargin = (int)wParam; 
          if (GetItemSize(hwnd,pCHS,&si,-1)) 
            SetWindowPos(hwnd,NULL,0,0,si.cx,si.cy,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); 
          return TRUE; 
        } 
        return FALSE; 
      } 
 
    default: 
      break; 
  } 
  return DefWindowProc(hwnd,uMsg,wParam,lParam); 
} 
 
static void APIPRIVATE AlphaBlendHeaderBitmap ( HDC hDC, HDC hDCMem, HBITMAP hBitmap, LPRECT lpRC, int iBmpWidth, int iBmpHeight ) 
{ 
  BLENDFUNCTION           bf; 
  HBITMAP                 hOldBitmap; 
 
  bf.BlendOp             = AC_SRC_OVER; 
  bf.BlendFlags          = 0; 
  bf.SourceConstantAlpha = 255; 
  bf.AlphaFormat         = AC_SRC_ALPHA; 
 
  hOldBitmap = SelectObject(hDCMem,hBitmap); 
 
  AlphaBlend(hDC,lpRC->left,lpRC->top, 
                 2, 
                 lpRC->bottom-lpRC->top, 
             hDCMem, 
                 0, 
                 0, 
                 2, 
                 iBmpHeight,bf); 
 
  AlphaBlend(hDC,lpRC->right-2,lpRC->top, 
                 2, 
                 lpRC->bottom-lpRC->top, 
             hDCMem, 
                 iBmpWidth-2, 
                 0, 
                 2, 
                 iBmpHeight,bf); 
 
  AlphaBlend(hDC,lpRC->left+2,lpRC->top, 
                 lpRC->right-lpRC->left-4, 
                 lpRC->bottom-lpRC->top, 
             hDCMem, 
                 2, 
                 0, 
                 iBmpWidth-4, 
                 iBmpHeight,bf); 
 
  SelectObject(hDCMem,hOldBitmap); 
} 
 
void APIENTRY ColHeaderPaintDC ( HWND hwnd, HDC hDC, POINT ptOffset, BOOL bPaintBackground, int iCtrlWidth ) 
{ 
  PCHSTRUCT     pCHS = (PCHSTRUCT)GetWindowLong(hwnd,GWL_USERDATA); 
  CHSTRUCT      CHSSave; 
  HDC           hDCMem; 
  TCHAR         szText[256]; 
  HGDIOBJ       hOldFont,hOldBitmap; 
  int           iOldColor,iOldBkMode,dy,idx,iArrWidth,iArrHeight; 
  RECT          rcText,rcClient; 
  LONG          lStyle   = GetWindowLong(hwnd,GWL_STYLE); 
  LONG          lExStyle = GetWindowLong(hwnd,GWL_EXSTYLE); 
  UINT          uDTStyle = 0; 
  UINT          uAlign; 
  BLENDFUNCTION bf; 
  HBITMAP      *phBitmap; 
  HBRUSH        hBrush; 
  HBITMAP       hBufferBitmap,hOldBufferBitmap; 
  HDC           hBufferDC; 
  HPEN          hOldPen; 
 
  if (!pCHS) return; 
 
  if (iCtrlWidth!=-1) 
  { 
    SIZE si; 
    memcpy(&CHSSave,pCHS,sizeof(CHSTRUCT)); 
    GetItemSize(hwnd,pCHS,&si,iCtrlWidth); 
    rcClient.left   = rcClient.top = 0; 
    rcClient.right  = si.cx; 
    rcClient.bottom = si.cy; 
  } 
  else 
    GetClientRect(hwnd,&rcClient); 
 
  bf.BlendOp             = AC_SRC_OVER; 
  bf.BlendFlags          = 0; 
  bf.SourceConstantAlpha = 255; 
  bf.AlphaFormat         = AC_SRC_ALPHA; 
 
  uAlign = pCHS->chf.uAlign; 
  if (lExStyle & WS_EX_RIGHT) 
  { 
    if (uAlign==CH_LEFT) uAlign=CH_RIGHT; 
    else 
    if (uAlign==CH_RIGHT) uAlign=CH_LEFT; 
  } 
 
  hBufferBitmap    = CreateCompatibleBitmap(hDC,rcClient.right,rcClient.bottom); 
  if (!hBufferBitmap) return; 
  hBufferDC        = CreateCompatibleDC(hDC); 
  if (!hBufferDC) 
  { 
    DeleteObject(hBufferBitmap); 
    return; 
  } 
  hOldBufferBitmap = SelectObject(hBufferDC,hBufferBitmap); 
 
  if (bPaintBackground) 
  { 
    hBrush = (HBRUSH)SendMessage(GetParent(hwnd),WM_CTLCOLORSTATIC,(WPARAM)hBufferDC,(LPARAM)hwnd); 
    if (((ULONG)(hBrush))>1) 
      FillRect(hBufferDC,&rcClient,hBrush); 
  } 
  else 
    BitBlt(hBufferDC,0,0,rcClient.right,rcClient.bottom,hDC,ptOffset.x,ptOffset.y,SRCCOPY); 
 
  hDCMem = CreateCompatibleDC(hDC); 
  switch(pCHS->iState) 
  { 
    case ITEMSTATE_COLD: 
      hOldFont  = SelectObject(hBufferDC,pCHS->hFontNormal); 
      iOldColor = SetTextColor(hBufferDC,pCHS->chf.crNormal); 
      break; 
    case ITEMSTATE_PRESSED: 
      hOldFont  = SelectObject(hBufferDC,pCHS->hFontHot); 
      iOldColor = SetTextColor(hBufferDC,pCHS->chf.crHot); 
      break; 
    case ITEMSTATE_HOT: 
      hOldFont  = SelectObject(hBufferDC,pCHS->hFontHot); 
      iOldColor = SetTextColor(hBufferDC,pCHS->chf.crHot); 
      break; 
    default: 
      hOldFont  = SelectObject(hBufferDC,pCHS->hFontNormal); 
      iOldColor = SetTextColor(hBufferDC,GetSysColor(COLOR_GRAYTEXT)); 
      break; 
  } 
  iOldBkMode = SetBkMode(hBufferDC,TRANSPARENT); 
 
  if (lStyle & CHS_PANEHEADER) 
  { 
    if (lStyle & CHS_SPECIALGROUP) 
    { 
      if (g_sEBI.bPreXP) 
      { 
        FillRect(hBufferDC,&pCHS->rcBackground,GetSysColorBrush(COLOR_HIGHLIGHT)); 
      } 
      else 
      { 
        AlphaBlendHeaderBitmap(hBufferDC,hDCMem,g_sEBI.headerspecial.hAlphaBmpListHeader, 
                               &pCHS->rcBackground, 
                               g_sEBI.headerspecial.iHeaderBmpWidth, 
                               g_sEBI.headerspecial.iHeaderBmpHeight); 
      } 
    } 
    else 
    { 
      if (g_sEBI.bPreXP) 
      { 
        FillRect(hBufferDC,&pCHS->rcBackground,GetSysColorBrush(COLOR_3DFACE)); 
      } 
      else 
      { 
        AlphaBlendHeaderBitmap(hBufferDC,hDCMem,g_sEBI.headernormal.hAlphaBmpListHeader, 
                               &pCHS->rcBackground, 
                               g_sEBI.headernormal.iHeaderBmpWidth, 
                               g_sEBI.headernormal.iHeaderBmpHeight); 
      } 
    } 
  } 
 
  if (lStyle & CHS_PANEHEADER) 
  { 
    if (lStyle & CHS_SPECIALGROUP)  // special pane header 
    { 
      iArrWidth   = g_sEBI.headerspecial.iBmpArrowWidth; 
      iArrHeight  = g_sEBI.headerspecial.iBmpArrowHeight; 
      phBitmap    = pCHS->bExpanded ? g_sEBI.headerspecial.hAlphaBmpArrowUp : g_sEBI.headerspecial.hAlphaBmpArrowDn; 
    } 
    else  // normal pane header 
    { 
      iArrWidth   = g_sEBI.headernormal.iBmpArrowWidth; 
      iArrHeight  = g_sEBI.headernormal.iBmpArrowHeight; 
      phBitmap    = pCHS->bExpanded ? g_sEBI.headernormal.hAlphaBmpArrowUp : g_sEBI.headernormal.hAlphaBmpArrowDn; 
    } 
  } 
  else  // group header 
  { 
    if (g_sEBI.bPreXP) 
    { 
      iArrWidth  = g_sEBI.iBmpPreXPArrowWidth; 
      iArrHeight = g_sEBI.iBmpPreXPArrowHeight; 
      phBitmap   = pCHS->bExpanded ? g_sEBI.hAlphaPreXPBmpArrowUp : g_sEBI.hAlphaPreXPBmpArrowDn; 
    } 
    else 
    { 
      iArrWidth   = g_sEBI.headernormal.iBmpArrowWidth; 
      iArrHeight  = g_sEBI.headernormal.iBmpArrowHeight; 
      phBitmap    = pCHS->bExpanded ? g_sEBI.headernormal.hAlphaBmpArrowUp : g_sEBI.headernormal.hAlphaBmpArrowDn; 
    } 
  } 
 
  dy = 0; 
  switch(pCHS->iState) 
  { 
    case ITEMSTATE_COLD: 
      idx = 0; 
      break; 
    case ITEMSTATE_PRESSED: 
      idx = 2; 
      if (phBitmap[idx]==NULL) 
      { 
        idx = 1; 
//        dy  = 1; 
      } 
      break; 
    case ITEMSTATE_HOT: 
      idx = 1; 
      break; 
    default: 
      idx = 0; 
      break; 
  } 
 
  hOldBitmap = SelectObject(hDCMem,phBitmap[idx]); 
  AlphaBlend(hBufferDC,pCHS->rcButton.left, 
                       pCHS->rcButton.top+dy, 
                       iArrWidth, 
                       iArrHeight, 
             hDCMem, 
                       0, 
                       0, 
                       iArrWidth, 
                       iArrHeight, 
                       bf); 
  SelectObject(hDCMem,hOldBitmap); 
 
  if ((g_sEBI.bPreXP) && (lStyle & CHS_PANEHEADER)) 
  { 
    if (pCHS->iState==ITEMSTATE_HOT) 
    { 
      hOldPen=SelectObject(hBufferDC,pCHS->hLightPen); 
      MoveToEx(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.bottom+dy-1,NULL); 
      LineTo(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.top+dy); 
      LineTo(hBufferDC,pCHS->rcButton.right,pCHS->rcButton.top+dy); 
      SelectObject(hBufferDC,hOldPen); 
 
      hOldPen=SelectObject(hBufferDC,pCHS->hShadowPen); 
      MoveToEx(hBufferDC,pCHS->rcButton.right-1,pCHS->rcButton.top+dy,NULL); 
      LineTo(hBufferDC,pCHS->rcButton.right-1,pCHS->rcButton.bottom+dy-1); 
      LineTo(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.bottom+dy-1); 
      SelectObject(hBufferDC,hOldPen); 
    } 
    else 
    if (pCHS->iState==ITEMSTATE_PRESSED) 
    { 
      hOldPen=SelectObject(hBufferDC,pCHS->hShadowPen); 
      MoveToEx(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.bottom+dy-1,NULL); 
      LineTo(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.top+dy); 
      LineTo(hBufferDC,pCHS->rcButton.right,pCHS->rcButton.top+dy); 
      SelectObject(hBufferDC,hOldPen); 
 
      hOldPen=SelectObject(hBufferDC,pCHS->hLightPen); 
      MoveToEx(hBufferDC,pCHS->rcButton.right-1,pCHS->rcButton.top+dy,NULL); 
      LineTo(hBufferDC,pCHS->rcButton.right-1,pCHS->rcButton.bottom+dy-1); 
      LineTo(hBufferDC,pCHS->rcButton.left,pCHS->rcButton.bottom+dy-1); 
      SelectObject(hBufferDC,hOldPen); 
    } 
  } 
 
  if ((lStyle & CHS_PANEHEADER) && (pCHS->chf.hIList)) 
  { 
    ImageList_Draw(pCHS->chf.hIList,pCHS->chf.iIIdx,hBufferDC, 
                   pCHS->rcIcon.left,pCHS->rcIcon.top,ILD_TRANSPARENT); 
  } 
 
  szText[0]=0x00; 
  GetWindowText(hwnd,szText,256); 
 
  memcpy(&rcText,&pCHS->rcText,sizeof(RECT)); 
 
  if (lStyle & CHS_FOCUSRECT) 
  { 
    if (pCHS->bFocus) 
      DrawFocusRect(hBufferDC,&rcText); 
    rcText.left++; 
    rcText.right--; 
    rcText.top++; 
    rcText.bottom--; 
  } 
 
  if (lStyle & CHS_WORDBREAK)         // multiline, use current control width 
  { 
    if (pCHS->bMultiLine) 
      uDTStyle = DT_EXTERNALLEADING|DT_WORDBREAK; 
    else 
      uDTStyle = DT_SINGLELINE|DT_NOCLIP; 
  } 
  else 
  { 
    if (lStyle & CHS_END_ELLIPSIS)    // singleline, use current control width 
    { 
      uDTStyle = DT_END_ELLIPSIS|DT_SINGLELINE; 
    } 
    else                              // singleline, ignore current control width 
    { 
       uDTStyle = DT_SINGLELINE|DT_NOCLIP; 
    } 
  } 
 
  switch(pCHS->chf.uAlign) 
  { 
    case CH_CENTER: 
      uDTStyle |= DT_CENTER; 
      break; 
    case CH_RIGHT: 
       uDTStyle |= DT_RIGHT; 
       break; 
    default: 
       uDTStyle |= DT_LEFT; 
       break; 
  } 
  if (lExStyle & WS_EX_RTLREADING) uDTStyle |= DT_RTLREADING; 
 
  DrawTextEx(hBufferDC,szText,lstrlen(szText),&rcText,uDTStyle,NULL); 
 
  SetBkMode(hBufferDC,iOldBkMode); 
  SetTextColor(hBufferDC,iOldColor); 
  SelectObject(hBufferDC,hOldFont); 
  if (hDCMem) DeleteDC(hDCMem); 
 
  BitBlt(hDC,ptOffset.x,ptOffset.y,rcClient.right,rcClient.bottom,hBufferDC,0,0,SRCCOPY); 
  SelectObject(hBufferDC,hOldBufferBitmap); 
  DeleteDC(hBufferDC); 
  DeleteObject(hBufferBitmap); 
 
  if (iCtrlWidth!=-1) 
    memcpy(pCHS,&CHSSave,sizeof(CHSTRUCT)); 
}