mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
Toolstatus: fixed searchbox subclass
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@5290 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
/*
|
||||
* Process Hacker -
|
||||
* Subclassed Edit control
|
||||
*
|
||||
* Copyright (C) 2012-2013 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Process Hacker -
|
||||
* Subclassed Edit control
|
||||
*
|
||||
* Copyright (C) 2012-2013 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// dmex: The non-client area subclassing code has been modified based on the following guide:
|
||||
// http://www.catch22.net/tuts/insert-buttons-edit-control
|
||||
@@ -28,8 +28,11 @@
|
||||
|
||||
#include <uxtheme.h>
|
||||
#include <vsstyle.h>
|
||||
#include <vssym32.h>
|
||||
#pragma comment(lib, "uxtheme.lib")
|
||||
|
||||
#define HRGN_FULL ((HRGN)1) // passed by WM_NCPAINT even though it's completely undocumented
|
||||
|
||||
typedef struct _NC_CONTROL
|
||||
{
|
||||
UINT CommandID; // sent in a WM_COMMAND message
|
||||
@@ -46,15 +49,14 @@ typedef struct _NC_CONTROL
|
||||
RECT rect;
|
||||
RECT oldrect;
|
||||
RECT* prect;
|
||||
|
||||
|
||||
HBRUSH BorderBrush;
|
||||
HBRUSH DcBrush;
|
||||
HTHEME WndHTheme;
|
||||
HIMAGELIST ImageList;
|
||||
HWND ParentWindow;
|
||||
WNDPROC NCAreaWndProc;
|
||||
} NC_CONTROL;
|
||||
|
||||
|
||||
static VOID GetButtonRect(
|
||||
__inout NC_CONTROL* nc,
|
||||
__in RECT* rect
|
||||
@@ -92,7 +94,7 @@ static VOID DrawInsertedButton(
|
||||
0, 0,
|
||||
CLR_NONE,
|
||||
CLR_NONE,
|
||||
ILD_NORMAL | ILD_TRANSPARENT | ILD_SCALE
|
||||
ILD_NORMAL | ILD_SCALE
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -106,21 +108,118 @@ static VOID DrawInsertedButton(
|
||||
0, 0,
|
||||
CLR_NONE,
|
||||
CLR_NONE,
|
||||
ILD_NORMAL | ILD_TRANSPARENT | ILD_SCALE
|
||||
ILD_NORMAL | ILD_SCALE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
VOID PhTnpDrawThemedBorder(
|
||||
__in HWND hwnd,
|
||||
__in NC_CONTROL* Context,
|
||||
__in HDC hdc
|
||||
)
|
||||
{
|
||||
RECT windowRect;
|
||||
RECT clientRect;
|
||||
LONG sizingBorderWidth;
|
||||
LONG borderX;
|
||||
LONG borderY;
|
||||
|
||||
GetWindowRect(hwnd, &windowRect);
|
||||
windowRect.right -= windowRect.left;
|
||||
windowRect.bottom -= windowRect.top;
|
||||
windowRect.left = 0;
|
||||
windowRect.top = 0;
|
||||
|
||||
clientRect.left = windowRect.left + GetSystemMetrics(SM_CXEDGE);
|
||||
clientRect.top = windowRect.top + GetSystemMetrics(SM_CYEDGE);
|
||||
clientRect.right = windowRect.right - GetSystemMetrics(SM_CXEDGE);
|
||||
clientRect.bottom = windowRect.bottom - GetSystemMetrics(SM_CYEDGE);
|
||||
|
||||
// Make sure we don't paint in the client area.
|
||||
//ExcludeClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);
|
||||
|
||||
// Draw the themed border.
|
||||
DrawThemeBackground(Context->WndHTheme, hdc, 0, 0, &windowRect, NULL);
|
||||
|
||||
// Calculate the size of the border we just drew, and fill in the rest of the space if we didn't fully paint the region.
|
||||
if (SUCCEEDED(GetThemeInt(Context->WndHTheme, 0, 0, TMT_SIZINGBORDERWIDTH, &sizingBorderWidth)))
|
||||
{
|
||||
borderX = sizingBorderWidth;
|
||||
borderY = sizingBorderWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
borderX = GetSystemMetrics(SM_CXBORDER);
|
||||
borderY = GetSystemMetrics(SM_CYBORDER);
|
||||
}
|
||||
|
||||
if (borderX < GetSystemMetrics(SM_CXEDGE) || borderY < GetSystemMetrics(SM_CYEDGE))
|
||||
{
|
||||
windowRect.left += GetSystemMetrics(SM_CXEDGE) - borderX;
|
||||
windowRect.top += GetSystemMetrics(SM_CYEDGE) - borderY;
|
||||
windowRect.right -= GetSystemMetrics(SM_CXEDGE) - borderX;
|
||||
windowRect.bottom -= GetSystemMetrics(SM_CYEDGE) - borderY;
|
||||
|
||||
FillRect(hdc, &windowRect, GetSysColorBrush(COLOR_WINDOW));
|
||||
}
|
||||
|
||||
//IntersectClipRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom);
|
||||
|
||||
{
|
||||
// get the screen coordinates of the window
|
||||
GetWindowRect(hwnd, &Context->rect);
|
||||
// adjust the coordinates - start from 0,0
|
||||
OffsetRect(&Context->rect, -Context->rect.left, -Context->rect.top);
|
||||
|
||||
// work out where to draw the button
|
||||
GetButtonRect(Context, &Context->rect);
|
||||
DrawInsertedButton(hwnd, Context, hdc, &Context->rect);
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN PhTnpOnNcPaint(
|
||||
__in HWND hwnd,
|
||||
__in NC_CONTROL* Context,
|
||||
__in_opt HRGN UpdateRegion
|
||||
)
|
||||
{
|
||||
// Themed border
|
||||
//if ((Context->ExtendedStyle & WS_EX_CLIENTEDGE) && Context->ThemeData)
|
||||
HDC hdc;
|
||||
ULONG flags;
|
||||
|
||||
if (UpdateRegion == HRGN_FULL)
|
||||
UpdateRegion = NULL;
|
||||
|
||||
// Note the use of undocumented flags below. GetDCEx doesn't work without these.
|
||||
flags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE | 0x10000;
|
||||
|
||||
if (UpdateRegion)
|
||||
flags |= DCX_INTERSECTRGN | 0x40000;
|
||||
|
||||
if (hdc = GetDCEx(hwnd, UpdateRegion, flags))
|
||||
{
|
||||
PhTnpDrawThemedBorder(hwnd, Context, hdc);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
__in HWND hwndDlg,
|
||||
__in UINT uMsg,
|
||||
__in WPARAM wParam,
|
||||
__in LPARAM lParam
|
||||
__in LPARAM lParam,
|
||||
__in UINT_PTR uIdSubclass,
|
||||
__in DWORD_PTR dwRefData
|
||||
)
|
||||
{
|
||||
NC_CONTROL* context = (NC_CONTROL*)GetProp(hwndDlg, L"Context");
|
||||
|
||||
if (!context || !context->NCAreaWndProc)
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
if (uMsg == WM_DESTROY)
|
||||
@@ -133,13 +232,11 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
|
||||
RemoveProp(hwndDlg, L"Context");
|
||||
PhFree(context);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_NCACTIVATE:
|
||||
case WM_ERASEBKGND:
|
||||
return TRUE;
|
||||
case WM_NCCALCSIZE:
|
||||
@@ -156,7 +253,8 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
nccsp->rgrc[0].bottom -= 1;
|
||||
|
||||
// let the old wndproc allocate space for the borders, or any other non-client space.
|
||||
CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam);
|
||||
//CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam);
|
||||
DefSubclassProc(hwndDlg, uMsg, wParam, lParam);
|
||||
|
||||
// calculate what the size of each window border is,
|
||||
// we need to know where the button is going to live.
|
||||
@@ -170,46 +268,51 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
// and will be the same width as a scrollbar button
|
||||
context->prect->right -= context->nButSize;
|
||||
}
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
case WM_NCPAINT:
|
||||
{
|
||||
HDC hdc;
|
||||
|
||||
if (hdc = GetWindowDC(hwndDlg))
|
||||
{
|
||||
// get the screen coordinates of the window
|
||||
GetWindowRect(hwndDlg, &context->rect);
|
||||
// adjust the coordinates - start from 0,0
|
||||
OffsetRect(&context->rect, -context->rect.left, -context->rect.top);
|
||||
|
||||
if (context->WndHTheme)
|
||||
{
|
||||
DrawThemeBackground(
|
||||
context->WndHTheme,
|
||||
hdc,
|
||||
EP_BACKGROUNDWITHBORDER,
|
||||
EBWBS_NORMAL,
|
||||
&context->rect,
|
||||
0
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear the draw region
|
||||
FillRect(hdc, &context->rect, context->DcBrush);
|
||||
// Set border color
|
||||
FrameRect(hdc, &context->rect, context->BorderBrush);
|
||||
}
|
||||
|
||||
// work out where to draw the button
|
||||
GetButtonRect(context, &context->rect);
|
||||
DrawInsertedButton(hwndDlg, context, hdc, &context->rect);
|
||||
|
||||
// cleanup
|
||||
ReleaseDC(hwndDlg, hdc);
|
||||
}
|
||||
{
|
||||
if (!PhTnpOnNcPaint(hwndDlg, context, (HRGN)wParam))
|
||||
return 0;
|
||||
}
|
||||
return FALSE;
|
||||
break;
|
||||
//case WM_NCPAINT:
|
||||
// {
|
||||
// HDC hdc;
|
||||
// if (hdc = GetWindowDC(hwndDlg))
|
||||
// {
|
||||
// // get the screen coordinates of the window
|
||||
// GetWindowRect(hwndDlg, &context->rect);
|
||||
// // adjust the coordinates - start from 0,0
|
||||
// OffsetRect(&context->rect, -context->rect.left, -context->rect.top);
|
||||
|
||||
// if (context->WndHTheme)
|
||||
// {
|
||||
// DrawThemeBackground(
|
||||
// context->WndHTheme,
|
||||
// hdc,
|
||||
// EP_BACKGROUNDWITHBORDER,
|
||||
// EBWBS_NORMAL,
|
||||
// &context->rect,
|
||||
// 0
|
||||
// );
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Clear the draw region
|
||||
// FillRect(hdc, &context->rect, context->DcBrush);
|
||||
// // Set border color
|
||||
// FrameRect(hdc, &context->rect, context->BorderBrush);
|
||||
// }
|
||||
|
||||
// // work out where to draw the button
|
||||
// GetButtonRect(context, &context->rect);
|
||||
// DrawInsertedButton(hwndDlg, context, hdc, &context->rect);
|
||||
|
||||
// // cleanup
|
||||
// ReleaseDC(hwndDlg, hdc);
|
||||
// }
|
||||
// }
|
||||
// return FALSE;
|
||||
case WM_NCHITTEST:
|
||||
{
|
||||
// get the screen coordinates of the mouse
|
||||
@@ -234,7 +337,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
|
||||
// get the position of the inserted button
|
||||
GetWindowRect(hwndDlg, &context->rect);
|
||||
|
||||
|
||||
context->pt.x -= context->rect.left;
|
||||
context->pt.y -= context->rect.top;
|
||||
|
||||
@@ -247,7 +350,7 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
if (PtInRect(&context->rect, context->pt))
|
||||
{
|
||||
SetCapture(hwndDlg);
|
||||
|
||||
|
||||
// Send the click notification to the parent window
|
||||
PostMessage(
|
||||
context->ParentWindow,
|
||||
@@ -257,42 +360,42 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
);
|
||||
|
||||
// invalidate the nonclient area
|
||||
//RedrawWindow(
|
||||
// hwndDlg,
|
||||
// NULL, NULL,
|
||||
// RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN
|
||||
// );
|
||||
SetWindowPos(
|
||||
hwndDlg,
|
||||
0, 0, 0, 0, 0,
|
||||
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
|
||||
);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
//case WM_NCMOUSEMOVE:
|
||||
//case WM_NCMOUSELEAVE:
|
||||
// {
|
||||
// // get the screen coordinates of the mouse
|
||||
// context->pt.x = GET_X_LPARAM(lParam);
|
||||
// context->pt.y = GET_Y_LPARAM(lParam);
|
||||
// // get the position of the inserted button
|
||||
// GetWindowRect(hwndDlg, &context->rect);
|
||||
// context->pt.x -= context->rect.left;
|
||||
// context->pt.y -= context->rect.top;
|
||||
// // adjust the coordinates so they start from 0,0
|
||||
// OffsetRect(&context->rect, -context->rect.left, -context->rect.top);
|
||||
// GetButtonRect(context, &context->rect);
|
||||
// context->oldstate = context->IsMouseActive;
|
||||
// //check that the mouse is within the inserted button
|
||||
// if (PtInRect(&context->rect, context->pt))
|
||||
// {
|
||||
// context->IsMouseActive = TRUE;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// context->IsMouseActive = FALSE;
|
||||
// }
|
||||
// // to prevent flicker, we only redraw the button if its state has changed
|
||||
// if (context->oldstate != context->IsMouseActive)
|
||||
// DrawInsertedButton(hwndDlg, context, NULL, &context->rect);
|
||||
// }
|
||||
// break;
|
||||
//case WM_NCMOUSEMOVE:
|
||||
//case WM_NCMOUSELEAVE:
|
||||
// {
|
||||
// // get the screen coordinates of the mouse
|
||||
// context->pt.x = GET_X_LPARAM(lParam);
|
||||
// context->pt.y = GET_Y_LPARAM(lParam);
|
||||
// // get the position of the inserted button
|
||||
// GetWindowRect(hwndDlg, &context->rect);
|
||||
// context->pt.x -= context->rect.left;
|
||||
// context->pt.y -= context->rect.top;
|
||||
// // adjust the coordinates so they start from 0,0
|
||||
// OffsetRect(&context->rect, -context->rect.left, -context->rect.top);
|
||||
// GetButtonRect(context, &context->rect);
|
||||
// context->oldstate = context->IsMouseActive;
|
||||
// //check that the mouse is within the inserted button
|
||||
// if (PtInRect(&context->rect, context->pt))
|
||||
// {
|
||||
// context->IsMouseActive = TRUE;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// context->IsMouseActive = FALSE;
|
||||
// }
|
||||
// // to prevent flicker, we only redraw the button if its state has changed
|
||||
// if (context->oldstate != context->IsMouseActive)
|
||||
// DrawInsertedButton(hwndDlg, context, NULL, &context->rect);
|
||||
// }
|
||||
// break;
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
// get the SCREEN coordinates of the mouse
|
||||
@@ -317,11 +420,11 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
{
|
||||
context->TextLength = Edit_GetTextLength(hwndDlg) > 0;
|
||||
|
||||
//RedrawWindow(
|
||||
// hwndDlg,
|
||||
// NULL, NULL,
|
||||
// RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN
|
||||
// );
|
||||
SetWindowPos(
|
||||
hwndDlg,
|
||||
0, 0, 0, 0, 0,
|
||||
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
|
||||
);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
@@ -330,16 +433,16 @@ LRESULT CALLBACK NcAreaWndSubclassProc(
|
||||
context->TextLength = Edit_GetTextLength(hwndDlg) > 0;
|
||||
|
||||
// invalidate the nonclient area
|
||||
RedrawWindow(
|
||||
hwndDlg,
|
||||
NULL, NULL,
|
||||
RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN
|
||||
SetWindowPos(
|
||||
hwndDlg,
|
||||
0, 0, 0, 0, 0,
|
||||
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc(context->NCAreaWndProc, hwndDlg, uMsg, wParam, lParam);
|
||||
return DefSubclassProc(hwndDlg, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
BOOLEAN InsertButton(
|
||||
@@ -347,12 +450,10 @@ BOOLEAN InsertButton(
|
||||
__in UINT CommandID
|
||||
)
|
||||
{
|
||||
NC_CONTROL* context = (NC_CONTROL*)PhAllocate(
|
||||
sizeof(NC_CONTROL)
|
||||
);
|
||||
NC_CONTROL* context = (NC_CONTROL*)PhAllocate(sizeof(NC_CONTROL));
|
||||
|
||||
memset(context, 0, sizeof(NC_CONTROL));
|
||||
|
||||
|
||||
context->CommandID = CommandID;
|
||||
context->ParentWindow = GetParent(hwndDlg);
|
||||
context->BorderBrush = (HBRUSH)CreateSolidBrush(RGB(0x8f, 0x8f, 0x8f));
|
||||
@@ -381,7 +482,7 @@ BOOLEAN InsertButton(
|
||||
SetProp(hwndDlg, L"Context", (HANDLE)context);
|
||||
|
||||
// replace the old window procedure with our new one
|
||||
context->NCAreaWndProc = SubclassWindow(hwndDlg, NcAreaWndSubclassProc);
|
||||
SetWindowSubclass(hwndDlg, NcAreaWndSubclassProc, 0, 0);
|
||||
|
||||
if (!context->WndHTheme)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user