📄 commctrl.c
字号:
LPSUBCLASS_INFO stack;
LPSUBCLASSPROCS prevproc = NULL;
LPSUBCLASSPROCS proc;
BOOL ret = FALSE;
TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID);
/* Find the Subclass to remove */
stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack)
return FALSE;
proc = stack->SubclassProcs;
while (proc) {
if ((proc->id == uID) &&
(proc->subproc == pfnSubclass)) {
if (!prevproc)
stack->SubclassProcs = proc->next;
else
prevproc->next = proc->next;
if (stack->stackpos == proc)
stack->stackpos = stack->stackpos->next;
Free (proc);
ret = TRUE;
break;
}
prevproc = proc;
proc = proc->next;
}
if (!stack->SubclassProcs && !stack->running) {
TRACE("Last Subclass removed, cleaning up\n");
/* clean up our heap and reset the origional window procedure */
if (IsWindowUnicode (hWnd))
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
else
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
Free (stack);
RemovePropW( hWnd, COMCTL32_wSubclass );
}
return ret;
}
/***********************************************************************
* COMCTL32_SubclassProc (internal)
*
* Window procedure for all subclassed windows.
* Saves the current subclassing stack position to support nested messages
*/
LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPSUBCLASS_INFO stack;
LPSUBCLASSPROCS proc;
LRESULT ret;
TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack) {
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
return 0;
}
/* Save our old stackpos to properly handle nested messages */
proc = stack->stackpos;
stack->stackpos = stack->SubclassProcs;
stack->running++;
ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
stack->running--;
stack->stackpos = proc;
if (!stack->SubclassProcs && !stack->running) {
TRACE("Last Subclass removed, cleaning up\n");
/* clean up our heap and reset the origional window procedure */
if (IsWindowUnicode (hWnd))
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
else
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
Free (stack);
RemovePropW( hWnd, COMCTL32_wSubclass );
}
return ret;
}
/***********************************************************************
* DefSubclassProc [COMCTL32.413]
*
* Calls the next window procedure (ie. the one before this subclass)
*
* PARAMS
* hWnd [in] The window that we're subclassing
* uMsg [in] Message
* wParam [in] WPARAM
* lParam [in] LPARAM
*
* RETURNS
* Success: non-zero
* Failure: zero
*/
LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPSUBCLASS_INFO stack;
LRESULT ret;
TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam);
/* retrieve our little stack from the Properties */
stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack) {
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
return 0;
}
/* If we are at the end of stack then we have to call the original
* window procedure */
if (!stack->stackpos) {
if (IsWindowUnicode (hWnd))
ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
else
ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam);
} else {
LPSUBCLASSPROCS proc = stack->stackpos;
stack->stackpos = stack->stackpos->next;
/* call the Subclass procedure from the stack */
ret = proc->subproc (hWnd, uMsg, wParam, lParam,
proc->id, proc->ref);
}
return ret;
}
/***********************************************************************
* COMCTL32_CreateToolTip [NOT AN API]
*
* Creates a tooltip for the control specified in hwnd and does all
* necessary setup and notifications.
*
* PARAMS
* hwndOwner [I] Handle to the window that will own the tool tip.
*
* RETURNS
* Success: Handle of tool tip window.
* Failure: NULL
*/
HWND
COMCTL32_CreateToolTip(HWND hwndOwner)
{
HWND hwndToolTip;
hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
0, 0, 0);
/* Send NM_TOOLTIPSCREATED notification */
if (hwndToolTip)
{
NMTOOLTIPSCREATED nmttc;
/* true owner can be different if hwndOwner is a child window */
HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
nmttc.hdr.hwndFrom = hwndTrueOwner;
nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
nmttc.hdr.code = NM_TOOLTIPSCREATED;
nmttc.hwndToolTips = hwndToolTip;
SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
(WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
(LPARAM)&nmttc);
}
return hwndToolTip;
}
/***********************************************************************
* COMCTL32_RefreshSysColors [NOT AN API]
*
* Invoked on any control recognizing a WM_SYSCOLORCHANGE message to
* refresh the color values in the color structure
*
* PARAMS
* none
*
* RETURNS
* none
*/
VOID
COMCTL32_RefreshSysColors(void)
{
comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
}
/***********************************************************************
* COMCTL32_DrawInsertMark [NOT AN API]
*
* Draws an insertion mark (which looks similar to an 'I').
*
* PARAMS
* hDC [I] Device context to draw onto.
* lpRect [I] Co-ordinates of insertion mark.
* clrInsertMark [I] Colour of the insertion mark.
* bHorizontal [I] True if insert mark should be drawn horizontally,
* vertical otherwise.
*
* RETURNS
* none
*
* NOTES
* Draws up to but not including the bottom co-ordinate when drawing
* vertically or the right co-ordinate when horizontal.
*/
void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
{
HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
HPEN hOldPen;
static const DWORD adwPolyPoints[] = {4,4,4};
LONG lCentre = (bHorizontal ?
lpRect->top + (lpRect->bottom - lpRect->top)/2 :
lpRect->left + (lpRect->right - lpRect->left)/2);
LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
const POINT aptInsertMark[] =
{
/* top (V) or left (H) arrow */
{lCentre , l1 + 2},
{lCentre - 2, l1 },
{lCentre + 3, l1 },
{lCentre + 1, l1 + 2},
/* middle line */
{lCentre , l2 - 2},
{lCentre , l1 - 1},
{lCentre + 1, l1 - 1},
{lCentre + 1, l2 - 2},
/* bottom (V) or right (H) arrow */
{lCentre , l2 - 3},
{lCentre - 2, l2 - 1},
{lCentre + 3, l2 - 1},
{lCentre + 1, l2 - 3},
};
hOldPen = SelectObject(hDC, hPen);
PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
SelectObject(hDC, hOldPen);
DeleteObject(hPen);
}
/***********************************************************************
* COMCTL32_EnsureBitmapSize [internal]
*
* If needed enlarge the bitmap so that the width is at least cxMinWidth
* the height is at least cyMinHeight. If the bitmap already have these
* dimensions nothing changes.
*
* PARAMS
* hBitmap [I/O] Bitmap to modify. The handle may change
* cxMinWidth [I] If the width of the bitmap is smaller then it will
* be enlarged to this value
* cyMinHeight [I] If the height of the bitmap is smaller then it will
* be enlarged to this value
* cyBackground [I] The color with which the new area will be filled
*
* RETURNS
* none
*/
void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
{
int cxNew, cyNew;
BITMAP bmp;
HBITMAP hNewBitmap;
HBITMAP hNewDCBitmap, hOldDCBitmap;
HBRUSH hNewDCBrush;
HDC hdcNew, hdcOld;
if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
return;
cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
return;
hdcNew = CreateCompatibleDC(NULL);
hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
hdcOld = CreateCompatibleDC(NULL);
hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
if (bmp.bmWidth < cxMinWidth)
PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
if (bmp.bmHeight < cyMinHeight)
PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
SelectObject(hdcNew, hNewDCBitmap);
DeleteObject(SelectObject(hdcNew, hNewDCBrush));
DeleteDC(hdcNew);
SelectObject(hdcOld, hOldDCBitmap);
DeleteDC(hdcOld);
DeleteObject(*pBitmap);
*pBitmap = hNewBitmap;
return;
}
/***********************************************************************
* MirrorIcon [COMCTL32.414]
*
* Mirrors an icon so that it will appear correctly on a mirrored DC.
*
* PARAMS
* phicon1 [I/O] Icon.
* phicon2 [I/O] Icon.
*
* RETURNS
* Success: TRUE.
* Failure: FALSE.
*/
BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
{
FIXME("(%p, %p): stub\n", phicon1, phicon2);
return FALSE;
}
static inline int IsDelimiter(WCHAR c)
{
switch(c)
{
case '/':
case '\\':
case '.':
case ' ':
return TRUE;
}
return FALSE;
}
static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code)
{
if (code == WB_ISDELIMITER)
return IsDelimiter(lpch[ichCurrent]);
else
{
int dir = (code == WB_LEFT) ? -1 : 1;
for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
}
return ichCurrent;
}
/***********************************************************************
* SetPathWordBreakProc [COMCTL32.384]
*
* Sets the word break procedure for an edit control to one that understands
* paths so that the user can jump over directories.
*
* PARAMS
* hwnd [I] Handle to edit control.
* bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed.
*
* RETURNS
* Result from EM_SETWORDBREAKPROC message.
*/
LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
{
return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
(LPARAM)(bSet ? PathWordBreakProc : NULL));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -