I need to redraw NC area of the window and set custom text in there. So with redrawing I'm okay, but I don't know what should I use to set my own text in caption of the window. I tried to use DefWindowProc function, but it suddenly draws default windows title bar, which is unnecessarily. Using SetWindowText also is inappropriate, because it causes WM_SETTEXT message once again. So help me, please, I need just to customize caption of window without any drawing default title bar.
LRESULT SkinWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
...
case WM_SETTEXT:
OnSetText(hWnd, wParam, lParam);
break;
...
}
void SkinWindow::OnSetText(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
DefWindowProc(hWnd, WM_SETTEXT, wParam, lParam);
OnNcPaint(hWnd, wParam, lParam);
}
You must fully handle the two gettext messages:
case WM_GETTEXT:
lstrcpyn((LPTSTR)lParam, "Booga!", (int)wParam);
return lstrlen((LPTSTR)lParam);
case WM_GETTEXTLENGTH:
return 7; // lstrlen("Booga!") + null
If you want WM_SETTEXT to work correctly you must store the text in you own buffer and use that buffer when queried for the text. Never pass these to DefWindowProc because DefWindowProc stores/retrieves the text internally in the HWND.
Note: External applications will still read it incorrectly if they use GetWindowText because it reads from the hidden internal storage when sent cross-process.
Related
It definetly works, but in a strange way.
I'm replacing RichEdit control's procedure with
WNDPROC g_OrigREditText =
(WNDPROC)SetWindowLongPtr( g_hwnd_RichEdit, GWLP_WNDPROC, (LONG_PTR)REditWndProc);
Then, I SendMessage to RichEdit control using EM_REPLACESEL msg, and the text appears in the RichEdit control as it should. But when I replace standard procedure with my own, and process EM_REPLACESEL in mine own procedure, then the following scenario happens. Here's the code:
LRESULT CALLBACK REditWndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
switch( msg )
{
case EM_REPLACESEL:
{
int sdfsdf = 0;
CallWindowProc( (WNDPROC)g_OrigREditText, hwnd, msg, wp, lp );
break;
}
default:
return DefWindowProc( hwnd, msg, wp, lp);
break;
}
return 0;
}
Ok, I send an EM_REPLACESEL message to the RichEdit as usual and it works well, cos I catch operation pointer in "case EM_REPLACESEL" block.
Then CallWindowProc should do its job by passing parameters to the next procedure in the chain, but instead nothing happens, the text doesn't appear in a RichEdit control. Looks like something prevent the message to be passed to old procedure, but! if I replace g_OrigREditText with REditWndProc, then I catch the same UINT msg again, so it definetely pass parameters further, like it should.
So what's wrong with CallWindowProc or with my code, where should I dig to fix the problem?
The whole thing is called "subclassing" and this can be useful .
usually there are more events that occurs in relating with one message so change your code to this
LRESULT CALLBACK REditWndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
if( msg == EM_REPLACESEL)
{
// whatever you want
return TRUE;// comment this
// if you want to give it to the original proc.
}
return CallWindowProc( g_OrigREditText, hwnd, msg, wp, lp );
}
I'm trying to change the text color whenever i receive WM_CTLCOLORSTATIC.
LRESULT ProcessWindowMessage(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_CTLCOLORSTATIC:
::SetTextColor((HDC)wParam, RGB(m_color.red, m_color.green, m_color.blue));
::SetBkMode((HDC)wParam, TRANSPARENT);
return (LRESULT)GetStockObject(DKGRAY_BRUSH);
}
return m_orgWndProc(hWnd, uMsg, wParam, lParam);
}
As you can see, the color of 'Just a test' was changed, but with it, the background of the entire box was also changed.
I've tried returning almost all GetStockObject() combinations including
return (LRESULT)GetStockObject(COLOR_BACKGROUND + number)
&
GetCurrentObject((HDC)wparam,OBJ_BRUSH)
I've to say, that these commands manipulated the color of the background somehow, but never matched the default gray value used to be.
what am i missing here?
You didn't try
return (LRESULT)GetStockObject(NULL_BRUSH);
As Mark Ransom commented, that would not erase the background if you set the new text.
You should use:
return (LRESULT)GetSysColorBrush(CTLCOLOR_DLG);
as was suggested earlier.
I need to get the current WndProc with its messages and configuration and add my own code to it. Why do I need this? Because I'm working under an IDE that defines a window (and its children controls) with a WndProc, and I need to modify it because It contains all the actions related with every control. If I point a control to a custom WndProc the control loses all the actions and configuration set by the IDE. Suggestions?
Scheme:
HWND button; //My Button
LONG_PTR wndProc = GetWindowLongPtr(button, GWL_WNDPROC); //Getting the WndProc
wndProc -> Get this `WndProc` source code
LRESULT CALLBACK WndProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
wndProc (all the data);
+ my messages
}
You can't get source code of "old" WndProc of course, but you can call it using CallWindowProc() in your new wnd proc. Check out this article:
When you subclass a window, it's the original window procedure of the window you subclass you have to call when you want to call the original window procedure
Quote:
... your subclass function should go something like this:
wndProcOrig =
(WNDPROC)SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)SubclassWndProc);
LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
{
switch (wm) {
...
default:
return CallWindowProc(wndprocOrig, hwnd, wm, wParam, lParam);
}
}
Okay, I have a ListView and I've just worked out how to manually set it's Callback procedure:
// Sets the list view procedure
listproc = (D_ListView *) LocalAlloc(LMEM_FIXED, sizeof(D_ListView));
listproc->oldproc = (WNDPROC)SetWindowLongPtr(g_hList, GWL_WNDPROC, (LONG)&ListViewProc);
SetWindowLongPtr(g_hList, GWL_USERDATA, (LONG)&listproc);
I used a code example I found - D_ListView is just a struct with a WNDPROC variable called oldproc.
Anyhow, I'm sending messages to my ListView to add items. But I don't want to handle the ADD messages manually, I want to pass them onto the ListView's default procedure, and only handle messages that I need to over-ride the functionality for.
LRESULT CALLBACK ListViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
// Just a test - we're getting this message so it worked
case LVM_INSERTCOLUMN:
{
cout << "CREATED" << endl;
}
}
WNDPROC* wp;
wp = (WNDPROC*)(::GetWindowLongPtr(hwnd, GWL_WNDPROC));
return ::CallWindowProc(*wp, hwnd, msg, wParam, lParam);
}
In the above, I don't want to deal withe LVM_INSERTCOLUMN: I just want to pass it on.
Any one able to help?
Thanks,
Rob
use getWindowLongPtr (...GWL_USERDATA) to get the pointer to your D_ListView instance and then forward any unwanted messages to oldproc
::CallWindowProc(*listproc->oldproc, hwnd, msg, wParam, lParam);
I have been having trouble with my program trying to gray out ( and disable ) a sub menu item.
What I'm looking for is that the "run" item be disabled unless the required .ini entry is not empty.
My code
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HMENU hmenu = GetMenu(hWnd);
// Reading in ini
if (0 == strcmp(webLocation, "")){
EnableMenuItem(hmenu,ID_WEBSERVICES_RUN,MF_DISABLED | MF_GRAYED);
WritePrivateProfileString(_T("WEBSERVICES"), _T("Location"), _T("Tool Not Found"), WpathStr);
}
I am unsure as to whether I am getting the HMENU correctly and why this code is not working for the desired effect.
Any help with this would be greatly appreciated.
You can't just put this in the WndProc at the top level. WndProc process events, whether the window has been constructed or not. It'll be called many times for many different reasons.
Your WndProc will almost certainly look like a big switch on message. The one you want here is WM_INITDIALOG:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
// jump to a new function that reads the .ini
// and disables the control etc.
return OnInitDialog(hWnd, wParam, lParam);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}