In gui app there is ON_MESSAGE(id, handler) with hanler's LRESULT CMainFrame::handler(WPARAM wParam, LPARAM lParam) declaration.
Well, visial studio doesn't want to get such handler in ON_COMMAND(). What can I do to use the same hanler in ON_MESSAGE and in ON_COMMAND?
Thanks in advance.
as you noticed the handlers need different declarations to work for the ON_MESSAGE and the ON_COMMAND so you can't have the same function for both ON_COMMAND and ON_MESSAGE.
you will have to create one function for each handler and then you can encapsulate your code into another function that is called from the first handlers.
like:
BEGIN_MESSAGE_MAP(CMyClass, CMyParentClass)
//{{AFX_MSG_MAP(CMyClass)
ON_MESSAGE(ID_MY_MESSAGE_ID,OnMyMessage)
ON_COMMAND(ID_MY_COMMAND_ID,OnMyCommand)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
LRESULT CMyClass::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
MyEncapsulatedCode();
return 0;
}
void CMyClass::OnMyCommand()
{
MyEncapsulatedCode();
}
void CMyClass::MyEncapsulatedCode()
{
//do stuff
}
Related
I'm trying to clean up some existing win32 UI code by putting it into a class. Previously I had an AppDlgProc function like this:
BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { ... }
Which I used like so:
DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, AppDlgProc, 0);
Now I'm putting all this in a SettingsWindow object, and I call settingsWindow->show() which kicks off this:
void SettingsWindow::show(HINSTANCE hInstance) {
DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, &SettingsWindow::AppDlgProc, 0);
}
I'm pretty sure I'm giving the callback method incorrectly here. Visual Studio tells me "Intellisense: Argument of type ... is incompatible with parameter of type DLGPROC". Googling seems to tell me seems to tell me I need another argument - is there no other way?
For reference, my AppDlgProc function now looks like this:
BOOL CALLBACK SettingsWindow::AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { ... }
Window and dialog procedures (and other Win32 callback functions) need to be static or global functions - they can't be non-static class functions. Win32 is fundamentally a C-based API and it has no concept of the hidden this pointer that class functions require.
The normal way to do this is to declare the function as static and store a pointer to the class instance in a window property. For example,
struct SettingsWindow
{
// static wrapper that manages the "this" pointer
static INT_PTR CALLBACK AppDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_INITDIALOG)
SetProp(hWnd, L"my_class_data", (HANDLE)lParam);
else
if (uMsg == WM_NCDESTROY)
RemoveProp(hWnd, L"my_class_data");
SettingsWindow* pThis = (SettingsWindow*)GetProp(hWnd, L"my_class_data");
return pThis ? pThis->AppDlgFunc(hWnd, uMsg, wParam, lParam) : FALSE;
}
INT_PTR AppDlgFunc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// the real dialog procedure goes in here
}
};
// to show the dialog - pass "this" as the dialog parameter
DialogBoxParam(hInstance, (LPCTSTR)IDD_SETTINGS, 0, SettingsWindow::AppDlgProc,
(LPARAM)this);
Recently, I've started to learn DX11 and I was trying to create message loops in WinAPI. I saw a LRESULT CALLBACK function from the tutorial that I haven't seen before. It is called in Window Procedure function. Here is the WndProc function and the MessageHandler function(the function that I'm talking about).
WndProc:
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch(umessage)
{
// Check if the window is being destroyed.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
// All other messages pass to the message handler in the system class.
default:
{
return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
MessageHandler:
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch(umsg)
{
// Check if a key has been pressed on the keyboard.
case WM_KEYDOWN:
{
// If a key is pressed send it to the input object so it can record that state.
m_Input->KeyDown((unsigned int)wparam);
return 0;
}
// Check if a key has been released on the keyboard.
case WM_KEYUP:
{
// If a key is released then send it to the input object so it can unset the state for that key.
m_Input->KeyUp((unsigned int)wparam);
return 0;
}
// Any other messages send to the default message handler as our application won't make use of them.
default:
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}
}
What I don't understand is, why we added the "LRESULT CALLBACK" part to the MessageHandler function? I know, we must add it to WndProc function, but I don't get the point of creating a new function and adding it a calling convention. What if we don't add any calling convention to the MessageHandler function? What if we didn't create the MessageHandler funciton and write the KEY_DOWN listeners to WndProc's switch-case statement?
These codes are in one class and ApplicationHandler pointer points to "this".
There is no obvious reason for SystemClass::MessageHandler to be declared as CALLBACK because it cannot be used as a message handler for Windows since it is not static. There is no reason for SystemClass::MessageHandler to be declared as CALLBACK in the code you showed.
About the CALLBACK (__stdcall):
Functions called from "within Windows" just have to be stdcall because Windows developers decided to write/compile Windows that it calls stdcall functions. In theory, any CC could be used, but Windows and your code must have the same.
Your own function won´t need it if you´re using it only in your own code in your program.
LRESULT (some int/pointer-like thing) is just the return type.
The reason for not just writing int (or something like that) is that LRESULT is a int with a certain length etc., and if MS decides to change it for some reason, they only need to change the definition of LRESULT, but not every function which has a LRESULT return type.
I have a problem with attaching a windows procedure to a window.
I have a baseclass called BaseWindow, that uses GWPL_USERDATA to call a virtual function called HandleMessage() of the child classes.
However, if i try to change the window procedure without creating a custom Window Class, it gives a type error from the child procedure to long.
Here's the code:
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BaseWindow *pThis = NULL;
if (uMsg == WM_NCCREATE)
{
CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
pThis = (BaseWindow*)pCreate->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->m_hwnd = hwnd;
}
else
{
pThis = (BaseWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (pThis)
{
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{return 0;};
PlayList Class : BaseWindow
SetWindowLong(m_hwnd, GWL_WNDPROC,(long) HandleMessage); //Error
LRESULT PlayList::HandleMessage(UINT message,WPARAM wParam,LPARAM lParam) //Need to attach this window procedure
{}
It works if the child procedure is static, however I use non static members in that procedure.
I want to subclass a common control, while using this base class (because a lot of code is redundant), is it possible?
Here's the whole code for the base class: http://pastebin.com/ME8ks7XK
The compiler doesn't like your declaration for HandleMessage, it isn't static. It's missing CALLBACK too, not good.
Not sure why you are trying to do this, the whole point of your WindowProc() function is to get the message forwarded to a virtual HandleMessage() method. At best you'd use WindowProc in your SetWindowLong() call instead of HandleMesssage. Or just specify it directly in the CreateWindowEx() call.
From MSDN:
An application subclasses an instance of a window by using the SetWindowLong function. The application passes the GWL_WNDPROC flag, the handle to the window to subclass, and the address of the subclass procedure to SetWindowLong. The subclass procedure can reside in either the application's executable or a DLL.
So, you should write this:
SetWindowLong(m_hwnd, GWL_WNDPROC,(long) & HandleMessage);
But this doesn't compile again! the reason: all non-static member functions have hidden this parameter (pointer to owner class). So, you HandleMessage doesn't fit the WindowProc declaration.
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)
{ ... }
};
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.