Exemple #1
0
INT LBPage(
    PLBIV plb,
    INT startItem,
    BOOL fPageForwardDirection)
{
    INT     i;
    INT height;
    RECT    rc;

    if (plb->cMac == 1)
        return(0);
    
    _GetClientRect(plb->spwnd, &rc);
    height = rc.bottom;
    i = startItem;

    if (fPageForwardDirection) {
        while ((height >= 0) && (i < plb->cMac))
            height -= LBGetVariableHeightItemHeight(plb, i++);

        return((height >= 0) ? plb->cMac - 1 : max(i - 2, startItem + 1));
    } else {
        while ((height >= 0) && (i >= 0))
            height -= LBGetVariableHeightItemHeight(plb, i--);

        return((height >= 0) ? 0 : min(i + 2, startItem - 1));
    }

}
void CCandidateWindow::_OnLButtonDown(POINT pt)
{
    RECT rcWindow = {0, 0, 0, 0};;
    _GetClientRect(&rcWindow);

    int cyLine = _cyRow;
    
    UINT index = 0;
    int currentPage = _CandidateIndexToPageNumber(_currentSelection);

    // Hit test on list items
    index =  _PageNumberToCandidateIndex(currentPage);

    for (UINT pageCount = 0; (index < _candidateList.size()) && (pageCount < _numCandidatesPerPage); index++, pageCount++)
    {
        RECT rc = {0, 0, 0, 0};

        rc.left = rcWindow.left;
        rc.right = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;
        rc.top = rcWindow.top + (pageCount * cyLine);
        rc.bottom = rcWindow.top + ((pageCount + 1) * cyLine);

        if (PtInRect(&rc, pt) && _pfnCallback)
        {
            SetCursor(LoadCursor(NULL, IDC_HAND));
            _currentSelection = index;
            _pfnCallback(_pObj, CAND_ITEM_SELECT);
            return;
        }
    }
	
    SetCursor(LoadCursor(NULL, IDC_ARROW));
}
void CCandidateWindow::_OnMouseMove(POINT pt)
{
    RECT rcWindow = {0, 0, 0, 0};

    _GetClientRect(&rcWindow);

    RECT rc = {0, 0, 0, 0};

    rc.left   = rcWindow.left;
    rc.right  = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;

    rc.top    = rcWindow.top;
    rc.bottom = rcWindow.bottom;

    if (PtInRect(&rc, pt))
    {
        SetCursor(LoadCursor(NULL, IDC_HAND));
        return;
    }

    SetCursor(LoadCursor(NULL, IDC_ARROW));

    if (_pVScrollBarWnd)
    {
        _pVScrollBarWnd->_GetClientRect(&rc);
        MapWindowPoints(_GetWnd(), _pVScrollBarWnd->_GetWnd(), &pt, 1);

        if (PtInRect(&rc, pt))
        {
            _pVScrollBarWnd->_OnMouseMove(pt);
        }
    }
}
void CScrollButtonWindow::_OnTimer()
{
    POINT pt = {0, 0};
    CScrollBarWindow* pParent = (CScrollBarWindow*)_GetParent();    // more secure w/ dynamic_cast
    if (pParent == nullptr)
    {
        return;
    }

    // start another faster timer
    _StartTimer(_GetScrollSpeed());

    GetCursorPos(&pt);
    MapWindowPoints(HWND_DESKTOP, pParent->_GetWnd(), &pt, 1);

    RECT rc = {0, 0, 0, 0};

    _GetClientRect(&rc);

    if (PtInRect(&rc, pt))
    {
        switch (subTypeOfControl)
        {
        case DFCS_SCROLLDOWN:
            _NotifyCommand(WM_VSCROLL, SB_LINEDOWN, 0);
            pParent->_ShiftLine(+1, FALSE);
            break;
        case DFCS_SCROLLUP:
            _NotifyCommand(WM_VSCROLL, SB_LINEUP, 0);
            pParent->_ShiftLine(-1, FALSE);
            break;
        }
    }
}
void CScrollButtonWindow::_OnPaint(_In_ HDC dcHandle, _In_ PAINTSTRUCT *pps)
{
    pps;

    RECT rc = {0, 0, 0, 0};

    _GetClientRect(&rc);

    DrawFrameControl(dcHandle, &rc, DFC_SCROLL, subTypeOfControl | typeOfControl | (!_IsEnabled() ? DFCS_INACTIVE : 0));
}
Exemple #6
0
void GetRealClientRect(
    PWND   pwnd,
    LPRECT prc,
    UINT   uFlags)
{
    if (GETFNID(pwnd) == FNID_DESKTOP) {

        *prc = (uFlags & GRC_FULLSCREEN) ? pwnd->rcWindow : gpsi->rcWork;

    } else {
        _GetClientRect(pwnd, prc);
        if (uFlags & GRC_SCROLLS) {
            if (TestWF(pwnd, WFHPRESENT))
                prc->bottom += SYSMET(CYHSCROLL);
            if (TestWF(pwnd, WFVPRESENT))
                prc->right += SYSMET(CXVSCROLL);
        }
    }

    if (uFlags & GRC_MINWNDS) {
        switch (SYSMET(ARRANGE) & ~ARW_HIDE) {
            case ARW_TOPLEFT | ARW_RIGHT:
            case ARW_TOPRIGHT | ARW_LEFT:
                //
                // Leave space on top for one row of min windows
                //
                prc->top += SYSMET(CYMINSPACING);
                break;

            case ARW_TOPLEFT | ARW_DOWN:
            case ARW_BOTTOMLEFT | ARW_UP:
                //
                // Leave space on left for one column of min windows
                //
                prc->left += SYSMET(CXMINSPACING);
                break;

            case ARW_TOPRIGHT | ARW_DOWN:
            case ARW_BOTTOMRIGHT | ARW_UP:
                //
                // Leave space on right for one column of min windows
                //
                prc->right -= SYSMET(CXMINSPACING);
                break;

            case ARW_BOTTOMLEFT | ARW_RIGHT:
            case ARW_BOTTOMRIGHT | ARW_LEFT:
                //
                // Leave space on bottom for one row of min windows
                //
                prc->bottom -= SYSMET(CYMINSPACING);
                break;
        }
    }
}
Exemple #7
0
//----获得窗口客户矩形区---------------------------------------------------------
//描述: 获得窗口客户矩形区,矩形为客户坐标.
//参数:hwnd:窗口句柄
//      prc:用于保存矩形数据的指针.
//返回:TRUE:成功; FALSE:失败
//------------------------------------------------------------------------------
BOOL    GetClientRect(HWND hwnd,RECT *prc)
{
    if(NULL!=prc)
    if(HWND_Lock(hwnd))
    {
        _GetClientRect(hwnd,prc);
        HWND_Unlock(hwnd);
        return TRUE;
    }
    return FALSE;
}
void CCandidateWindow::_OnLButtonDown(POINT pt)
{
    RECT rcWindow = {0, 0, 0, 0};;
    _GetClientRect(&rcWindow);

    int cyLine = _cyRow;
    
    UINT candidateListPageCnt = _pIndexRange->Count();
    UINT index = 0;
    int currentPage = 0;

    if (FAILED(_GetCurrentPage(&currentPage)))
    {
        return;
    }

    // Hit test on list items
    index = *_PageIndex.GetAt(currentPage);

    for (UINT pageCount = 0; (index < _candidateList.Count()) && (pageCount < candidateListPageCnt); index++, pageCount++)
    {
        RECT rc = {0, 0, 0, 0};

        rc.left = rcWindow.left;
        rc.right = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;
        rc.top = rcWindow.top + (pageCount * cyLine);
        rc.bottom = rcWindow.top + ((pageCount + 1) * cyLine);

        if (PtInRect(&rc, pt) && _pfnCallback)
        {
            SetCursor(LoadCursor(NULL, IDC_HAND));
            _currentSelection = index;
            _pfnCallback(_pObj, CAND_ITEM_SELECT);
            return;
        }
    }

    SetCursor(LoadCursor(NULL, IDC_ARROW));

    if (_pVScrollBarWnd)
    {
        RECT rc = {0, 0, 0, 0};

        _pVScrollBarWnd->_GetClientRect(&rc);
        MapWindowPoints(_GetWnd(), _pVScrollBarWnd->_GetWnd(), &pt, 1);

        if (PtInRect(&rc, pt))
        {
            _pVScrollBarWnd->_OnLButtonDown(pt);
        }
    }
}
void CCandidateWindow::_ResizeWindow()
{
    SIZE size = {0, 0};

    _cxTitle = max(_cxTitle, size.cx + 2 * GetSystemMetrics(SM_CXFRAME));

    CBaseWindow::_Resize(0, 0, _cxTitle, _cyRow * this->_numCandidatesPerPage + _cyHelpText );

    RECT rcCandRect = {0, 0, 0, 0};
    _GetClientRect(&rcCandRect);

    int letf = rcCandRect.right - GetSystemMetrics(SM_CXVSCROLL) * 2 - CANDWND_BORDER_WIDTH;
    int top = rcCandRect.top + CANDWND_BORDER_WIDTH;
    int width = GetSystemMetrics(SM_CXVSCROLL) * 2;
    int height = rcCandRect.bottom - rcCandRect.top - CANDWND_BORDER_WIDTH * 2;
}
Exemple #10
0
INT CItemInWindowVarOwnerDraw(
    PLBIV plb,
    BOOL fPartial)
{
    RECT rect;
    INT sItem;
    INT clientbottom;

    _GetClientRect(plb->spwnd, (LPRECT)&rect);
    clientbottom = rect.bottom;

    /*
     * Find the number of var height ownerdraw items which are visible starting
     * from plb->iTop.
     */
    for (sItem = plb->iTop; sItem < plb->cMac; sItem++) {

        /*
         * Find out if the item is visible or not
         */
        if (!LBGetItemRect(plb, sItem, (LPRECT)&rect)) {

            /*
             * This is the first item which is completely invisible, so return
             * how many items are visible.
             */
            return (sItem - plb->iTop);
        }

        if (!fPartial && rect.bottom > clientbottom) {

            /*
             * If we only want fully visible items, then if this item is
             * visible, we check if the bottom of the item is below the client
             * rect, so we return how many are fully visible.
             */
            return (sItem - plb->iTop - 1);
        }
    }

    /*
     * All the items are visible
     */
    return (plb->cMac - plb->iTop);
}
BOOL CScrollBarWindow::_GetBtnDnRect(_Out_ RECT *prc)
{
    RECT rc = {0, 0, 0, 0};

    _GetClientRect(&rc);

    if (prc == nullptr)
    {
        return FALSE;
    }

    prc->left = rc.left;
    prc->top = rc.bottom - min(_sizeOfScrollBtn.cy, (rc.bottom - rc.top)/2);
    prc->right = rc.right;
    prc->bottom = rc.bottom;

    return TRUE;
}
void CCandidateWindow::_ResizeWindow()
{
    SIZE size = {0, 0};

    _cxTitle = max(_cxTitle, size.cx + 2 * GetSystemMetrics(SM_CXFRAME));

    int candidateListPageCnt = _pIndexRange->Count();
    CBaseWindow::_Resize(0, 0, _cxTitle, _cyRow * candidateListPageCnt);

    RECT rcCandRect = {0, 0, 0, 0};
    _GetClientRect(&rcCandRect);

    int letf = rcCandRect.right - GetSystemMetrics(SM_CXVSCROLL) * 2 - CANDWND_BORDER_WIDTH;
    int top = rcCandRect.top + CANDWND_BORDER_WIDTH;
    int width = GetSystemMetrics(SM_CXVSCROLL) * 2;
    int height = rcCandRect.bottom - rcCandRect.top - CANDWND_BORDER_WIDTH * 2;

    _pVScrollBarWnd->_Resize(letf, top, width, height);
}
void CCandidateWindow::_OnMouseMove(POINT pt)
{
    RECT rcWindow = {0, 0, 0, 0};

    _GetClientRect(&rcWindow);

    RECT rc = {0, 0, 0, 0};

    rc.left   = rcWindow.left;
    rc.right  = rcWindow.right - GetSystemMetrics(SM_CXVSCROLL) * 2;

    rc.top    = rcWindow.top;
    rc.bottom = rcWindow.bottom;

    if (PtInRect(&rc, pt))
    {
        SetCursor(LoadCursor(NULL, IDC_HAND));
        return;
    }

    SetCursor(LoadCursor(NULL, IDC_ARROW));
}
void CScrollBarWindow::_GetScrollArea(_Out_ RECT *prc)
{
    RECT rcBtnUp = {0, 0, 0, 0};
    RECT rcBtnDn = {0, 0, 0, 0};

    _GetBtnUpRect(&rcBtnUp);
    _GetBtnDnRect(&rcBtnDn);

    RECT rc = {0, 0, 0, 0};

    _GetClientRect(&rc);

    if (prc == nullptr)
    {
        return;
    }

    prc->left = rc.left;
    prc->top = rc.top + (rcBtnUp.bottom - rcBtnUp.top);
    prc->right = rc.right;
    prc->bottom = rc.bottom - (rcBtnDn.bottom - rcBtnDn.top);
}
Exemple #15
0
INT LBCalcVarITopScrollAmt(
    PLBIV plb,
    INT iTopOld,
    INT iTopNew)
{
    RECT rc;
    RECT rcClient;

    _GetClientRect(plb->spwnd, (LPRECT)&rcClient);

    /*
     * Just optimize redrawing when move +/- 1 item.  We will redraw all items
     * if moving more than 1 item ahead or back.  This is good enough for now.
     */
    if (iTopOld + 1 == iTopNew) {

        /*
         * We are scrolling the current iTop up off the top off the listbox so
         * return a negative number.
         */
        LBGetItemRect(plb, iTopOld, (LPRECT)&rc);
        return (rcClient.top - rc.bottom);
    }

    if (iTopOld - 1 == iTopNew) {

        /*
         * We are scrolling the current iTop down and the previous item is
         * becomming the new iTop so return a positive number.
         */
        LBGetItemRect(plb, iTopNew, (LPRECT)&rc);
        return -rc.top;
    }

    return rcClient.bottom - rcClient.top;
}
Exemple #16
0
void duTreeCtrl::DrawObject(HDC hDC)
{
	duRect rcTreeCtrl;
	Plugin_GetRect(this, &rcTreeCtrl);
	rcTreeCtrl.OffsetRect(-rcTreeCtrl.left, -rcTreeCtrl.top);

	BITMAPINFO bmInfo;
	BYTE *pBits;

	HDC hMemDC = ::CreateCompatibleDC(hDC);
	InitBitmapInfo(&bmInfo, rcTreeCtrl.Width(), rcTreeCtrl.Height());
	HBITMAP hBmp = ::CreateDIBSection(hDC, &bmInfo, DIB_RGB_COLORS,(void**)&pBits, 0, 0);
	HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBmp);

	BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
	::AlphaBlend(hMemDC, 0, 0, rcTreeCtrl.Width(), rcTreeCtrl.Height(), hDC, 0, 0, rcTreeCtrl.Width(), rcTreeCtrl.Height(), bf);


	duStyleGroup *pStyleGroup = (duStyleGroup *)GetResObj(GetStyle(), DU_RES_STYLEGROUP);
	if (pStyleGroup)
		pStyleGroup->Draw(hMemDC, &rcTreeCtrl, GetState(), NULL, GetAlpha());
	
	int nOffsetY = 0;
	TreeCtrlItem *pFirstVisible = GetFirstVisibleItem(nOffsetY);
	if (pFirstVisible == NULL || pFirstVisible == m_pRoot)
		return;
		
	duRect rcClient = _GetClientRect();
	
	POINT ptView = GetViewPoint();
	duFont *pFont = (duFont *)GetResObj(m_szFont, DU_RES_FONT);
	
	duSize sizeView;
	GetViewSize(&sizeView);
	
	int nDrawHeight = -nOffsetY;
	TreeCtrlItem *pItem = pFirstVisible;
	while (pItem)
	{
		duRect rcItem;
		
		rcItem.left   = -ptView.x;
		rcItem.right  = rcClient.right;
		rcItem.top    = nDrawHeight;
		rcItem.bottom = rcItem.top + m_nItemHeight;

		UINT uItemState = DU_STATE_NORMAL;
		if (pItem == m_pHot)
			uItemState = DU_STATE_OVER;
		
		if (pItem == m_pSelect)
			uItemState = DU_STATE_PRESS;
		
		DrawByStyle(this, m_szItemStyle, hMemDC, &rcItem, uItemState, NULL, GetAlpha());

		// draw indent[-+]
		int nLeft = (pItem->nLevel - 1) * m_nIndentWidth;
		duRect rcIndent = CalcVCenterRect(rcItem, nLeft, m_nIndentWidth, m_nIndentHeight);
		if (ItemHasChildren(pItem))
		{
			UINT nIndentState = pItem->fExpand ? DU_STATE_NORMAL : DU_STATE_CHECKED;
			DrawByStyle(this, m_szIndentStyle, hMemDC, &rcIndent, nIndentState, NULL, GetAlpha());
		}

		// draw icon
		nLeft += (m_nIndentWidth + m_nIndentIconSpace);
		duRect rcIcon = CalcVCenterRect(rcItem, nLeft, m_nIconWidth, m_nIconHeight);
		duImage *pIcon = (duImage *)GetResObj(pItem->strImage.c_str(), DU_RES_IMAGE);
		if (pIcon)
			DrawNormal(hMemDC, rcIcon.left, rcIcon.top, rcIcon.Width(), rcIcon.Height(), pIcon, 0, 0, GetAlpha());

		// draw text
		duRect rcText;
		nLeft += (m_nIconWidth + m_nIconTextSpace);
		rcText = rcItem;
		rcText.left = rcItem.left + nLeft;
		if (pItem->strText.length() > 0)
			DrawText32Bpp(hMemDC, pFont, m_clrText, pItem->strText.c_str(), pItem->strText.length(), &rcText, DT_LEFT|DT_VCENTER|DT_SINGLELINE, GetAlpha());

		if (nDrawHeight - nOffsetY > rcTreeCtrl.Height())
			break;

		nDrawHeight += m_nItemHeight;
		pItem = GetNextVisibleItem(pItem);
	}

	::AlphaBlend(hDC, 0, 0, rcTreeCtrl.Width(), rcTreeCtrl.Height(), hMemDC, 0, 0, rcTreeCtrl.Width(), rcTreeCtrl.Height(), bf);

	::SelectObject(hMemDC, hOldBitmap);
	::DeleteObject(hBmp);
	::DeleteDC(hMemDC);
}
Exemple #17
0
LRESULT APIENTRY ListBoxWndProcWorker(
    PWND pwnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam,
    DWORD fAnsi)
{
    HWND hwnd = HWq(pwnd);
    PAINTSTRUCT ps;
    HDC         hdc;
    LPRECT      lprc;
    PLBIV plb;    /* List Box Instance Variable */
    INT iSel;     /* Index of selected item */
    DWORD dw;
    TL tlpwndParent;
    UINT wFlags;
    LPWSTR lpwsz = NULL;
    LRESULT lReturn = 0;
    static BOOL fInit = TRUE;

    CheckLock(pwnd);

    VALIDATECLASSANDSIZE(pwnd, FNID_LISTBOX);
    INITCONTROLLOOKASIDE(&ListboxLookaside, LBIV, spwnd, 4);

    /*
     * Get the plb for the given window now since we will use it a lot in
     * various handlers. This was stored using SetWindowLong(hwnd,0,plb)
     * when the listbox was first created (by INITCONTROLLOOKASIDE above)
     */
    plb = ((PLBWND)pwnd)->pLBIV;

    /*
     * Handle ANSI translations of input parameters
     */
    if (fAnsi) {
        switch (message) {
        case LB_ADDSTRING:
        case LB_ADDSTRINGUPPER:
        case LB_ADDSTRINGLOWER:
        case LB_FINDSTRING:
        case LB_FINDSTRINGEXACT:
        case LB_INSERTSTRING:
        case LB_INSERTSTRINGUPPER:
        case LB_INSERTSTRINGLOWER:
        case LB_SELECTSTRING:
            if (!plb->fHasStrings) {
                break;
            }
            // Fall through...
        case LB_ADDFILE:
        case LB_DIR:
            if (lParam) {
                if (!MBToWCS((LPSTR)lParam, -1, &lpwsz, -1, TRUE))
                    return LB_ERR;
            }
            break;
        default:
            break;
        }
        if (lpwsz) {
            lParam = (LPARAM)lpwsz;
        }
    }

    switch (message) {

    case LB_GETTOPINDEX:        // Return index of top item displayed.
        return plb->iTop;

    case LB_SETTOPINDEX:
        if (wParam && ((INT)wParam < 0 || (INT)wParam >= plb->cMac)) {
            RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
            return LB_ERR;
        }
        if (plb->cMac) {
            xxxNewITop(plb, (INT)wParam);
        }
        break;

    case WM_STYLECHANGED:
        plb->fRtoLReading = (TestWF(pwnd, WEFRTLREADING) != 0);
        plb->fRightAlign  = (TestWF(pwnd, WEFRIGHT) != 0);
        xxxCheckRedraw(plb, FALSE, 0);
        break;

    case WM_WINDOWPOSCHANGED:

        /*
         * If we are in the middle of creation, ignore this
         * message because it will generate a WM_SIZE message.
         * See xxxLBCreate().
         */
        if (!plb->fIgnoreSizeMsg)
            goto CallDWP;
        break;

    case WM_SIZE:

        /*
         * If we are in the middle of creation, ignore size
         * messages.  See xxxLBCreate().
         */
        if (!plb->fIgnoreSizeMsg)
            xxxLBSize(plb, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
        break;

    case WM_ERASEBKGND:
        ThreadLock(plb->spwndParent, &tlpwndParent);
        FillWindow(HW(plb->spwndParent), hwnd, (HDC)wParam,
                (HBRUSH)CTLCOLOR_LISTBOX);
        ThreadUnlock(&tlpwndParent);
        return TRUE;

    case LB_RESETCONTENT:
        xxxLBResetContent(plb);
        break;

    case WM_TIMER:
        if (wParam == IDSYS_LBSEARCH) {
            plb->iTypeSearch = 0;
            NtUserKillTimer(hwnd, IDSYS_LBSEARCH);
            xxxInvertLBItem(plb, plb->iSel, TRUE);
            break;
        }

        message = WM_MOUSEMOVE;
        xxxTrackMouse(plb, message, plb->ptPrev);
        break;

        /*
         * Fall through
         */
    case WM_MOUSEMOVE:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_LBUTTONDBLCLK:
        {
            POINT pt;

            POINTSTOPOINT(pt, lParam);
            xxxTrackMouse(plb, message, pt);
        }
        break;

    case WM_MBUTTONDOWN:
        EnterReaderModeHelper(hwnd);
        break;

    case WM_CAPTURECHANGED:
            //
            // Note that this message should be handled only on unexpected
            // capture changes currently.
            //
        UserAssert(TestWF(pwnd, WFWIN40COMPAT));
        if (plb->fCaptured)
            xxxLBButtonUp(plb, LBUP_NOTIFY);
        break;

    case LBCB_STARTTRACK:
        //
        // Start tracking mouse moves in the listbox, setting capture
        //
        if (!plb->pcbox)
            break;

        plb->fCaptured = FALSE;
        if (wParam) {
            POINT pt;

            POINTSTOPOINT(pt, lParam);

            _ScreenToClient(pwnd, &pt);
            xxxTrackMouse(plb, WM_LBUTTONDOWN, pt);
        } else {
            NtUserSetCapture(hwnd);
            plb->fCaptured = TRUE;
            plb->iLastSelection = plb->iSel;
        }
        break;

    case LBCB_ENDTRACK:
        // Kill capture, tracking, etc.
        if (plb->fCaptured)
            xxxLBButtonUp(plb, LBUP_RELEASECAPTURE | (wParam ? LBUP_SELCHANGE :
                LBUP_RESETSELECTION));
        break;

    case WM_PRINTCLIENT:
        xxxLBPaint(plb, (HDC) wParam, NULL);
        break;

    case WM_PAINT:
        if (wParam) {
            hdc = (HDC) wParam;
            lprc = NULL;
        } else {
            hdc = NtUserBeginPaint(hwnd, &ps);
            lprc = &(ps.rcPaint);
        }

        if (IsLBoxVisible(plb))
            xxxLBPaint(plb, hdc, lprc);

        if (!wParam)
            NtUserEndPaint(hwnd, &ps);
        break;

    case WM_NCDESTROY:
    case WM_FINALDESTROY:
        xxxDestroyLBox(plb, pwnd);
        break;

    case WM_SETFOCUS:
// DISABLED in Win 3.1        xxxUpdateWindow(pwnd);
        CaretCreate(plb);
        xxxLBSetCaret(plb, TRUE);
        xxxNotifyOwner(plb, LBN_SETFOCUS);
        if (FWINABLE()) {
            if (_IsWindowVisible(pwnd)) {
                LBEvent(plb, EVENT_OBJECT_FOCUS, plb->iSelBase);
            }
        }
        break;

    case WM_KILLFOCUS:
        /*
         * Reset the wheel delta count.
         */
        gcWheelDelta = 0;

        xxxLBSetCaret(plb, FALSE);
        xxxCaretDestroy(plb);
        xxxNotifyOwner(plb, LBN_KILLFOCUS);
        if (plb->iTypeSearch) {
            plb->iTypeSearch = 0;
            NtUserKillTimer(hwnd, IDSYS_LBSEARCH);
        }
        if (plb->pszTypeSearch) {
            UserLocalFree(plb->pszTypeSearch);
            plb->pszTypeSearch = NULL;
        }
        break;

    case WM_MOUSEWHEEL:
        {
            int     cDetants;
            int     cPage;
            int     cLines;
            RECT    rc;
            int     windowWidth;
            int     cPos;

            /*
             * Don't handle zoom and datazoom.
             */
            if (wParam & (MK_SHIFT | MK_CONTROL)) {
                goto CallDWP;
            }

            lReturn = 1;
            gcWheelDelta -= (short) HIWORD(wParam);
            cDetants = gcWheelDelta / WHEEL_DELTA;
            if (    cDetants != 0 &&
                    gpsi->ucWheelScrollLines > 0 &&
                    (pwnd->style & (WS_VSCROLL | WS_HSCROLL))) {

                gcWheelDelta = gcWheelDelta % WHEEL_DELTA;

                if (pwnd->style & WS_VSCROLL) {
                    cPage = max(1, (plb->cItemFullMax - 1));
                    cLines = cDetants *
                            (int) min((UINT) cPage, gpsi->ucWheelScrollLines);

                    cPos = max(0, min(plb->iTop + cLines, plb->cMac - 1));
                    if (cPos != plb->iTop) {
                        xxxLBoxCtlScroll(plb, SB_THUMBPOSITION, cPos);
                        xxxLBoxCtlScroll(plb, SB_ENDSCROLL, 0);
                    }
                } else if (plb->fMultiColumn) {
                    cPage = max(1, plb->numberOfColumns);
                    cLines = cDetants * (int) min((UINT) cPage, gpsi->ucWheelScrollLines);
                    cPos = max(
                            0,
                            min((plb->iTop / plb->itemsPerColumn) + cLines,
                                plb->cMac - 1 - ((plb->cMac - 1) % plb->itemsPerColumn)));

                    if (cPos != plb->iTop) {
                        xxxLBoxCtlHScrollMultiColumn(plb, SB_THUMBPOSITION, cPos);
                        xxxLBoxCtlHScrollMultiColumn(plb, SB_ENDSCROLL, 0);
                    }
                } else {
                    _GetClientRect(plb->spwnd, &rc);
                    windowWidth = rc.right;
                    cPage = max(plb->cxChar, (windowWidth / 3) * 2) /
                            plb->cxChar;

                    cLines = cDetants *
                            (int) min((UINT) cPage, gpsi->ucWheelScrollLines);

                    cPos = max(
                            0,
                            min(plb->xOrigin + (cLines * plb->cxChar),
                                plb->maxWidth));

                    if (cPos != plb->xOrigin) {
                        xxxLBoxCtlHScroll(plb, SB_THUMBPOSITION, cPos);
                        xxxLBoxCtlHScroll(plb, SB_ENDSCROLL, 0);
                    }
                }
            }
        }
        break;

    case WM_VSCROLL:
        xxxLBoxCtlScroll(plb, LOWORD(wParam), HIWORD(wParam));
        break;

    case WM_HSCROLL:
        xxxLBoxCtlHScroll(plb, LOWORD(wParam), HIWORD(wParam));
        break;

    case WM_GETDLGCODE:
        return DLGC_WANTARROWS | DLGC_WANTCHARS;

    case WM_CREATE:
        return xxxLBCreate(plb, pwnd, (LPCREATESTRUCT) lParam);

    case WM_SETREDRAW:

        /*
         * If wParam is nonzero, the redraw flag is set
         * If wParam is zero, the flag is cleared
         */
        xxxLBSetRedraw(plb, (wParam != 0));
        break;

    case WM_ENABLE:
        xxxLBInvalidateRect(plb, NULL, !plb->OwnerDraw);
        break;

    case WM_SETFONT:
        xxxLBSetFont(plb, (HANDLE)wParam, LOWORD(lParam));
        break;

    case WM_GETFONT:
        return (LRESULT)plb->hFont;

    case WM_DRAGSELECT:
    case WM_DRAGLOOP:
    case WM_DRAGMOVE:
    case WM_DROPFILES:
        ThreadLock(plb->spwndParent, &tlpwndParent);
        lReturn = SendMessage(HW(plb->spwndParent), message, wParam, lParam);
        ThreadUnlock(&tlpwndParent);
        return lReturn;


    case WM_QUERYDROPOBJECT:
    case WM_DROPOBJECT:

        /*
         * fix up control data, then pass message to parent
         */
        LBDropObjectHandler(plb, (PDROPSTRUCT)lParam);
        ThreadLock(plb->spwndParent, &tlpwndParent);
        lReturn = SendMessage(HW(plb->spwndParent), message, wParam, lParam);
        ThreadUnlock(&tlpwndParent);
        return lReturn;

    case LB_GETITEMRECT:
        return LBGetItemRect(plb, (INT)wParam, (LPRECT)lParam);

    case LB_GETITEMDATA:
        return LBGetItemData(plb, (INT)wParam);  // wParam = item index

    case LB_SETITEMDATA:

        /*
         * wParam is item index
         */
        return LBSetItemData(plb, (INT)wParam, lParam);

    case LB_ADDSTRINGUPPER:
        wFlags = UPPERCASE | LBI_ADD;
        goto CallInsertItem;

    case LB_ADDSTRINGLOWER:
        wFlags = LOWERCASE | LBI_ADD;
        goto CallInsertItem;

    case LB_ADDSTRING:
        wFlags = LBI_ADD;
        goto CallInsertItem;

    case LB_INSERTSTRINGUPPER:
        wFlags = UPPERCASE;
        goto CallInsertItem;

    case LB_INSERTSTRINGLOWER:
        wFlags = LOWERCASE;
        goto CallInsertItem;

    case LB_INSERTSTRING:
        wFlags = 0;
CallInsertItem:
        lReturn = ((LRESULT) xxxLBInsertItem(plb, (LPWSTR) lParam, (int) wParam, wFlags));
        break;

    case LB_INITSTORAGE:
        return xxxLBInitStorage(plb, fAnsi, (INT)wParam, (INT)lParam);

    case LB_DELETESTRING:
        return xxxLBoxCtlDelete(plb, (INT)wParam);

    case LB_DIR:
        /*
         * wParam - Dos attribute value.
         * lParam - Points to a file specification string
         */
        lReturn = xxxLbDir(plb, (INT)wParam, (LPWSTR)lParam);
        break;

    case LB_ADDFILE:
        lReturn = xxxLbInsertFile(plb, (LPWSTR)lParam);
        break;

    case LB_SETSEL:
        return xxxLBSetSel(plb, (wParam != 0), (INT)lParam);

    case LB_SETCURSEL:
        /*
         * If window obscured, update so invert will work correctly
         */
// DISABLED in Win 3.1        xxxUpdateWindow(pwnd);
        return xxxLBSetCurSel(plb, (INT)wParam);

    case LB_GETSEL:
        if (wParam >= (UINT) plb->cMac)
                return((LRESULT) LB_ERR);

        return IsSelected(plb, (INT)wParam, SELONLY);

    case LB_GETCURSEL:
        if (plb->wMultiple == SINGLESEL) {
            return plb->iSel;
        }
        return plb->iSelBase;

    case LB_SELITEMRANGE:
        if (plb->wMultiple == SINGLESEL) {
            /*
             * Can't select a range if only single selections are enabled
             */
            RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SELITEMRANGE");
            return LB_ERR;
        }

        xxxLBSelRange(plb, LOWORD(lParam), HIWORD(lParam), (wParam != 0));
        break;

    case LB_SELITEMRANGEEX:
        if (plb->wMultiple == SINGLESEL) {
            /*
             * Can't select a range if only single selections are enabled
             */
            RIPERR0(ERROR_INVALID_LB_MESSAGE, RIP_VERBOSE,"LB_SELITEMRANGEEX:Can't select a range if only single selections are enabled");
            return LB_ERR;
        } else {
            BOOL fHighlight = ((DWORD)lParam > (DWORD)wParam);
            if (fHighlight == FALSE) {
                ULONG_PTR temp = lParam;
                lParam = wParam;
                wParam = temp;
            }
            xxxLBSelRange(plb, (INT)wParam, (INT)lParam, fHighlight);
        }
        break;

    case LB_GETTEXTLEN:
        if (lParam != 0) {
            RIPMSG1(RIP_WARNING, "LB_GETTEXTLEN with lParam = %lx\n", lParam);
        }
        lReturn = LBGetText(plb, TRUE, fAnsi, (INT)wParam, NULL);
        break;

    case LB_GETTEXT:
        lReturn = LBGetText(plb, FALSE, fAnsi, (INT)wParam, (LPWSTR)lParam);
        break;

    case LB_GETCOUNT:
        // Lotus Approach calls CallWndProc(ListWndProc, LB_GETCOUNT,...)
        // on a window that doesn't have a plb yet. So, we need to make
        // this check. Bug #6675 - 11/7/94 --
        if(plb)
            return((LRESULT) plb->cMac);
        else
            return(0);

    case LB_SETCOUNT:
        return xxxLBSetCount(plb, (INT)wParam);

    case LB_SELECTSTRING:
    case LB_FINDSTRING:
        iSel = xxxFindString(plb, (LPWSTR)lParam, (INT)wParam, PREFIX, TRUE);
        if (message == LB_FINDSTRING || iSel == LB_ERR) {
            lReturn = iSel;
        } else {
            lReturn = xxxLBSetCurSel(plb, iSel);
        }
        break;

    case LB_GETLOCALE:
        return plb->dwLocaleId;

    case LB_SETLOCALE:

        /*
         * Validate locale
         */
        wParam = ConvertDefaultLocale((LCID)wParam);
        if (!IsValidLocale((LCID)wParam, LCID_INSTALLED))
            return LB_ERR;

        dw = plb->dwLocaleId;
        plb->dwLocaleId = (DWORD)wParam;
        return dw;

    case WM_KEYDOWN:

        /*
         * IanJa: Use LOWORD() to get low 16-bits of wParam - this should
         * work for Win16 & Win32.  The value obtained is the virtual key
         */
        xxxLBoxCtlKeyInput(plb, message, LOWORD(wParam));
        break;

    case WM_CHAR:
        xxxLBoxCtlCharInput(plb, LOWORD(wParam), fAnsi);
        break;

    case LB_GETSELITEMS:
    case LB_GETSELCOUNT:

        /*
         * IanJa/Win32 should this be LPWORD now?
         */
        return LBoxGetSelItems(plb, (message == LB_GETSELCOUNT), (INT)wParam,
                (LPINT)lParam);

    case LB_SETTABSTOPS:

        /*
         * IanJa/Win32: Tabs given by array of INT for backwards compatability
         */
        return LBSetTabStops(plb, (INT)wParam, (LPINT)lParam);

    case LB_GETHORIZONTALEXTENT:

        /*
         * Return the max width of the listbox used for horizontal scrolling
         */
        return plb->maxWidth;

    case LB_SETHORIZONTALEXTENT:

        /*
         * Set the max width of the listbox used for horizontal scrolling
         */
        if (plb->maxWidth != (INT)wParam) {
            plb->maxWidth = (INT)wParam;

            /*
             * When horizontal extent is set, Show/hide the scroll bars.
             * NOTE: LBShowHideScrollBars() takes care if Redraw is OFF.
             * Fix for Bug #2477 -- 01/14/91 -- SANKAR --
             */
            xxxLBShowHideScrollBars(plb); //Try to show or hide scroll bars
            if (plb->fHorzBar && plb->fRightAlign && !(plb->fMultiColumn || plb->OwnerDraw)) {
                /*
                 * origin to right
                 */
                xxxLBoxCtlHScroll(plb, SB_BOTTOM, 0);
            }
        }
        break;    /* originally returned register ax (message) ! */

    case LB_SETCOLUMNWIDTH:

        /*
         * Set the width of a column in a multicolumn listbox
         */
        plb->cxColumn = (INT)wParam;
        LBCalcItemRowsAndColumns(plb);
        if (IsLBoxVisible(plb))
            NtUserInvalidateRect(hwnd, NULL, TRUE);
        xxxLBShowHideScrollBars(plb);
        break;

    case LB_SETANCHORINDEX:
        if ((INT)wParam >= plb->cMac) {
            RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SETANCHORINDEX");
            return LB_ERR;
        }
        plb->iMouseDown = (INT)wParam;
        plb->iLastMouseMove = (INT)wParam;
        xxxInsureVisible(plb, (int) wParam, (BOOL)(lParam != 0));
        break;

    case LB_GETANCHORINDEX:
        return plb->iMouseDown;

    case LB_SETCARETINDEX:
        if ( (plb->iSel == -1) || ((plb->wMultiple != SINGLESEL) &&
                    (plb->cMac > (INT)wParam))) {

            /*
             * Set's the iSelBase to the wParam
             * if lParam, then don't scroll if partially visible
             * else scroll into view if not fully visible
             */
            xxxInsureVisible(plb, (INT)wParam, (BOOL)LOWORD(lParam));
            xxxSetISelBase(plb, (INT)wParam);
            break;
        } else {
            if ((INT)wParam >= plb->cMac) {
                RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE,"Invalid index passed to LB_SETCARETINDEX");
            }
            return LB_ERR;
        }
        break;

    case LB_GETCARETINDEX:
        return plb->iSelBase;

    case LB_SETITEMHEIGHT:
    case LB_GETITEMHEIGHT:
        return LBGetSetItemHeightHandler(plb, message, (INT)wParam, LOWORD(lParam));
        break;

    case LB_FINDSTRINGEXACT:
        lReturn = xxxFindString(plb, (LPWSTR)lParam, (INT)wParam, EQ, TRUE);
        break;

    case LB_ITEMFROMPOINT: {
        POINT pt;
        BOOL bOutside;
        DWORD dwItem;

        POINTSTOPOINT(pt, lParam);
        bOutside = ISelFromPt(plb, pt, &dwItem);
        UserAssert(bOutside == 1 || bOutside == 0);
        return (LRESULT)MAKELONG(dwItem, bOutside);
    }

    case LBCB_CARETON:

        /*
         * Internal message for combo box support
         */
        CaretCreate(plb);
        // Set up the caret in the proper location for drop downs.
        plb->iSelBase = plb->iSel;
        xxxLBSetCaret(plb, TRUE);
        if (FWINABLE()) {
            if (_IsWindowVisible(pwnd)) {
                LBEvent(plb, EVENT_OBJECT_FOCUS, plb->iSelBase);
            }
        }
        return(plb->iSel);

    case LBCB_CARETOFF:

        /*
         * Internal message for combo box support
         */
        xxxLBSetCaret(plb, FALSE);
        xxxCaretDestroy(plb);
        break;

    case WM_NCCREATE:
        if ((pwnd->style & LBS_MULTICOLUMN) && (pwnd->style & WS_VSCROLL))
        {
            DWORD mask = WS_VSCROLL;
            DWORD flags = 0;
            if (!TestWF(pwnd, WFWIN40COMPAT)) {
                mask |= WS_HSCROLL;
                flags = WS_HSCROLL;
            }
            NtUserAlterWindowStyle(hwnd, mask, flags);
        }
        goto CallDWP;

     default:
CallDWP:
        return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
    }

    /*
     * Handle translation of ANSI output data and free buffer
     */
    if (lpwsz) {
        UserLocalFree(lpwsz);
    }

    return lReturn;
}