Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

661 lines
18 KiB

// UI.CPP
#include "common.h"
#define mskTraceLocalDebug 0x00000
CStatusBar StatusBar;
HMENU hmenuMain; // Menu handle of the main window
HMENU hmenuContext; // Context menu handle
HCURSOR hcursorArrow; // Standard Arrow Cursor
HCURSOR hcursorWait; // Hourglass cursor
HCURSOR hcursorNo; // Slashed circle cursor
HCURSOR hcursorSplit; // Split window cursor
HCURSOR hcursorFinger;
HCURSOR hcursorFingerNo;
HFONT hfontNormal; // Normal dialog font
HFONT hfontBold; // Bold dialog font
HFONT hfontBig; // 3/2 dialog font
COLORREF clrWindow;
COLORREF clrWindowText;
COLORREF clrHighlight;
COLORREF clrHighlightText;
HBRUSH hbrWindow;
HBRUSH hbrWindowText;
HBRUSH hbrHighlight;
int cyCharListBoxItem = 13; // Height of a listbox item
int cyCharStaticCtrl = 13; // Height of a single line static control
SPLITTERINFO splitterinfo = { NULL, SPI_nDragModeNone, 60, 0 };
/////////////////////////////////////////////////////////////////////////////
BOOL FInitBrushes()
{
hcursorArrow = LoadCursor(NULL, IDC_ARROW);
hcursorWait = LoadCursor(NULL, IDC_WAIT);
hcursorNo = LoadCursor(NULL, IDC_NO);
hcursorSplit = HLoadCursor(ID_CURSOR_VSPLIT);
hcursorFinger = HLoadCursor(ID_CURSOR_FINGER);
hcursorFingerNo = HLoadCursor(ID_CURSOR_FINGERNO);
clrWindow = GetSysColor(COLOR_WINDOW);
clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
hbrWindow = CreateSolidBrush(clrWindow);
Report(hbrWindow);
hbrWindowText = CreateSolidBrush(clrWindowText);
Report(hbrWindowText);
hbrHighlight = CreateSolidBrush(clrHighlight);
Report(hbrHighlight);
return (hbrWindow && hbrWindowText && hbrHighlight);
} // FInitBrushes
/////////////////////////////////////////////////////////////////////////////
void DestroyBrushes()
{
SideReport(DeleteObject(hbrWindow));
SideReport(DeleteObject(hbrWindowText));
SideReport(DeleteObject(hbrHighlight));
} // DestroyBrushes
/////////////////////////////////////////////////////////////////////////////
void MoveSplitterWindow()
{
int xSplitterT;
xSplitterT = splitterinfo.xOffset + (mainwindowposition.cx / 4);
if (xSplitterT < 60)
xSplitterT = 60;
if (xSplitterT > mainwindowposition.cx - 60)
xSplitterT = mainwindowposition.cx - 60;
splitterinfo.xPosLast = xSplitterT;
HDWP hdwp = BeginDeferWindowPos(3);
hdwp = DeferWindowPos(hdwp, TreeView.m_hWnd, NULL,
0, 0,
xSplitterT, mainwindowposition.cy - 1,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
Report(hdwp);
hdwp = DeferWindowPos(hdwp, splitterinfo.hwnd, NULL,
xSplitterT, 0,
4, mainwindowposition.cy,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS);
Report(hdwp);
xSplitterT += 4;
hdwp = HelperMgr.HDeferWindowPos(
hdwp,
xSplitterT, 0,
mainwindowposition.cx - xSplitterT, mainwindowposition.cy - 1);
SideReport(EndDeferWindowPos(hdwp));
} // MoveSplitterWindow
/////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProcSplitter(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT rc;
switch (uMsg)
{
case WM_ERASEBKGND:
GetClientRect(hwnd, OUT &rc);
SelectObject((HDC)wParam, GetStockObject(WHITE_PEN));
MoveToEx((HDC)wParam, 0, rc.bottom, NULL);
LineTo((HDC)wParam, 0, 0);
rc.left = 1;
FillRect((HDC)wParam, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
LineTo((HDC)wParam, rc.right, 0);
return TRUE;
case WM_LBUTTONDOWN:
splitterinfo.nDragMode = SPI_nDragModeMouse;
SetCapture(hwnd);
return 0;
case WM_LBUTTONUP:
splitterinfo.nDragMode = SPI_nDragModeNone;
ReleaseCapture();
SetFocus(hwndMain);
return 0;
case WM_MOUSEMOVE:
if (splitterinfo.nDragMode)
{
splitterinfo.xOffset = (signed short)LOWORD(lParam) - 1 + splitterinfo.xPosLast
- (mainwindowposition.cx / 4);
MoveSplitterWindow();
SetCapture(hwnd);
}
return 0;
case WM_SETFOCUS:
splitterinfo.nDragMode = SPI_nDragModeKeyboard;
GetWindowRect(hwnd, OUT &rc);
SetCursorPos(rc.left + 1, rc.top + (rc.bottom - rc.top) / 5);
StatusBar.SetText(IDS_STATUS_MOVE_SPLIT_BAR);
return 0;;
case WM_KILLFOCUS:
splitterinfo.nDragMode = SPI_nDragModeNone;
ReleaseCapture();
StatusBar.SetText(IDS_READY);
return 0;
case WM_KEYDOWN:
Report(splitterinfo.nDragMode != SPI_nDragModeNone);
splitterinfo.nDragMode = SPI_nDragModeKeyboard;
ReleaseCapture();
lParam = 1;
switch (wParam)
{
case VK_LEFT:
splitterinfo.xOffset -= 5;
MoveSplitterWindow();
break;
case VK_RIGHT:
splitterinfo.xOffset += 5;
MoveSplitterWindow();
break;
case VK_ESCAPE:
case VK_RETURN:
lParam = -4;
SetFocus(hwndMain);
}
GetWindowRect(hwnd, OUT &rc);
SetCursorPos(rc.left + lParam, rc.top + (rc.bottom - rc.top) / 5);
return 0;
} // switch
return DefWindowProc (hwnd, uMsg, wParam, lParam);
} // WndProcSplitter
/////////////////////////////////////////////////////////////////////////////
CWaitCursor::CWaitCursor(HWND hwnd)
{
Assert(IsWindow(hwnd));
Assert(hcursorWait);
m_hCursorPrev = SetCursor(hcursorWait);
SetCapture(hwnd);
} // CWaitCursor
/////////////////////////////////////////////////////////////////////////////
CWaitCursor::~CWaitCursor()
{
SetCursor(m_hCursorPrev);
ReleaseCapture();
} // ~CWaitCursor
/////////////////////////////////////////////////////////////////////////////
CWaitTimer::CWaitTimer()
{
m_dwInitTime = GetTickCount();
} // CWaitTimer
/////////////////////////////////////////////////////////////////////////////
void CWaitTimer::DoWait(LONG lMaximumSleepTime)
{
LONG l;
l = GetTickCount() - m_dwInitTime;
Report(l >= 0);
lMaximumSleepTime -= l;
Report(lMaximumSleepTime < 60000);
Trace1(mskTracePaintUI, "\nCWaitTimer::DoWait() - Sleeping for %d milliseconds...", lMaximumSleepTime);
if (lMaximumSleepTime > 0)
Sleep(lMaximumSleepTime & 0xFFFF);
} // DoWait
/////////////////////////////////////////////////////////////////////////////
BOOL CStatusBar::FCreate()
{
RECT rc;
// Create the status bar
Assert(m_hWnd == NULL);
Assert(IsWindow(hwndMain));
m_hWnd = CreateWindow(
STATUSCLASSNAME,
NULL, // Pane 0 text
WS_CHILD | WS_VISIBLE, // Style of the status bar bits
0, 0, 0, 0, // The size of the status bar is handled by WM_SIZE
hwndMain, // Parent windowh
(HMENU)ID_STATUSBAR, // StatusBar ID
hInstanceSave, // Instance handle
NULL); // No parameters
Report(m_hWnd);
if (!m_hWnd)
return FALSE;
GetWindowRect(m_hWnd, &rc);
m_cy = rc.bottom - rc.top;
return TRUE;
} // CStatusBar::FCreate
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetText(UINT wIdString)
{
TCHAR szT[256];
Assert(HIWORD(wIdString) == 0);
CchLoadString(wIdString, szT, LENGTH(szT));
Assert(IsWindow(m_hWnd));
LSendMessage(m_hWnd, SB_SETTEXT, 0 /* Pane 0 */, (LPARAM)szT);
} // SetText
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetText(const TCHAR szText[])
{
Assert(IsWindow(m_hWnd));
LSendMessage(m_hWnd, SB_SETTEXT, 0 /* Pane 0 */, (LPARAM)szText);
} // SetText
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetTextPrintf(const TCHAR szTextFmt[], ...)
{
TCHAR szBuffer[512]; // Buffer to hold the final result
va_list arglist;
va_start(arglist, szTextFmt);
wvsprintf(szBuffer, szTextFmt, arglist);
Assert(lstrlen(szBuffer) < LENGTH(szBuffer));
Assert(IsWindow(m_hWnd));
LSendMessage(m_hWnd, SB_SETTEXT, 0 /* Pane 0 */, (LPARAM)szBuffer);
} // SetTextPrintf
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetTextPrintf(UINT wIdString, ...)
{
TCHAR szFormat[256]; // Format of the string
TCHAR szBuffer[512]; // Buffer to hold the final result
va_list arglist;
va_start(arglist, wIdString);
CchLoadString(wIdString, szFormat, LENGTH(szFormat));
wvsprintf(szBuffer, szFormat, arglist);
Assert(lstrlen(szBuffer) < LENGTH(szBuffer));
Assert(IsWindow(m_hWnd));
LSendMessage(m_hWnd, SB_SETTEXT, 0 /* Pane 0 */, (LPARAM)szBuffer);
} // SetTextPrintf
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetPaneText(UINT wIdString)
{
TCHAR szT[128];
Assert(HIWORD(wIdString) == 0);
CchLoadString(wIdString, szT, LENGTH(szT));
Assert(IsWindow(m_hWnd));
LSendMessage(m_hWnd, SB_SETTEXT, 1 /* Pane 1 */, (LPARAM)szT);
} // CStatusBar::SetPaneText
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::SetPaneText(const TCHAR szText[])
{
Assert(IsWindow(m_hWnd));
Assert(szText);
LSendMessage(m_hWnd, SB_SETTEXT, 1 /* Pane 1 */, (LPARAM)szText);
} // CStatusBar::SetPaneText
/////////////////////////////////////////////////////////////////////////////
void CStatusBar::OnSize(int cx)
{
int rgPaneWidth[2] = { cx - (70 + cx/10), -1 };
LSendMessage(m_hWnd, SB_SETPARTS, 2, (LPARAM)rgPaneWidth);
LSendMessage(m_hWnd, WM_SIZE, 0, 0);
} // CStatusBar::OnSize
/////////////////////////////////////////////////////////////////////////////
void CWndHeader::FInit(
HWND hwndHeader,
HWND hwndListBox,
HEADERITEMINFO rgHeaderItem[],
int cHeaderItem)
{
HD_ITEM hdi; // Header item
TCHAR szT[64];
int i, j;
AssertClassName(hwndHeader, WC_HEADER);
Assert(IsWindow(hwndListBox));
Assert(rgHeaderItem);
m_hWnd = hwndHeader;
m_hwndListBox = hwndListBox;
m_rgHeaderItem = rgHeaderItem;
m_cHeaderItem = cHeaderItem;
m_iAutoFitItem = -1;
Report(GetWindowLong(hwndListBox, GWL_USERDATA) == 0);
SetWindowLong(hwndListBox, GWL_USERDATA, (LONG)rgHeaderItem);
hdi.mask = HDI_FORMAT | HDI_WIDTH | HDI_TEXT;
hdi.fmt = HDF_LEFT | HDF_STRING;
hdi.pszText = szT;
for (i = 0; i < cHeaderItem; i++)
{
hdi.cxy = rgHeaderItem[i].cxItemInitial;
if (hdi.cxy == 0)
{
Trace0(m_iAutoFitItem >= 0 ? mskTraceAlways : mskTraceNone,
"\nOnly one item can be auto sized.");
m_iAutoFitItem = i;
}
CchLoadString(rgHeaderItem[i].idsItem, szT, LENGTH(szT));
j = Header_InsertItem(hwndHeader, i, &hdi);
Report(j == i);
} // for
// Add one last item for better UI
hdi.pszText = (TCHAR *)szNull;
Header_InsertItem(hwndHeader, i, &hdi);
m_cyWnd = 0;
DoLayout();
} // CWndHeader::FInit
/////////////////////////////////////////////////////////////////////////////
void CWndHeader::SetSize(int cx, int cyListBox)
{
Assert(IsWindow(m_hWnd));
HDWP hdwp = BeginDeferWindowPos(2);
Report(hdwp != NULL);
if (m_cyWnd == 0)
{
RECT rc;
GetWindowRect(m_hWnd, OUT &rc);
m_cyWnd = rc.bottom - rc.top;
GetWindowRect(m_hwndListBox, OUT &rc);
Assert(IsWindow(GetParent(m_hwndListBox)));
MapWindowPoints(HWND_DESKTOP, GetParent(m_hwndListBox), INOUT (POINT*)&rc, 2);
hdwp = DeferWindowPos(
hdwp, m_hWnd, NULL,
rc.left, rc.top - m_cyWnd + 4, cx, m_cyWnd,
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER);
}
else
{
hdwp = DeferWindowPos(
hdwp, m_hWnd, NULL,
0, 0, cx, m_cyWnd,
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER);
}
Report(hdwp != NULL);
hdwp = DeferWindowPos(
hdwp, m_hwndListBox, NULL,
0, 0, cx, cyListBox,
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER);
Report(hdwp != NULL);
SideReport(EndDeferWindowPos(hdwp));
DoLayout();
} // CWndHeader::SetSize
/////////////////////////////////////////////////////////////////////////////
// DoLayout()
//
// Layout the widths of each columns
//
void CWndHeader::DoLayout()
{
HD_ITEM hdi; // Header item
RECT rc;
int i;
int x;
GetClientRect(m_hwndListBox, OUT &rc);
Assert(rc.left == 0);
m_cyWndListBox = rc.bottom;
GetClientRect(m_hWnd, OUT &rc);
Assert(rc.left == 0);
m_cxWnd = rc.right;
x = 0;
hdi.mask = HDI_WIDTH;
for (i = 0; i < m_cHeaderItem; i++)
{
SideReport(Header_GetItem(m_hWnd, i, OUT &hdi));
m_rgHeaderItem[i].cxItemCurrent = hdi.cxy;
if (i != m_iAutoFitItem)
x += hdi.cxy;
}
if (m_iAutoFitItem >= 0)
{
int cxAuto = m_cxWnd - x;
Trace0(cxAuto > 0 ? mskTraceNone : mskTracePaintUI,
"\nUI: INFO: Width of control too small to for autofit");
m_rgHeaderItem[m_iAutoFitItem].cxItemCurrent = cxAuto;
// Change the width of the item
hdi.cxy = cxAuto;
SideReport(Header_SetItem(m_hWnd, m_iAutoFitItem, IN &hdi));
}
Report((HEADERITEMINFO *)GetWindowLong(m_hwndListBox, GWL_USERDATA) == m_rgHeaderItem);
//SetWindowPos(
// m_hwndListBox, NULL,
// 0, 0, 0, 0,
// SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
} // CWndHeader::DoLayout
/////////////////////////////////////////////////////////////////////////////
void CWndHeader::DrawListBoxLine()
{
HDC hdcListBox;
Assert(IsWindow(m_hwndListBox));
hdcListBox = GetDC(m_hwndListBox);
SetROP2(hdcListBox, R2_NOT);
MoveToEx(hdcListBox, m_xDragStart + m_cxDragCurrent, 0, NULL);
LineTo(hdcListBox, m_xDragStart + m_cxDragCurrent, m_cyWndListBox);
ReleaseDC(m_hwndListBox, hdcListBox);
} // CWndHeader::DrawListBoxLine
/////////////////////////////////////////////////////////////////////////////
BOOL CWndHeader::FOnNotify(HD_NOTIFY * pHeaderNotify)
{
HD_ITEM hdi;
int i;
int x;
Assert(pHeaderNotify != NULL);
Assert(pHeaderNotify->hdr.hwndFrom == m_hWnd);
switch (pHeaderNotify->hdr.code)
{
case HDN_BEGINTRACK:
Assert(pHeaderNotify->pitem != NULL);
// Compute the maximum and minimum width of item
if (pHeaderNotify->iItem >= m_cHeaderItem - 1)
{
Trace0(mskTraceLocalDebug, "\nHDN_BEGINTRACK: NoDrag");
break;
}
Assert(pHeaderNotify->iItem >= 0);
m_cxDragCurrent = pHeaderNotify->pitem->cxy;
m_cxDragMin = m_rgHeaderItem[pHeaderNotify->iItem].cxItemMin;
m_cxDragMax = m_cxWnd;
m_xDragStart = 0;
for (i = 0; i < pHeaderNotify->iItem; i++)
{
x = m_rgHeaderItem[i].cxItemCurrent;
m_cxDragMax -= x;
m_xDragStart += x;
}
while (i < m_cHeaderItem)
m_cxDragMax -= m_rgHeaderItem[i++].cxItemMin;
Report(m_cxDragMax > 0);
Report(m_xDragStart <= m_cxWnd);
DrawListBoxLine();
Trace4(mskTraceLocalDebug, "\nHDN_BEGINTRACK [iItem=%d]: m_xDragStart=%d, m_cxDragMin=%d, m_cxDragMax=%d.",
pHeaderNotify->iItem, m_xDragStart, m_cxDragMin, m_cxDragMax);
break;
case HDN_TRACK:
Assert(pHeaderNotify->pitem != NULL);
Assert(pHeaderNotify->pitem->mask & HDI_WIDTH);
if (pHeaderNotify->iItem >= m_cHeaderItem - 1)
break;
if (pHeaderNotify->pitem->cxy < m_cxDragMin)
pHeaderNotify->pitem->cxy = m_cxDragMin;
if (pHeaderNotify->pitem->cxy > m_cxDragMax)
pHeaderNotify->pitem->cxy = m_cxDragMax;
if (m_cxDragCurrent == pHeaderNotify->pitem->cxy)
break;
DrawListBoxLine();
m_cxDragCurrent = pHeaderNotify->pitem->cxy;
DrawListBoxLine();
Trace1(mskTraceLocalDebug, "\nHDN_TRACK: %d.", pHeaderNotify->pitem->cxy);
break;
case HDN_ENDTRACK:
Assert(pHeaderNotify->pitem != NULL);
if (pHeaderNotify->iItem >= m_cHeaderItem - 1)
{
Trace0(mskTraceLocalDebug, "\nHDN_ENDTRACK: NoDrag");
break;
}
Assert(pHeaderNotify->iItem >= 0);
Assert(m_cxDragCurrent >= m_cxDragMin);
DrawListBoxLine();
m_rgHeaderItem[pHeaderNotify->iItem].cxItemCurrent = m_cxDragCurrent;
Trace0(mskTraceLocalDebug, "\nHDN_ENDTRACK: [");
x = 0;
for (i = 0; i < m_cHeaderItem - 1; i++)
{
x += m_rgHeaderItem[i].cxItemCurrent;
Trace1(mskTraceLocalDebug, " %d ", m_rgHeaderItem[i].cxItemCurrent);
}
hdi.cxy = m_cxWnd - x;
// Resize the last item
if (hdi.cxy > 0)
{
hdi.mask = HDI_WIDTH;
SideReport(Header_SetItem(m_hWnd, i, IN &hdi));
}
Trace1(mskTraceLocalDebug, "] %d.", hdi.cxy);
Assert(IsWindow(m_hwndListBox));
InvalidateRect(m_hwndListBox, NULL, FALSE);
break;
} // switch
return FALSE;
} // CWndHeader::OnNotify
/////////////////////////////////////////////////////////////////////////////
void SubclassListBoxEx(HWND hwndListBox)
{
AssertClassName(hwndListBox, szClassListBox);
Assert((WNDPROC)GetWindowLong(hwndListBox, GWL_WNDPROC) == lpfnListBoxOld);
SetWindowLong(hwndListBox, GWL_WNDPROC, (LONG)WndProcListBoxEx);
} // SubclassListBoxEx
/////////////////////////////////////////////////////////////////////////////
void LB_HandleMouseClick(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
MOUSECLICKINFO mci;
HWND hwndParent;
RECT rcListBox;
int cItems; // Number of items in listbox
int i;
mci.hwndFrom = hwnd;
mci.wId = GetDlgCtrlID(hwnd);
mci.uAction = uMsg;
mci.uMouseFlags = wParam;
mci.ptMouse.x = LOWORD(lParam);
mci.ptMouse.y = HIWORD(lParam);
mci.iItem = LB_ERR;
mci.lParam = NULL;
Assert(IsWindow(hwnd));
hwndParent = GetParent(hwnd);
Assert(IsWindow(hwndParent));
SideAssert(GetClientRect(hwnd, OUT &rcListBox));
Assert(lpfnListBoxOld != NULL);
// Get number of elements in listbox
cItems = CallWindowProc(lpfnListBoxOld, hwnd, LB_GETCOUNT, 0, 0);
Report(cItems >= 0);
// Get the top index
i = CallWindowProc(lpfnListBoxOld, hwnd, LB_GETTOPINDEX, 0, 0);
Report(i >= 0 && (i < cItems || cItems == 0));
// Do some primitive hit-testing
while (i < cItems)
{
RECT rcItem;
DebugCode( LRESULT lResult = ) CallWindowProc(lpfnListBoxOld, hwnd,
LB_GETITEMRECT, i, OUT (LPARAM)&rcItem);
Report(lResult != LB_ERR);
#ifdef DEBUG
int cyItem = CallWindowProc(lpfnListBoxOld, hwnd,
LB_GETITEMHEIGHT, i, 0);
Assert(cyItem == rcItem.bottom - rcItem.top);
#endif // DEBUG
if (rcItem.top > rcListBox.bottom)
break;
if (PtInRect(&rcItem, mci.ptMouse))
{
mci.iItem = i;
break;
}
i++;
} // while
(void)SendMessage(hwndParent, UN_MOUSECLICK, mci.wId, (LPARAM)&mci);
#ifdef UNUSED
// REVIEW: This code is not necessary
Trace0(mci.uAction != uMsg ? mskTraceLocalDebug : mskTraceNone, "\nUN_MOUSECLICK: uAction changed");
Trace0(mci.iItem != i && i < cItems ? mskTraceAlways : mskTraceNone, "\nUN_MOUSECLICK: iItem changed");
if (mci.uAction == WM_LBUTTONDOWN && mci.iItem >= 0)
{
DebugCode( LRESULT lResult = ) CallWindowProc(lpfnListBoxOld,
hwnd, LB_SETCURSEL, mci.iItem, 0);
Report(lResult != LB_ERR);
Report(mci.iItem == CallWindowProc(lpfnListBoxOld, hwnd, LB_GETCURSEL, 0, 0));
// Notify the parent that the selection changed
SendMessage(hwndParent, WM_COMMAND,
MAKEWPARAM(mci.wId, LBN_SELCHANGE), (LPARAM)hwnd);
} // if
#endif // UNUSED
} // LB_HandleMouseClick
/////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProcListBoxEx(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
if (0 != LSendMessage(GetParent(hwnd), UN_KEYDOWN, wParam, (LPARAM)hwnd))
return 0;
break;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
LB_HandleMouseClick(hwnd, uMsg, wParam, lParam);
return 0;
} // switch
Assert(lpfnListBoxOld != NULL);
return CallWindowProc(lpfnListBoxOld, hwnd, uMsg, wParam, lParam);
} // WndProcListBoxEx