I have a dialog box with several comboboxes in it as a member variables. The control wizard lets me create handlers for the comboboxes for the CBN_KILLFOCUS message. For example, one such handler is automatically called
void MyDlg::OnKillfocusMyCombo()
My expectation is that this handler would be called just as soon as I tab out of it. But it doesn't get called.
I ran into the same issue. This is a bug in MFC. (It's over 4 years later and it is still there.) Somehow ON_CBN_KILLFOCUS handler is never called although the Win32 CBN_KILLFOCUS notification itself is broadcast.
To fix this override the WindowProc for the dialog manually (Win32-way):
LRESULT CMyDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
//Fix for the bug in MFC
if(message == WM_COMMAND)
{
if(HIWORD(wParam) == CBN_KILLFOCUS &&
LOWORD(wParam) == Your_ComboBox_ID)
{
OnCbnKillfocusComboBox();
}
}
return CDialog::WindowProc(message, wParam, lParam);
}
Related
How can I detect in an "empty" CMainFrame mouse clicks? With empty I mean a MDI which has not yet any document/view.
I have tried to detect mouse clicks with:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg);
MDI main frame windows have an 'invisible' client window that occupies the client area of the main frame. This window is inaccessible using 'normal' class override techniques but, if that main frame window is derived from either CMDIFrameWnd or CMDIFrameWndEx, you can use its m_hWndMDIClient member (the HWND of that invisible window) to subclass it, by overriding its WindowProc.
I do this (actually, to draw in that client area) in an override of the main frame's UpdateWindow procedure, using a bool member variable (set to false on construction) to keep track of whether or not the subclassing has already been done.
Here's a possible solution (adapted from my own code) that will likely work for intercepting mouse clicks. (I tested it and did actually get the Beep() diagnostic on mouse clicks!)
// Local function pointer to store the 'original' (default) window procedure...
LRESULT (CALLBACK *DefCliPrc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = nullptr;
// Static definition of our override procedure...
static LRESULT CALLBACK ClientProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT answer = DefCliPrc(hWnd, uMsg, wParam, lParam); // First, call default proc.
if (uMsg == WM_LBUTTONDOWN) {
Beep(1000,1000); // Make a sound to show that it's working!
// <Insert your handling code here>
}
//...
// Intercept/handle other messages, as required ...
//...
return answer;
}
// Override of the UpdateWindow function, to enact the subclassing...
void MyMainFrame::UpdateWindow(void)
{
if (!funchange) { // Only do the sub-classing ONCE ...
DefCliPrc = (WNDPROC)(intptr_t)(::GetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC));
::SetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC, (intptr_t)(ClientProc));
funchange = true; // Set this 'flag' to prevent repetition!
}
CMDIFrameWnd::UpdateWindow(); // Should always call base class
return;
}
I think I've fallen in the same trap as many before me where I try to impose a nice OO methodology on win32 API programming. No MFC, no AFX, I'm not even using VC++, I'm using C::B with gcc.
I think what I'm trying to do is impossible, but since MFC exists (although I'm not using it) there must be some way.
I've created a class to contain several window controls. It implements handlers for WM_CREATE and WM_COMMAND, and keeps track of all the associated data around my small group of controls (ID codes and HWNDs).
It works great for buttons, static controls, even light GDI methods, but it all breaks down when I try to subclass an edit control.
Really, I just want to capture the "enter" key, but as anybody who's been down that road before will attest, when an edit control has focus, the parent window doesn't receive WM_KEYDOWN or WM_COMMAND, we are left to implement our own proc. Super lame.
OK, so subclassing an edit control is fine, if the editProc is global or static. I know that is because SetWindowLongPtr needs a function address, and that concept is nebulous for a member function.
So the object of my class is declared as "static" inside the parent WndProc. But the function is not "static" because then I wouldn't have access to non-static data members (completely defeating the purpose of this exercise). I'm hoping that because the objest is itself static, I should be able to properly define the address of one of its member functions.
Readers that have tried this before will either have given up and used MFC or something else, or perhaps have found a clever work-around.
I'll let this sample code do the rest of the talking: (simplified - will not compile as such)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
The header file for my class:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...and the implementation:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
Even once I get this done, I'll still need to figure out a way to pass the address of the parent WndProc to myEditProc for the return value, but until I get past this there is no point in worrying about that.
Thanks in advance for reading!
myEditProc needs to be a static function.
Once you've done that you can pass the address of the function directly without going through the intermediate variable:
static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);
To access your class data from the static function, you can save it in the userdata field of the edit control, e.g.:
// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);
// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);
But as #K-ballo suggested, SetWindowSubclass is definitely the way to do this unless you want compatibility with pre-XP. It handles the sub-classing procedure for you automatically, lets you associate a userdata pointer (e.g. this) that is automatically passed to the sub-class procedure, and safely handles removing the sub-class at the end.
I am trying to handle wm_mousewheel for my application.
Code:
BEGIN_MSG_MAP(DxWindow)
MESSAGE_HANDLER(WM_MOUSEWHEEL, KeyHandler)
END_MSG_MAP()
.
.
.
LRESULT DxWindow::KeyHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if(uMsg==wm_mousewheel)
{
//Perform task.
}
return 0;
}
But this code doesn't work.KeyHandler doesn't receive wm_mousewheel message.
I am testing this application on vista.
If my approach is wrong how to handle wm_mousewheel properly?
Do vista is responsible for failure in handling wm_mousewheel message?
From the doc:
The WM_MOUSEWHEEL message is sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
Change your test to if(uMsg == WM_MOUSEWHEEL).
Check that your window or one of it's children has focus.
If this is related to your previous wtl-child-window-event-handling question, I edited my answer to not forward WM_MOUSEWHEEL.
Well, first, you don't have to somehow check uMsg in message handler, because in this situation every message handler is bound to one concrete message.
Second, these atl macroses usually mean to write something like CHAIN_MSG_MAP(CMyBaseClass)
at the end of your map.
Anyway, what you've posted here looks ok, except this part:
if(uMsg==wm_mousewheel)
{
//Perform task.
}
Try erasing it, adding a breakpoint to the handler and debugging. Also you could try adding another neutral message handler (such as WM_CLICK) and tracing it's behavior.
This is the example from MSDN, and the code block that you've posted actually follows it.
class CMyWindow : ...
{
public:
...
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
CHAIN_MSG_MAP(CMyBaseWindow)
END_MSG_MAP()
LRESULT OnPaint(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{ ... }
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{ ... }
};
I'm writing a win32 wrapper classes, mainly to learn more about win32 programming.
To get around the problem of c-style callbacks, the following method stores/retrieves the pointer using SetWindowLong/GetWindowLong and passes it to the actual winproc.
LRESULT CALLBACK WinClass::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// On window creation, WindowProc receives lParam as a LPCREATESTRUCT
// Store *this* pointer as long in GWL_USERDATA
if (msg == WM_NCCREATE)
::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams));
// Retrieve the pointer
WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLongPtr(hwnd, GWL_USERDATA));
// Call the actual winproc function
if (wnd)
return wnd->WndProc(hwnd, msg, wParam, lParam);
// Default to DefWindowProc message handler function
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
Winclass is the class wrapping the main window created by CreateWindowEx. The same WindowProc function is part of the MDlgClass wrapping the modal dialog. I'm calling the dialog like this
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(id), hwnd, DialogProc);
If I pass NULL as the hWndParent, the dialog works okay as a modeless dialog but if I pass hwnd, the handle to the main window as hWndParent the dialog works correctly as a modal dialog. However when i close the dialog it doesnt pass control back to the main parent window? Debugging in Visual Studio shows its hanging in the message pump in WinMain.
I thought of using a hashmap to map the pointers but I'd rather do it using GetWindowLong etc. Is this possible? I've tried storing the dialog pointer in DWL_USER but it doesnt help.
Any help would be appreciated, I'm still getting my head around Win32.
EDIT: I'm destroying the dialog using EndDialog
EDIT: I'm storing the pointer in the GWL_USERDATA region of the main window, which is not used by windows and I'm only modifying it in WinClass::WindowProc when the window is first created. If I don't instantiate a dialog class, I know the pointer is being accessed correctly since the application responds to menu commands processed via WindowProc and WM_COMMAND.
You can't use a WindowProc as a DialogProc. Window Procedures call DefWindowProc when they don't handle a message and return a meaningful result when they do.
Dialog Procedures return FALSE when they don't process a message, return TRUE when they DO, (except when they handle WM_INITDIALOG) and, if they have a meaningful result that they need to return from the outer window procedure, that is placed in DWL_MSGRESULT.
When you call the modal dialog box function, DialogBox, it enters a message pumping loop - which does dispatch messages to all windows in the thread so all windows continue to paint and process input - when the dialog is closed (using EndDialog), the DialogBox procedure should return.
When making a class to wrap dialog boxes, the usual method is to pass the 'this' pointer to One of the DialogBoxParam functions - which can be directly extracted from the WM_INITDIALOG message.
How are you closing the window? Are you using DestroyWindow? While the child window is live, the parent window will be disabled.
You're saving a pointer to lpCreateParams. Is it possible that the associated memory block is being freed or otherwise destroyed?
//static method
BOOL CALLBACK WinClass::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Store *this* pointer as long in GWL_USERDATA
if (msg == WM_INITDIALOG)
{
::SetWindowLongPtr(hwnd, DWLP_USER, reinterpret_cast(lParam));
m_hWnd = hWnd; // I assume you really don't want to keep passing the hwnd around
}
WinClass* wnd = reinterpret_cast(::GetWindowLongPtr(hwnd, GWL_USERDATA));
if (wnd)
return wnd->DlgProcImpl(umsg, wParam, lParam);
return FALSE;
}
BOOL WinClass::DlgProcImpl(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// your code goes here
return FALSE;
}
return FALSE;
}
INT_PTR WinClass:DoModalDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR template)
{
return ::DialogBoxParam(hInst, template, hwndParent, WinClass::DlgProc, this);
}
How to go about implementing a user activity logger in MFC application.To get to know what are all the features are used most in an existing application.
You can override the windows procedure of your application window:
class CMyMainWindow {
void LogUsageData(UINT message);
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
LogData(message);
return CWnd::WindowProc(message, wParam, lParam); // route message to message map
}
}
Note that the task is not so trivial: LogUsageData should discard most messages, focusing only on the ones defined in the message map.
However, this should be a good place to start.