Re: How add buton onto title bar of any external active window?
- From: Joseph M. Newcomer <newcomer@xxxxxxxxxxxx>
- Date: Wed, 17 Dec 2008 15:54:55 -0500
See below...many problems, including massive complexity where none is needed, and
addressing the wrong problem. See the Paul DiLascia articles on painting the caption bar.
joe
On Wed, 17 Dec 2008 01:34:01 -0800 (PST), varsh211@xxxxxxxxx wrote:
Hi,****
I want to add buttons ontoany active window. But in my code I
have some problem.
1] When I tried to draw button using WM_PAINT of custom application
window proc then button shown flickring effect.
You would not use OnPaint for this, because the title bar is in the nonclient portion of
the window, and OnPaint refers only to the client portion. Therefore, you can ignore this
as a possible solution
****
2] I set the position of custom window using SetWindowPos with****
hWndInsertAfter=HWND_TOP then It changes its zorder or inactivated
after some time with some window event like resize and titlebar
mousedown.
If the button is on the title bar, it is in the nonclient area. Therefore, trying to set
its position relative to controls in the client area, which is all SetWindowPos can do, is
a meaningless action, and will result in undefined behavior.
****
****
I attached my code with this mail which is created in VC++ VS2003.
Please replacethe threadId of SetWindowsHookEx function which in
main.c's
winmain function to the any active window threadId using SPY++ of
Visual studio tools.
Please tell my code is worng or right and how to solve above problems.
//This is main.c file winmain is the starting point of this
application
// In file I created custom external window and attached this window
to active window on desktop using hook
#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
#include "common.h"
#include "resource.h"
#include "CaptionButton.h"
#define WS_EX_NOACTIVATE 0x08000000L
Why are you defining this here? It makes no sense. It is ALREADY defined in winuser.h.
You need to do
#define _WIN32_WINNT 0x0500
#include <windows.h>
But why are you not using stdafx.h and using precompiled headers?
****
****
TCHAR szAppName[] = _T("Custom Titlebar");
static const TCHAR szAppName[] = _T("Custom Titlebar");
****
/* System-wide properties */****
int sm_CXSIZE;
int sm_CYSIZE;
int sm_CXSIZEFRAME;
int sm_CXFIXEDFRAME;
int sm_CYSIZEFRAME;
int sm_CYFIXEDFRAME;
int sm_CXFULLSCREEN;
These should not exist. (a) they are global variables (b) they will have no meaning once
the message loop is entered, EACH TIME the message loop is entered, therefore they cannot
be relied on except in the immediate context of when they are used. Also, they have no
meaning in a multimonitor environment.
****
****
HBITMAP hBmp1, hBmp2;
Do not use commas in declaration lists. One variable, one line.
****
int AppWindowWidth;****
int left1;
HWND hd;
/* Work out where the grabbed window is, and move the app there */
/* Move the window into place */
void GetMetrics( void )
{
sm_CXSIZE = GetSystemMetrics( SM_CXSIZE );
sm_CYSIZE = GetSystemMetrics( SM_CYSIZE );
sm_CXSIZEFRAME = GetSystemMetrics( SM_CXSIZEFRAME );
sm_CXFIXEDFRAME = GetSystemMetrics( SM_CXFIXEDFRAME );
sm_CYSIZEFRAME = GetSystemMetrics( SM_CYSIZEFRAME );
sm_CYFIXEDFRAME = GetSystemMetrics( SM_CYFIXEDFRAME );
sm_CXFULLSCREEN = GetSystemMetrics( SM_CXFULLSCREEN );
}
Note that these must be obtained EVERY TIME, since they are essentially rendered
meaningless each time through the message pump. Think multi-monitor systems; you are
capturing information only for the primary monitor, and therefore these numbers can be
made irrelevant if the window moves. Why are they global variables, anyway?
****
****
/* Most captioned windows have things like minimise or close buttons
on
the right: this routine calculates the width of these features on
the
passed in window. Because the callers of this routine typically use
the style already, this function accepts that as an argument too, a
bit quicker than getting it again. Unfortunately, not all the sizes
associated with the placement of these features are defined by
Windows
metrics, so some, I am afraid, are just magic numbers found by
careful
measurement. Additionally, I grab the other sizes every time,
instead
of caching them, just in case they are changed under my feet! */
static int WindowsFeaturesWidth( HWND hwnd, DWORD style )
{
/* The reasoning behind this is: if a Window has a system menu
specified,
it'll have a close button; additionally it can have nothing else
OR a
help button OR both minimise and maximise buttons, and in that
latter
case, the buttons are adjacent so trim off the inter-button
spacing.
Note that the buttons are actually 2 pixels smaller than the
system
metric, as it appears that that includes the spacing. */
int width = 2 + ( ( style & WS_THICKFRAME ) ? sm_CXSIZEFRAME :
sm_CXFIXEDFRAME );
if( style & WS_SYSMENU )
width += sm_CXSIZE;
It probably isn't 2 pixels, it's probably ::GetSystemMetrics(SM_CXEDGE)
****
/* I think I should be able to check for maximise and minimise****
buttons
separately, but some applications (all?), such as calculator,
display
both even though one is not enabled - since it's better to have a
gap
I assume that if one's there both are */
if( style & ( WS_MAXIMIZEBOX | WS_MINIMIZEBOX ) )
width += sm_CXSIZE * 2 - 2; /* -2 since the buttons touch */
else if( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_CONTEXTHELP )
width += sm_CXSIZE;
return width;
}
/* Move the window into place */
static void Position( int top, int right )
{
RECT r;
DWORD a;
BOOL ff;
if( GetWindowRect( hd, &r ) )
AppWindowWidth = r.right - r.left;
And if GetWindowRect fails, what is AppWindowWidth?
****
****
left1 = right - 0 - AppWindowWidth;
Is the - 0 and important term.
****
****
if( left1 < 0 )
left1 = 0;
top += 0;
The above line doesn't do much...
****
if( top < 0 )*****
top = 0;
/* TODO - make sure it doesn't fall off the right or bottom either
*/
//LOG(( _T("Moving to %d,%d\n"), left, top ));
ff=SetWindowPos( hd, HWND_TOP,
left1, top, 30, 20,
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOSENDCHANGING |
SWP_ASYNCWINDOWPOS | SWP_NOOWNERZORDER );
}
SetWindowPos is meaningless. You need to look at the articles by Paul DiLascia on doing
non-client painting; google
dilascia shadecap
****
****
static void Attach( HWND hwnd, int right, int top )
{
DWORD style = GetWindowLong( hwnd, GWL_STYLE );
right -= WindowsFeaturesWidth( hwnd, style );
top += ( ( style & WS_THICKFRAME ) ? sm_CYSIZEFRAME :
sm_CYFIXEDFRAME );
Position( top, right );
MostRecentWindow = hwnd;
}
static BOOL IsPositionOK( HWND hwnd, /*[out]*/ int* right, /*[out]*/
int* top )
{
RECT r;
GetWindowRect( hwnd, &r );
/* Window is offscreen - that's no use! */
/* TODO - check of off bottom too */
if( r.right < 0 || r.left > sm_CXFULLSCREEN || r.bottom < 0 )
return FALSE;
*right = r.right;
*top = r.top;
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{
TCHAR szText[80];
HBITMAP hBmp1, hBmp2;
One variable, one line, no commas. Also, move this declaration into the WM_CREATE handler
so it doesn't add confusion to the handler. For that matter, why are you doing code
inline in the switch statement, instead of calling functions to do this. And why are you
not using the windowsx.h macros to make the code readable?
****
****
int right, top;
switch(msg)
{
case WM_CREATE:
// These must be MONOCHROME bitmaps if you want them
// to be drawn nicely.
hBmp2 = LoadBitmap(GetModuleHandle(0), MAKEINTRESOURCE
(IDB_BITMAP2));
Caption_InsertButton(hwnd, 2, 2, hBmp2);
return 0;
case UPDATE_MSG:
What is the definition of this message?
(a) it must not be WM_USER-based
(b) it should NOT be WM_APP-based
(c) it SHOULD be a Registered Window Message, which means you cannot use a switch
statement to decode it, but instead must do
if(msg == UPDATE_MSG)
{
...
}
switch(msg)
{
...
}
/* Only do something if the config window is hidden, and don't****
react to
the window we're hooking! */
/*if( IsWindowVisible( hwnd ) || (HWND)wParam == hd )
return 0;*/
if( IsWindowSuitable( (HWND)wParam ) && IsPositionOK( (HWND)wParam,
&right, &top ) )
{
hd=hwnd;
Attach( (HWND)wParam, right, top );
wsprintf(szText, _T("%s %d "), szAppName, lParam);
And if the appname + lParam is > 80 characters, you destroy the stack? Get real! wsprintf
should never be used in real programs. Nor sprintf, strcpy, or strcat. If you do use
them, you MUST, absolutely MUST, limit the size of the result! For example, it would be
valid if you did _T("%-67.67s %d") because that would truncate the name, so even if lParam
took the whole 11 digits-plus-sign, it would fit into 80 spaces. Or do
_T(%-*.*s %d"), sizeof(szText)/sizeof(szText[0]) - 12,
sizeof(szText)/sizeof(szText[0]) - 12,
szAppName,
lParam
****
LOG((szText,"\n")) ;***
return 0;
}
return 0;
case WM_COMMAND:
/*wsprintf(szText, _T("%s %d [%d, %d]"), szAppName, wParam, LOWORD
(lParam), HIWORD(lParam));
SetWindowText(hd, szText);*/
It is appropriate to comment these lines out because they would never make sense as a
generic response to every possible WM_COMMAND message.
****
return 0;****
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine,
int iShowCmd)
{
HWND hwnd;
MSG msg;
WNDCLASSEX wc;
HINSTANCE hookLib;
DWORD lStyle;
HANDLE shared;
//hInst = GetModuleHandle( NULL );
/* Open shared memory block for write access */
shared = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, sizeof( SHARED_DATA ), SHARED_DATA_NAME );
SharedData = (SHARED_DATA*)MapViewOfFile( shared,
FILE_MAP_ALL_ACCESS, 0, 0, sizeof( SHARED_DATA ) );
Why is the application creating a shared data file? Why does this make sense, since the
size is compile-time fixed? Why do we not see the declaration of SHARED_DATA?
****
****
//Window class for the main application parent window
wc.cbSize = sizeof(wc);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
wc.lpszMenuName = 0;
wc.lpszClassName = szAppName;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hwnd = CreateWindowEx(WS_EX_NOACTIVATE,// | WS_EX_TOOLWINDOW,
szAppName, // window class name
szAppName, // window caption
WS_DLGFRAME , // window style
//WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION,
100, // initial x position
0, // initial y position
1, // initial x size
2, // initial y size
NULL, // parent window handle
NULL, // use window class menu
hInst, // program instance handle
NULL); // creation parameters
GetMetrics();
PositionerWindow=hwnd;
hd=hwnd;
lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= WS_CHILD;
lStyle &=~WS_MINIMIZEBOX,
SetWindowLong(hwnd, GWL_STYLE, lStyle);
This makes no sense. Why are you removing all the style bits but WS_CHILD, and THEN
deleting the WS_MINIMIZEBOX, given that none of these styles exist anyway, you should have
a style result of 0. If you don't want these styles, why did you not exclude them when
you specified the creation of the window?
****
SetWindowPos(hwnd,HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE |****
SWP_NOCOPYBITS | SWP_NOSENDCHANGING |
SWP_NOSIZE | SWP_ASYNCWINDOWPOS |
SWP_NOOWNERZORDER);
hookLib = LoadLibrary( _T("ForegroundHooker.dll") );
if( !hookLib )
{
return 0;
}
PrevHook = SetWindowsHookEx( WH_CALLWNDPROCRET,
(HOOKPROC)GetProcAddress( hookLib,
"_CallWndRetProc@12" ),
It seems weird to give a name like this; why do you explicitly call LoadLibrary instead of
just implicitly linking the DLL? If you are doing GetProcAddress, you can simplify things
tremendously by declaring the function as
extern "C" CallWndRetProc(int id, HOOKPROC proc, HINSTANCE hinst, DWORD threadid)
{
...code goes here
}
For that matter, why did you not simply create a function called SetHook in the DLL that
did all this for you?
*****
hookLib, 1840);****
THERE IS NO CONCEIVABLE WAY THAT 1840 COULD POSSIBLY MAKE SENSE IN ANY REAL PROGRAM!!!!
The thread ID is unpredictable, which is why there is an operation called
GetCurrentThreadId, and one called GetProcessThreadId.
*****
LOG(( _T("After window create and hook\n") ));****
if( !PrevHook )
{
return 0;
}
while(GetMessage(&msg, NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// KillTimer( hwnd, 1 /* Same number as SetTimer above */ );
UnhookWindowsHookEx( PrevHook );
PrevHook = NULL;
FreeLibrary( hookLib );
UnmapViewOfFile( SharedData );
Why are you using a mapped file view to share data? Why not a shared data segment? Why
does your application know about something that should be the private knowledge of the
DLL?
****
CloseHandle( shared );****
return 0;
}
//This is caption.c which is used to draw button on to custom windows
client area using subclassing
//
//
//
#include <windows.h>
#include <tchar.h>
static TCHAR szPropName[] = _T("CustomCaptionSubclassPtr");
static const TCHAR would have been a better choice
****
****
#define MAX_TITLE_BUTTONS 8
#define B_EDGE 2
#define BUFFER 4096
typedef struct
{
UINT uCmd; //command to send when clicked
int nRightBorder; //Pixels between this button and buttons to the
right
HBITMAP hBmp; //Bitmap to display
BOOL fPressed; //Private.
} CaptionButton;
typedef struct
{
CaptionButton buttons[MAX_TITLE_BUTTONS];
int nNumButtons;
BOOL fMouseDown;
WNDPROC wpOldProc;
int iActiveButton;
} CustomCaption;
// WinPropProc is an application-defined callback function
// that lists a window property.
static CustomCaption *GetCustomCaption(HWND hwnd)
{
//EnumPropsEx(hwnd, WinPropProc, NULL);
return (CustomCaption *)GetProp(hwnd, szPropName);
}
static void RedrawNC(HWND hwnd)
{
SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
SWP_NOZORDER | SWP_NOACTIVATE | SWP_DRAWFRAME);
}
static int CalcTopEdge(HWND hwnd)
{
DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
if(dwStyle & WS_THICKFRAME)
return GetSystemMetrics(SM_CYSIZEFRAME);
else
return GetSystemMetrics(SM_CYFIXEDFRAME);
}
static int CalcRightEdge(HWND hwnd)
{
DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
if(dwStyle & WS_THICKFRAME)
return GetSystemMetrics(SM_CXSIZEFRAME);
else
return GetSystemMetrics(SM_CXFIXEDFRAME);
}
//
// Return the starting position of the first inserted button.
// We need to take into account the size of the close button,
// The minimize, maximize buttons etc
//
// -------------------------------------------------\
// [-][+] [X] |
// ^
// |
// Return is pos |--- Ret --|
//
//
static int GetRightEdgeOffset(CustomCaption *ctp, HWND hwnd)
{
DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
int nButSize = 0;
int nSysButSize;
if(dwExStyle & WS_EX_TOOLWINDOW)
{
nSysButSize = GetSystemMetrics(SM_CXSMSIZE) - B_EDGE;
if(dwStyle & WS_SYSMENU)
nButSize += nSysButSize + B_EDGE;
return nButSize + CalcRightEdge(hwnd);
}
else
{
nSysButSize = GetSystemMetrics(SM_CXSIZE) - B_EDGE;
// Window has Close [X] button. This button has a 2-pixel
// border on either size
B_EDGE should be ::GetSystemMetrics(SM_CXEDGE) or some other appropriate method. It is
only 2 pixels on your machine, as far as you know.
****
if(dwStyle & WS_SYSMENU)****
{
nButSize += nSysButSize + B_EDGE;
}
// If either of the minimize or maximize buttons are shown,
// Then both will appear (but may be disabled)
// This button pair has a 2 pixel border on the left
if(dwStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX) )
{
nButSize += B_EDGE + nSysButSize * 2;
}
// A window can have a question-mark button, but only
// if it doesn't have any min/max buttons
else if(dwExStyle & WS_EX_CONTEXTHELP)
{
nButSize += B_EDGE + nSysButSize;
}
// Now calculate the size of the border...aggghh!
return nButSize + CalcRightEdge(hwnd);
}
}
//
// Input - rect is coords of window rectangle
// (in screen or relative coords)
//
// Output - rect is adjusted to describe button rectangle
//
static void GetButtonRect(CustomCaption *ctp, HWND hwnd, int idx, RECT
*rect, BOOL fWindowRelative)
{
int i, re_start;
int cxBut, cyBut;
if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
{
cxBut = GetSystemMetrics(SM_CXSMSIZE);
cyBut = GetSystemMetrics(SM_CYSMSIZE);
}
else
{
cxBut = GetSystemMetrics(SM_CXSIZE);
cyBut = GetSystemMetrics(SM_CYSIZE);
}
// right-edge starting point of inserted buttons
re_start = GetRightEdgeOffset(ctp, hwnd);
GetWindowRect(hwnd, rect);
//GetWindowRect(hd, rect);
if(fWindowRelative)
OffsetRect(rect, -rect->left, -rect->top);
//Find the correct button - but take into
//account all other buttons.
for(i = 0; i <= idx; i++)
{
re_start += ctp->buttons[i].nRightBorder + cxBut - B_EDGE;
}
////////rect->left =0;
////// rect->left = 200;
////// rect->top =0;
////// //rect->top = rect->top + CalcTopEdge(hwnd) + B_EDGE;
////// //rect->right = rect->left + cxBut - B_EDGE;
////// rect->right = 100;
////// rect->bottom = rect->top + cyBut - B_EDGE*2;
///* rect->left = rect->right - re_start;
//rect->top = rect->top + CalcTopEdge(hwnd) + B_EDGE;
//rect->right = rect->left + cxBut - B_EDGE;
//rect->bottom = rect->top + cyBut - B_EDGE*2;*/
rect->left = rect->right - re_start;
rect->top = rect->top + CalcTopEdge(hwnd) + B_EDGE;
rect->right = rect->left + cxBut - B_EDGE;
rect->bottom = rect->top + cyBut - B_EDGE*2;
}
static LRESULT Caption_NCHitTest(CustomCaption *ctp, HWND hwnd, WPARAM
wParam, LPARAM lParam)
{
RECT rect;
POINT pt;
int i;
UINT ret;
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
ret = CallWindowProc(ctp->wpOldProc, hwnd, WM_NCHITTEST, wParam,
lParam);
//If the mouse is in the caption, then check to
//see if it is over one of our buttons
if(ret == HTCAPTION)
{
for(i = 0; i < ctp->nNumButtons; i++)
{
GetButtonRect(ctp, hwnd, i, &rect, FALSE);
InflateRect(&rect, 0, B_EDGE);
//If the mouse is in any custom button, then
//We need to override the default behaviour.
if(PtInRect(&rect, pt))
{
return HTBORDER;
}
}
}
return ret;
}
//
// If hBitmap is MONOCHROME then
// whites will be drawn transparently,
// blacks will be drawn normally
// So, it will look just like a caption button
//
// If hBitmap is > 2 colours, then no transparent
// drawing will take place....i.e. DIY!
//
static void CenterBitmap(HDC hdc, RECT *rc, HBITMAP hBitmap)
{
BITMAP bm;
int cx;
int cy;
HDC memdc;
HBITMAP hOldBM;
RECT rcDest = *rc;
POINT p;
SIZE delta;
COLORREF colorOld;
if(hBitmap == NULL)
return;
// center bitmap in caller's rectangle
GetObject(hBitmap, sizeof bm, &bm);
cx = bm.bmWidth;
cy = bm.bmHeight;
delta.cx = (rc->right-rc->left - cx) / 2;
delta.cy = (rc->bottom-rc->top - cy) / 2;
if(rc->right-rc->left > cx)
{
SetRect(&rcDest, rc->left+delta.cx, rc->top + delta.cy, 0, 0);
rcDest.right = rcDest.left + cx;
rcDest.bottom = rcDest.top + cy;
p.x = 0;
p.y = 0;
}
else
{
p.x = -delta.cx;
p.y = -delta.cy;
}
// select checkmark into memory DC
memdc = CreateCompatibleDC(hdc);
hOldBM = (HBITMAP)SelectObject(memdc, hBitmap);
// set BG color based on selected state
colorOld = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
BitBlt(hdc, rcDest.left, rcDest.top, rcDest.right-rcDest.left,
rcDest.bottom-rcDest.top, memdc, p.x, p.y, SRCCOPY);
// restore
SetBkColor(hdc, colorOld);
SelectObject(memdc, hOldBM);
DeleteDC(memdc);
}
static LRESULT Caption_NCPaint(CustomCaption *ctp, HWND hwnd, HRGN
hrgn)
{
RECT rect, rect1;
BOOL fRegionOwner = FALSE;
int i;
HDC hdc;
UINT uButType;
int x, y;
HRGN hrgn1;
GetWindowRect(hwnd, &rect);
x = rect.left;
y = rect.top;
hdc= GetWindowDC(hwnd);
// Draw buttons in a loop
for(i = 0; i < ctp->nNumButtons; i++)
{
//Get Button rect in window coords
GetButtonRect(ctp, hwnd, i, &rect1, TRUE);
if(ctp->buttons[i].hBmp)
uButType = DFCS_BUTTONPUSH;
else
uButType = DFCS_BUTTONPUSH;
if(ctp->buttons[i].fPressed)
DrawFrameControl(hdc, &rect1, DFC_BUTTON, uButType | DFCS_PUSHED);
//DrawFrameControl(hdc, &rect1, DFC_CAPTION, DFCS_CAPTIONRESTORE |
DFCS_PUSHED);
else
DrawFrameControl(hdc, &rect1, DFC_BUTTON, uButType);
//DrawFrameControl(hdc, &rect1, DFC_CAPTION, DFCS_CAPTIONRESTORE);
//Now draw the bitmap!
InflateRect(&rect1, -2, -2);
rect1.right--;
rect1.bottom--;
if(ctp->buttons[i].fPressed)
OffsetRect(&rect1, 1, 1);
CenterBitmap(hdc, &rect1, ctp->buttons[i].hBmp);
}
ReleaseDC(hwnd, hdc);
if(fRegionOwner)
DeleteObject(hrgn);
return 0;
}
//
// This is a generic message handler used by WM_SETTEXT and
WM_NCACTIVATE.
// It works by turning off the WS_VISIBLE style, calling
// the original window procedure, then turning WS_VISIBLE back on.
//
// This prevents the original wndproc from redrawing the caption.
// Last of all, we paint the caption ourselves with the inserted
buttons
//
static LRESULT Caption_Wrapper(CustomCaption *ctp, HWND hwnd, UINT
msg, WPARAM wParam, LPARAM lParam)
{
UINT ret;
DWORD dwStyle;
dwStyle = GetWindowLong(hwnd, GWL_STYLE);
//Turn OFF WS_VISIBLE, so that WM_NCACTIVATE does not
//paint our window caption...
SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_VISIBLE);
Are you sure this has any effect? Generally, the only way you can manipulate this bit is
by using ShowWindow(SW_SHOW / SW_HIDE).
****
****
//Do the default thing..
ret = CallWindowProc(ctp->wpOldProc, hwnd, msg, wParam, lParam);
//Restore the original style
SetWindowLong(hwnd, GWL_STYLE, dwStyle);
//Paint the whole window frame + caption
Caption_NCPaint(ctp, hwnd, (HRGN)1);
return ret;
}
static LRESULT Caption_NCActivate(CustomCaption *ctp, HWND hwnd,
WPARAM wParam, LPARAM lParam)
{
return Caption_Wrapper(ctp, hwnd, WM_NCACTIVATE, wParam, lParam);
}
//static LRESULT Caption_SetText(CustomCaption *ctp, HWND hwnd, WPARAM
wParam, LPARAM lParam)
//{
// return Caption_Wrapper(ctp, hwnd, WM_SETTEXT, wParam, lParam);
//}
//
////
//// NonClient Left Button Down.
//// Mouse is in screen coordinates
////
//static LRESULT Caption_NCLButtonDown(CustomCaption *ctp, HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam)
//{
// int i;
// RECT rect;
// POINT pt;
//
// pt.x = (short)LOWORD(lParam);
// pt.y = (short)HIWORD(lParam);
//
// //If mouse has been clicked in caption
// //(Note: the NCHITTEST handler changes HTCAPTION to HTBORDER
// // if we are over an inserted button)
// if(wParam == HTBORDER)
// {
// for(i = 0; i < ctp->nNumButtons; i++)
// {
// GetButtonRect(ctp, hwnd, i, &rect, FALSE);
// InflateRect(&rect, 0, 2);
//
// //if clicked in a custom button
// if(PtInRect(&rect, pt))
// {
// ctp->iActiveButton = i;
// ctp->buttons[i].fPressed = TRUE;
// ctp->fMouseDown = TRUE;
//
// SetCapture(hwnd);
//
// RedrawNC(hwnd);
//
// return 0;
// }
// }
// }
//
// return CallWindowProc(ctp->wpOldProc, hwnd, msg, wParam, lParam);
//}
//
////
//// Left-button UP. Coords are CLIENT relative
////
//static LRESULT Caption_LButtonUp(CustomCaption *ctp, HWND hwnd,
WPARAM wParam, LPARAM lParam)
//{
// RECT rect;
// POINT pt;
//
// pt.x = (short)LOWORD(lParam);
// pt.y = (short)HIWORD(lParam);
// ClientToScreen(hwnd, &pt);
//
// if(ctp->fMouseDown)
// {
// ReleaseCapture();
//
// GetButtonRect(ctp, hwnd, ctp->iActiveButton, &rect, FALSE);
// InflateRect(&rect, 0, 2);
//
// //if clicked in a custom button
// if(PtInRect(&rect, pt))
// {
// UINT uCmd = ctp->buttons[ctp->iActiveButton].uCmd;
// SendMessage(hwnd, WM_COMMAND, uCmd, MAKELPARAM(pt.x, pt.y));
// }
//
// ctp->buttons[ctp->iActiveButton].fPressed = FALSE;
// ctp->fMouseDown = FALSE;
//
// RedrawNC(hwnd);
//
// return 0;
// }
//
// return CallWindowProc(ctp->wpOldProc, hwnd, WM_LBUTTONUP, wParam,
lParam);
//}
//
//static LRESULT Caption_MouseMove(CustomCaption *ctp, HWND hwnd,
WPARAM wParam, LPARAM lParam)
//{
// RECT rect;
// POINT pt;
// BOOL fPressed;
//
// pt.x = (short)LOWORD(lParam);
// pt.y = (short)HIWORD(lParam);
// ClientToScreen(hwnd, &pt);
//
// if(ctp->fMouseDown)
// {
// GetButtonRect(ctp, hwnd, ctp->iActiveButton, &rect, FALSE);
// InflateRect(&rect, 0, 2);
//
// fPressed = PtInRect(&rect, pt);
//
// if(fPressed != ctp->buttons[ctp->iActiveButton].fPressed)
// {
// ctp->buttons[ctp->iActiveButton].fPressed ^= 1;
// RedrawNC(hwnd);
// }
//
// return 0;
// }
//
// return CallWindowProc(ctp->wpOldProc, hwnd, WM_MOUSEMOVE, wParam,
lParam);
//}
//Replacement window procedure
static LRESULT CALLBACK NewWndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
CustomCaption *ctp = GetCustomCaption(hwnd);
WNDPROC oldproc = ctp->wpOldProc;
switch(msg)
{
//clean up when window is destroyed
case WM_DESTROY:
HeapFree(GetProcessHeap(), 0, ctp);
break;
case WM_ACTIVATE:
return Caption_NCActivate(ctp, hwnd, wParam, lParam);
case WM_PAINT:
return Caption_NCPaint(ctp, hwnd, (HRGN)wParam);
Why are you painting the nonclient area when the CLIENT area wants repainting? Wouldn't
it make more sense to handle this on a WM_NCPAINT?
****
}****
//call the old window procedure
return CallWindowProc(oldproc, hwnd, msg, wParam, lParam);
}
//
// Insert a button into specified window's titlebar
//
BOOL WINAPI Caption_InsertButton(HWND hwnd, UINT uCmd, int nBorder,
HBITMAP hBmp)
{
CustomCaption *ctp = GetCustomCaption(hwnd);
int idx;
// If this window doesn't have any buttons yet,
// then perform the subclass and allocate structures etc.
if(ctp == 0)
Why did you compare it to 0? It shoud be
if(ctp == NULL)
pointers should never be compared to 0 because this makes them look as if they are
integers
****
{****
//allocate memory for our subclass information
ctp = HeapAlloc(GetProcessHeap(), 0, sizeof(CustomCaption));
HeapAlloc is a bit odd here; what's wrong with malloc()?
****
****
ctp->nNumButtons = 0;
ctp->fMouseDown = FALSE;
//assign this to the window in question
SetProp(hwnd, szPropName, (HANDLE)ctp);
//subclass the window
ctp->wpOldProc = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)
NewWndProc);
}
idx = ctp->nNumButtons++;
ctp->buttons[idx].hBmp = hBmp;
ctp->buttons[idx].nRightBorder = nBorder;
ctp->buttons[idx].uCmd = uCmd;
ctp->buttons[idx].fPressed = FALSE;
return TRUE;
}
//
// Remove the last inserted button from window's titlebar
//
BOOL WINAPI Caption_RemoveButton(HWND hwnd)
{
CustomCaption *ctp = GetCustomCaption(hwnd);
if(ctp == 0)
return FALSE;
if(ctp->nNumButtons > 0)
{
ctp->nNumButtons--;
RedrawNC(hwnd);
}
return TRUE;
}
//This is the dllmain.c which conatins hook proc for active window
/
******************************************************************************
Window hook function
******************************************************************************/
#include "../shared.h"
#include "common.h"
#include <winuser.h>
That's
#include <windows.h>
you do NOT include random subcomponents of windows.h by themselves! ANd have you hread of
"precompiled headers" or do you enjoy unnecessarily long compilation times?
****
#include "resource.h"****
#include "CaptionButton.h"
__declspec( dllexport ) CALLBACK CallWndRetProc( int code, WPARAM wp,
LPARAM lp )
If you put the setHook call in the DLL, you don't need to export this function at all!
Nobody outside this DLL should know it exists!
****
{****
DWORD style;
HDC hdc;
UINT uButType;
RECT rect1;
LONG AppOrigExStyle;
if( code == HC_ACTION )
{
const CWPRETSTRUCT* cwp = (CWPRETSTRUCT*)lp;
switch( cwp->message )
{
case WM_ACTIVATE:
if( LOWORD( cwp->wParam ) != WA_INACTIVE )
{
/* Change the window styles to hide the media player from the task
bar:
need to hide the window before making the change and then make it
visible again - works for Winamp and Windows Media Player but
those windows have custom title bars - this might do weird things
where the window has a more normal title bar... */
//ShowWindow( PositionerWindow, SW_HIDE );
AppOrigExStyle = GetWindowLong( PositionerWindow, GWL_EXSTYLE );
SetWindowLong( PositionerWindow, GWL_EXSTYLE, ( AppOrigExStyle &
~WS_EX_APPWINDOW ) );
SetWindowPos(PositionerWindow,HWND_TOP, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOSENDCHANGING |
SWP_NOSIZE | SWP_ASYNCWINDOWPOS |
SWP_NOOWNERZORDER| SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow( PositionerWindow, SW_SHOW );
PostMessage( PositionerWindow, UPDATE_MSG, (WPARAM)cwp->hwnd, 1 );
LOG((_T("in activate")));
}
else
{
ShowWindow( PositionerWindow, SW_HIDE );
}
break;
case WM_WINDOWPOSCHANGED:
if( cwp->hwnd == MostRecentWindow )
{
/* Change the window styles to hide the media player from the task
bar:
need to hide the window before making the change and then make
it
visible again - works for Winamp and Windows Media Player but
those windows have custom title bars - this might do weird
things
where the window has a more normal title bar... */
AppOrigExStyle = GetWindowLong( PositionerWindow, GWL_EXSTYLE );
SetWindowLong( PositionerWindow, GWL_EXSTYLE, ( AppOrigExStyle &
~WS_EX_APPWINDOW ) );
SetWindowPos(PositionerWindow,HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE |
SWP_NOCOPYBITS | SWP_NOSENDCHANGING |
SWP_NOSIZE | SWP_ASYNCWINDOWPOS |
SWP_NOOWNERZORDER| SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow( PositionerWindow, SW_SHOW );
PostMessage( PositionerWindow, UPDATE_MSG, (WPARAM)cwp->hwnd, 2 );
LOG((_T("in positionchanged")));
}
break;
} /* end switch message */
} /* end if action */
return CallNextHookEx( PrevHook, code, wp, lp );
}
/* Remove whinges about unused variable "reserved" */
#pragma warning( disable : 4100 )
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
static HANDLE shared;
switch( reason )
{
case DLL_PROCESS_ATTACH:
/* Save a little bit of time by getting rid of thread
notifications since
I don't need them */
DisableThreadLibraryCalls( hinst );
/* Get read access to the shared memory block */
shared = OpenFileMapping( FILE_MAP_READ, FALSE,
SHARED_DATA_NAME );
if( shared )
SharedData = (SHARED_DATA*)MapViewOfFile( shared,
FILE_MAP_READ, 0, 0, sizeof( SHARED_DATA ) );
else
SharedData = NULL;
if( !SharedData )
return FALSE;
Why are you creating a complicated shared-data file when there is an ABSOLUTELY TRIVIAL
solution to this problem? Just create a shared data segment:
#pragma data_seg("shared")
SHARED_DATA data = { 0 };
#pragma data_seg()
#pragma comment(linker, "/SECTION:shared,rws")
That's all you need, it is done for you. Put accessor functions in your DLL to return
values or return a pointer to the structure. Get rid of all that shared file stuff!
Note that it is generally bad practice to return FALSE from DllMain:DLL_PROCESS_ATTACH,
because this causes the DLL to fail to load properly.
Also, I'm curious why in one place you compare a pointer to an integer, and in this case
you test a pointer as if it is a boolean? Would it not be better to say
if(SharedData == NULL)
which makes it very clear that SharedData is *not* a boolean, but a pointer?
*****
break;****
case DLL_PROCESS_DETACH:
/* I really ought to close the shared memory section here, but
that
seems to cause MMC to crash - at least, not closing it here
makes MMC
*not* crash on exit, and seems to cause no other problems...
*/
//if( SharedData )
// UnmapViewOfFile( SharedData );
//if( shared )
// CloseHandle( shared );
It causes a problem because your code is ill-structured and has the DLL and executable
sharing the same section. Get rid of all of this. Shared memory-mapped files when the
size is compile-time-constant is pointless.
*****
break;.
} /* end switch on reason */
return TRUE;
}
/
*****************************************************************************/
Thanks & Regards
Varsha
- References:
- How add buton onto title bar of any external active window?
- From: varsh211
- How add buton onto title bar of any external active window?
- Prev by Date: Re: CreateDC() problem with printer drivers on Windows Server 200x
- Next by Date: How to determine the size of a character?
- Previous by thread: How add buton onto title bar of any external active window?
- Next by thread: How to determine the size of a character?
- Index(es):