Though I've had plenty of software experience I've not done a great deal of Windows programming. I'm trying to post a WM_USER message from a thread so that it gets picked up in the main UI thread but I'm having some trouble. This is in C++ using VS2010 and MFC.
I've created a message map thus,
#define WM_MYMSG (WM_USER + 77)
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_MESSAGE(WM_MYMSG, DoSomething)
END_MESSAGE_MAP()
Declared the handler function as follows,
afx_msg LRESULT DoSomething(WPARAM wParam, LPARAM lParam);
And written the function body as,
LRESULT CMyApp::DoSomething( WPARAM wParam, LPARAM lParam )
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
CallSomeFunction();
return 0L;
}
As far as I can see this is all in line with what MSDN says as stated here.
http://msdn.microsoft.com/en-gb/library/k35k2bfs(v=vs.100).aspx
However I'm getting an
error C2440: 'static_cast' : cannot convert from 'LRESULT (__cdecl CMyApp::*)(WPARAM,LPARAM)' to 'LRESULT (__cdecl CWnd::* )(WPARAM,LPARAM)'
relating to the line
ON_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
Can anyone let me know what the problem is?
Thanks for reading.
Paul
CMyApp inherits from CWinApp, which inherits from CWinThread. CWinThread user-defined messages take a special macro in their message map for what you want to do:
Change this:
ON_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
To this:
ON_THREAD_MESSAGE(WM_AVATAR_SCALE_MSG, DoSomething)
Assuming DoSomething() is a member of your CMyApp class.
See the documentation on ON_THREAD_MESSAGE() for more information.
THe problem is that the message map expects a function on a CWnd, whereas your class clearly is not a CWnd, either by virtue of actually being such or inheriting from CWnd.
The function expects you to pass a method of CWnd that takes a WPARAM and an LPARAM, but you're passing in a function of CMyApp.
Make the CMyApp class extend off of the CWnd class:
class CMyApp : public CWnd {
// members here
};
edit
If this isn't possible, then you're going to have to find a way to pass in a function of CWnd or any other function of a class that extends off of CWnd with the right parameters and return type.
Related
The general rule of thumb is not to call a virtual function from a constructor because it can lead to unpredictable behavior. So why does it work sometimes?
I recently wrote a couple of base classes with pure virtual functions, and accidentally included an indirect call to those functions in the constructor. I realized my mistake and corrected it, but one of them worked while the other did not.
Here's the definition of the class that worked:
template <typename TWindow>
class dialog_base
{
static INT_PTR CALLBACK dlg_proc_internal
(HWND,
UINT,
WPARAM,
LPARAM);
protected:
dialog_base
(const LPCWSTR templateName,
const HWND parent)
{
CREATESTRUCT create;
create.lpCreateParams = this;
m_hwnd = CreateDialogParam(
hinstance_, templateName, parent, dlg_proc_internal,
reinterpret_cast<LPARAM>(&create));
}
HWND m_hwnd;
virtual INT_PTR CALLBACK dlg_proc
(UINT,
WPARAM,
LPARAM) = 0;
public:
virtual ~dialog_base()
{
DestroyWindow(m_hwnd);
}
HWND GetHandle() const;
void show() const;
};
In this class, the DialogBoxParam function calls dlg_proc_internal, passing the WM_NCCREATE message:
template <typename TWindow>
INT_PTR dialog_base<TWindow>::dlg_proc_internal
(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
dialog_base<TWindow>* pThis;
if (msg == WM_NCCREATE)
{
pThis = static_cast<dialog_base<TWindow>*>(reinterpret_cast<
CREATESTRUCT*>(lParam)->lpCreateParams);
SetLastError(0);
if (!SetWindowLongPtr(
hWnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(pThis)) && GetLastError() != 0)
return 0;
}
else
{
pThis = reinterpret_cast<dialog_base<TWindow>*>(
GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
return pThis
? pThis->dlg_proc(msg, wParam, lParam)
: DefWindowProc(hWnd, msg, wParam, lParam);
}
This function retrieves the pointer passed as the last argument to CreateDialogParam and stores it in the window so that it can be retrieved again in later calls to the function.
It then mistakenly calls the pure virtual function dlg_proc instead of returning -- and appears to work just fine through the constructor of a child class.
I created a different class which was almost identical, except that it called CreateWindowEx instead of CreateDialogParam. The pointer argument was passed in much the same way, and used to call the pure virtual function. This time, it failed as one might expect. So what's the difference between the two situations?
EDIT:
Perhaps I should clarify. I'm not asking "Why can't I call virtual members from a constructor?". I'm asking about why the process of resolving virtual members before the object is constructed can sometimes create situations in which an error does not occur, and the correct function is called.
Calling a virtual function from a constructor has perfectly predictable behavior in C++, just like it has perfectly predictable behavior in .Net and Java. However, it's not the same behavior.
In C++, virtual functions dispatch on the type of the object at the moment of calling. Some other languages will use the intended type of object. Both are viable choices, both have risks, but since this is a C++ question I'll focus on the C++ risk.
In C++, virtual functions can be pure virtual. dlg_proc in the question is such a pure virtual function. These are declared in the base class, but not (necessarily) defined there. Trying to call a function that you did not define is Undefined Behavior. Compilers are entirely free to do whatever they like.
One possible implementation is that a compiler just calls a random other function. This could be remove(filename). It might also be the override from a derived class. But there are a million other possible results, including crashes and hangs. So we don't try to predict what happens, and just say: don't call pure virtual functions from ctors.
Footnote:
You can actually provide a body for a pure virtual function; the language allows it.
CreateDialog...() (and DialogBox...()) does not pass its dwInitParam parameter value to your message procedure via WM_(NC)CREATE. It is passed via WM_INITDIALOG instead, which you are not handling. Only CreateWindow/Ex() passes its lpParam parameter values to the message procedure via WM_(NC)CREATE. This is documented behavior!
But more importantly, you are manually passing a CREATESTRUCT to CreateDialogParam(). That is not necessary, especially since you are not handling that extra CREATESTRUCT in your WM_NCCREATE handler. When the system issues WM_(NC)CREATE to a window, the lParam passed to CreateWindow/Ex() gets wrapped in a system-provided CREATESTRUCT. So, even if CreateDialogParam() were to pass its dwInitParam as the lParam to CreateWindowEx() (which is not documented behavior, BTW), you still wouldn't be obtaining your dialog_base* pointer correctly inside your message procedure, as you are not handling that 2 separate CREATESTRUCTs could be present. So, your code has undefined behavior when using the pThis pointer for any reason, since you are not passing that pointer value into your message procedure correctly.
You need to pass your this pointer directly to CreateDialogParam() without wrapping it, and you need to handle WM_INITDIALOG instead of WM_NCCREATE. Then your virtual method should behave as expected (ie, it will not dispatch to a derived class, since WM_INITDIALOG is being handled within the context of the base class constructor).
Also, DO NOT call DefWindowProc() in your message procedure (or derived overrides) when using CreateDialog...() (or DialogBox...()). This is specifically stated in the DialogProc documentation:
Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages. Unwanted messages are processed internally by the dialog box window procedure.
Try this instead:
template <typename TWindow>
class dialog_base
{
static INT_PTR CALLBACK dlg_proc_internal(HWND, UINT, WPARAM, LPARAM);
protected:
dialog_base(LPCWSTR templateName, HWND parent)
{
m_hwnd = CreateDialogParamW(hinstance_, templateName, parent, dlg_proc_internal, reinterpret_cast<LPARAM>(this));
}
HWND m_hwnd;
virtual INT_PTR CALLBACK dlg_proc(UINT, WPARAM, LPARAM) = 0;
public:
virtual ~dialog_base()
{
DestroyWindow(m_hwnd);
}
HWND GetHandle() const;
void show() const;
};
template <typename TWindow>
INT_PTR dialog_base<TWindow>::dlg_proc_internal (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
dialog_base<TWindow>* pThis;
if (msg == WM_INITDIALOG)
{
pThis = reinterpret_cast<dialog_base<TWindow>*>(lParam);
// you CANT cancel dialog creation here when
// using CreateDialog...(), only when using
// DialogBox...()! So, no point in doing any
// error checking on SetWindowLongPtr()...
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
// no point in trying to call pThis->dlg_proc()
// here since it won't be dispatched to derived
// classes anyway...
return TRUE; // or FALSE, depending on your needs...
}
pThis = reinterpret_cast<dialog_base<TWindow>*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (!pThis) return FALSE;
return pThis->dlg_proc(msg, wParam, lParam);
}
I am currently making a C++ MFC application, and I need a timer to call a function called OnTimer every 30 seconds or so. Right now, I have a class that looks like this:
class CMyApp : public CWinApp
{
// Do some stuff...
DECLARE_MESSAGE_MAP()
BOOL InitInstance()
{
// m_pMainWnd is an object in CWinApp that allows me to render a window
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
// Do some stuff with this window
::SetTimer(NULL, 0, 30000, 0);
}
afx_msg void OnTimer(WPARAM wParam, LPARAM lParam)
{
// I want this function to execute every 30 seconds
// This function manipulates the window
}
}
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_THREAD_MESSAGE(WM_TIMER, OnTimer)
END_MESSAGE_MAP()
CMyApp theApp;
This method does get OnTimer to be called, but not every 30 seconds. In fact, OnTimer seems to get called hundreds of times a minute now. My question is: how do I set my class's timer?
Things I've tried
I've tried changing the user extension from ON_THREAD_MESSAGE to ON_WM_TIMER, to ON_COMMAND, and to ON_MESSAGE. For anything that isn't ON_THREAD_MESSAGE, I get the error
error C2440: 'static_cast' : cannot convert from 'void (__thiscall CMyApp::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'
I'm not sure, but I think SetTimer may be manipulating some CWinApp specific function, while the CWnd SetTimer is not being manipulated, and is set to some default value. I'm pretty much in the dark here though, any help would be appreciated.
ON_THREAD_MESSAGE is for user defined messages, not WM_TIMER
According to SetTimer documentation, the window handle must be valid, and the timer identifier must be non-zero to create a new timer. Example:
::SetTimer(m_pMainWnd->m_hWnd, 1, 30000, NULL);
or
m_pMainWnd->SetTimer(1, 30000, NULL);
The message can be handled in main GUI Window. For example CMainFrame, CMyCMDIFrameWnd, or whatever m_pMainWnd points to.
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_TIMER()
...
END_MESSAGE_MAP()
void CMainFrame::OnTimer(UINT id)
{
TRACE("OnTimer(%d)\n", id);
}
Alternatively you can use NULL for window handle in ::SetTimer but you must supply a call back function:
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
TRACE("TimerProc\n");
}
::SetTimer(NULL, 2, 30000, TimerProc);
I have a custom class derived from CWnd that I would like to post a message to from a worker thread. I am using the PostMessage function to achieve this. The first argument to PostMessage is the HWND type handle to my class, and the next is the message I would like handled. For the first parameter, I generate the handle to my class using GetSafeHwnd() function, and for the second parameter, I use WM_USER+3. Also, I declare a message map inside my class header file, and add an entry for the message handler inside the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP block. However, my handler is not getting called. I have also checked the return value of PostMessage function, it is 1, that means success.
Here is my code :
Inside MyClass.h
class CMyClass : CWnd
{
....
....
public:
void InitHandle();
protected:
afx_msg LRESULT OnMessageReceived(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
}
Inside MyClass.cpp
#define WM_MY_MESSAGE WM_USER+3
HWND handleToMyClassWindow;
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
ON_MESSAGE(WM_MY_MESSAGE, OnMessageReceived)
END_MESSAGE_MAP()
LRESULT CMyClass::OnMessageReceived(WPARAM wParam, LPARAM lParam)
{ .... }
void CMyClass::InitHandle()
{
handleToMyClassWindow = GetSafeHwnd();
}
Inside Worker thread
UINT WorkerThreadFunction(LPVOID pParam )
{
....
PostMessage(handleToMyClassWindow, WM_MY_MESSAGE, NULL, NULL);
....
}
My question is, what are the possible reasons for the OnMessageReceived handler to not be called.
P.S.
I take care that the calling object calls the InitHandle() function.
I tried the same technique with the View class (derived from CView) of my program, and it works there, but fails here.
You cannot post to a window if it has not been created. GetSafeHwnd() will return NULL if you have not actually created a window using your class.
this class is much larger, but i'll just post the offending code.
template<class T>
class BaseWindow : public IWindow
{
typedef void(T::*HandlerPtr)(WPARAM, LPARAM)
public:
LRESULT CALLBACK BaseWindow<T>::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
// various stuff
private:
void AddHandler(long id, HandlerPtr func);
private:
std::map<long, void(T::*)(WPARAM, LPARAM)> m_MessageHandlers;
}
template<class T>
void BaseWindow<T>::AddHandler(long id, HandlerPtr func)
{
m_MessageHandler.insert(std::pair<long, HandlerPtr>(id, func));
}
template<class T>
LRESULT CALLBACK Dapper32::BaseWindow<T>::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if(m_MessageHandlers.count(msg) == 1)
{
auto it = m_MessageHandlers.find(msg);
it->second(wparam, lparam); // <-- error here for all template instantiations
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
Here's a little background. For fun and practice, i'm making a win32 wrapper since it seems like a fun, lengthy project to tackle. After a bit of a deliberation, i decided that i preferred a system of storing message handlers in maps rather than each message getting there own virtual function, or worse even, working with a giant switch statement. What the goal here is, you derive from this BaseWindow class and then the template parameter is that derived class. Something like
class MyWindow : public BaseWindow<MyWindow>
then you make private methods that will handle a specific message, and then call the AddHandler function passing in the message id, and then a pointer to that method. Easy as cake, and i've verified that they are entered into the map correctly. However, in the BaseWindow class, i get the error:
error C2064: term does not evaluate to a function taking 2 arguments
I find this odd because every place i pass around the pointer, the declaration certainly does take two arguments. When i remove the parentheses and arguements to make it look like:
it->second;
it compiles and runs, and of course, none of the handlers are called, but how can it even compile when a function pointer with two parameters is invoked without taking an arguement list? something is fishy and frankly i don't get it. Do any of you brilliant minds have any insight into this?
You need to do this:
(it->second)(wparam, lparam); // note parens
Can't remove the question so i guess i'll exlain how i solved it. got rid of the method pointers altogether, used std::functions in the map, and then used std::bind in the add handler function calls. much easier to work with system and method pointers are harder to store in a map together.
Try this code:
(*this.*(it->second))(wparam , lparam)
A standard window procedure function takes this prototype:
LRESULT CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
When a message such as WM_MOUSEMOVE or WM_CHAR, the WndProc function will receive the window the message originated from, and any extra parameters, which will be with msg and wParam/lParam.
What I have now is a class. Say
class Random
{
public:
void Initialize ();
private:
void Draw ();
HWND hWnd;
friend LRESULT CALLBACK RandomProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
After the hWnd is initialized and created by Initialize (), it will send messages such as WM_LBUTTONDOWN to RandomProc. Once a message is received, I would like RandomProc to use Draw () to redraw the window of the class Random.
The thing is, I will have multiple Random variables, and each will have a window. All the windows will send their messages to RandomProc, and will want it to redraw the corresponding windows of the hWnd. I do not know which random variable sent the message based upon the hWnd parameter nor the msg/wParam/lParam, and so cannot access the appropriate Draw () function and cannot redraw the correct window.
Is there a way to pass a pointer to the class of the window to the Procedure every time a message is sent or is there another way to access the Random class whose hWnd sent the message?
Aren't you looking for the GetWindowLongPtr/SetWindowLongPtr functions?
This function assigns/retrieves arbitrary pointer to/from the window handle. You might assign the pointer to your Random class instance to each window you create. In the RandomProc you just use the GetWindowLongPtr and cast the pointer to Random*.
As Chris says in a comment, use the GWLP_USERDATA attribute to assign the pointer.