When do you use ON_COMMAND and when do we use ON_MESSAGE. What are the differences between them.
ON_COMMAND is specifically used to handle a command message (i.e. WM_COMMAND) like the click of a button/menu item/toolbar button.
ON_MESSAGE is more generic and can be used for any windows message. It is usually used for less frequently handled messages for which specific message map macros have not been provided. You can use ON_MESSAGE to handle ON_COMMAND messages as well but you will have to extract message information (i.e. command ID) yourself.
Example:
See here:
http://msdn.microsoft.com/en-us/library/k35k2bfs(VS.80).aspx
http://msdn.microsoft.com/en-us/library/ms647591(VS.85).aspx
In the message map:
ON_MESSAGE( WM_COMMAND, OnMyCommand )
The handler:
LRESULT CMyWnd::OnMyCommand( WPARAM wParam, LPARAM lParam )
{
// ... Handle message here
int commandId = LOWORD(wParam);
switch(commandId){
case ID_HELLOCOMMAND:
MessageBox(0, "Hello there!", "ID_HELLO_COMMAND", MB_OK);
break;
// ... other commands here
}
return 0L;
}
Disclaimer: Owing to MFC's message pump mechanism, you may have to do a bit more than what's shown above. The best man to ask: Jeff Prosise
Related
About
I am trying to build a custom mouse input for Unity that gets the data directly from the HID. I do this because I want to try if there is any difference (when using my own custom mouse input) to the Unity API that gives me raw mouse input.
Also I need to say that everything I am doing right now does not happen within Unity. I want to build an C++ application and then pass the data to Unity (that's not a part of this question).
This link (MSDN High-Definition Mouse Movement) shows that there are three different types of messages I can use. Due to I need so called "High-Definition Mouse Movement" I need to go with WM_INPUT.
This message can be caught with the WinProc handler as the documentation says. Within that callback the raw mouse data can be accessed. This is what I want to achieve and where I need help.
My current approach
The documentation (link above) gives me this example to register the mouse:
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = gameWindowHandle;
regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
The following two lines were modified by me:
Rid[0].hwndTarget = gameWindowHandle;
There I define the Unity window as target. gameWindowHandle is set by EnumWindows.
The other line I changed is the last one due to there is a syntax error (missing parenthesis).
As far as I understood the documentation right this should be it. Now the following callback should be called when there are WM_INPUT messages sent to the Unity window.
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
) {
printf("%d", uMsg);
switch (uMsg) {
case WM_INPUT:
UINT dwSize = 40;
static BYTE lpb[40];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT,
lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX;
int yPosRelative = raw->data.mouse.lLastY;
printf("X: %d, Y: %d", xPosRelative, yPosRelative);
}
break;
}
return NULL;
}
My problems
The first problem I have is that calling this
regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
does not return true as it should. Instead it returns false and GetLastError gives me error 87 (after googling this I found out it has to do with wrong parameters).
The documentation says to do so but unfortunately it does not work the way I do it.
Another problem is how to keep the application alive. After registering the device I need to wait for the callbacks to trigger (if they would work). How can I achieve that the application does nothing than waiting for the callbacks?
Is my approach even reasonable or am I doing completely wrong and have to use different APIs?
Your approach is wrong. First, RawInput requires Window. A Window under your control with your own WndProc. Hence in your C++ library, you should define a window procedure. Start a thread. In this thread register window class with that procedure. After you succeed in registering your class, create HWND_MESSAGE window, register your devices and enter a while GetMessage... DispatchMessage loop. This should be done in a separate thread. In your window procedure you must now catch WM_INPUT messages. Enjoy.
I would like to know if its possible to specify a WndProc for a Child Window created by CreateWindowEx.
I have created a Window Class, the Main Window, the Window Procedure and a Message Loop already. The code works and I decided to keep it out for the clarity of my question.
This is my Window Proc, so far:
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// Creation of the Win32 Window
case WM_CREATE:
// Add an Edit Field
CreateWindowEx(
WS_EX_CLIENTEDGE,
"EDIT",
"",
WS_CHILD | WS_VISIBLE,
5, 5, 200, 24,
hwnd,
(HMENU)100,
g_Instance, // Comming from WinMain
NULL
);
return DefWindowProc(hwnd, uMsg, lParam, wParam);
case WM_KEYDOWN:
// Track key presses on the edit field
std::cout << "The key with the code " << wParam << " was pressed." << std::endl;
return 0;
case WM_PAINT:
// Some painting code...
return DefWindowProc(hwnd, uMsg, lParam, wParam);
default:
return DefWindowProc(hwnd, uMsg, lParam, wParam);
}
}
I expected key presses on the child Edit Field that I created to throw a WM_KEYDOWN message, but they dont! The keys just get added to the Edit Field in my Window but do not cause a WM_KEYDOWN message.
It seems that the created Edit Window does not use my WndProc. How can I change that?
Your WndProc don't get WM_KEYDOWN messages because, if the user is typing inside the edit control, it means that it has the focus (not your window), so they are sent to the edit control window proc, not yours. However, the edit control window proc will send notifications to your WndProc (his parent window proc).
So, if you only want to react to the user changing the content of your child edit control, you don't need another window procedure. Your current WndProc will receive EN_CHANGE notification code through a WM_COMMAND message.
See https://msdn.microsoft.com/en-us/library/windows/desktop/bb761676(v=vs.85).aspx
If you really want to catch WM_KEYDOWN messages, you need to subclass the edit control, like this:
OldWndProc = (WNDPROC)SetWindowLongPtr (hButton, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
You also need to define a new windows procedure (the NewWndProc), that should handle WM_KEYDOWN message (and any other message you want to handle). You also need to call OldWndProc as you would call DefWndProc in a standard WndProc, unless you want to prevent the edit control to do its normal processing.
For details on subclassing, see https://msdn.microsoft.com/en-us/library/windows/desktop/bb773183(v=vs.85).aspx
Edit
Responding to OP comment here.
If your window is a dialog box, you should be notified of enter key, in your WndProc:
case WM_COMMAND:
if(wParam == IDOFDEFBUTTON || wParam == IDOK) ...
See https://support2.microsoft.com/Default.aspx?scid=kb;en-us;Q102589
To be honest, I never took the time to understand what a dialog box really is. But if I recall correctly, you can get your window to get theses special notifications by calling IsDialogMessage in your message pump:
if(!IsDialogMessage(hWnd,&msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
For interesting information about IsDialogMessage, see http://blogs.msdn.com/b/oldnewthing/archive/2012/04/16/10293933.aspx
If this doesn't give you enough control, you probably have to subclass the edit control.
Your call to CreateWindowsEx creates a new window with "EDIT" wnd class having its own Window procedure. You need a new WndProc and set it to the newly created window (whose handle is returned by CreateWindowEx) via SetClassLong function
I don't quite understand how this works. So I've made my dialog box.. or boxes. And I don't know how to make them appear in my code. Right now I'm trying to just get them to pop up right when I start my program so I can get a basic understanding of how this works.
switch (message)
{
case WM_CREATE:
HINSTANCE hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
CreateDialog(hInstance, "Whatever", hwnd, ABOUT_DIALOG);
That gives me an error in CreateDialog saying a parameter of type int is incompatible with DLGPROC. I'm assuming that I need to declare my dialog box somewhere?
And If I had a button on my very first start up window, how would I know that the user pressed the button? I'm going to once again assume and say that I need to catch it somewhere in the WM_COMMAND command?
The final parameter, the thing that you pass ABOUT_DIALOG to, needs to be a DLGPROC. That is a function of this form:
INT_PTR CALLBACK DialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
The compiler is telling you that ABOUT_DIALOG is not a function of that form. In fact the compiler tells you that ABOUT_DIALOG is an int which is definitely not the right thing!
To get it up and running with a default do-nothing dialog procedure implement it like this:
INT_PTR CALLBACK DialogProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
return FALSE;
}
The documentation says this:
Typically, the dialog box procedure should return TRUE if it processed the message, and FALSE if it did not. If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response to the message.
So by returning FALSE we are asking for default processing.
Once you have the dialog up and running, you can then fill out the dialog procedure with any functionality that you need.
I have class MyCTreeCtrl and I want to add message handler like:
void MyCTreeCtrl::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
}
What should I write between:
BEGIN_MESSAGE_MAP(MyCTreeCtrl, CTreeCtrl)
END_MESSAGE_MAP()
for creating BEGINDRAG handler.
Can't you advice me some literature about message handling in MFC? Thanks.
You should not deal with message map trying to create handlers yourself. For most messages, wizard is going to add the code for you.
For tree control in the dialog for example, you can select tree control in the resource editor and choose Add Event Handler (There are also other ways of inserting message handler using class view and properties). It is unfortunate that MS named it an event handler while in reality it is notification message handler for control specific notification code; in your case it is TVN_BEGINDRAG.
Wizard inserts appropriate entries into a message map:
ON_NOTIFY(TVN_BEGINDRAG, IDC_TREE_DRAG, &CYourDlg::OnTvnBegindragTreeDrag)
Adds declaration in .h file:
afx_msg void OnTvnBegindragTreeDrag(NMHDR *pNMHDR, LRESULT *pResult);
and implementation (definition) on .cpp file:
void CYourDlg::OnTvnBegindragTreeDrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
In the nutshell:
Message map is the way MFC was design for the flexibility of inserting message handlers. As for any Win32 application, message handler is called from windows procedure; in MFC it is MFC window procedure that all controls are subclassed with.
The message map is the static array of AFX_MSGMAP_ENTRY structures:
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT_PTR nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
MFC window procedure gets this map, search for an entry for specific signature (nSig) and if signature of the entry matches, calls appropriate function (pfn).
Each message entry in the map uses specific macro that expands to this structure.
In your case it is ON_NOTIFY, since message is MW_NOTIFY. You will also notice the notification code TVN_BEGINDRAG.
In case you want to create message entry for a message that is not in the wizard database, or for custom message, you have couple of choices, ON_MESSAGE you can use in following manner:
Macro goes into a message map and declaration and definition that go into header and cpp files.
ON_MESSAGE(WM_CUSTOM_MESSAGE, OnCustomMessage)
LRESULT CTreeCtrlDragSampleDlg::OnCustomMessage(WPARAM wParam, LPARAM lParam)
{
return 0;
}
afx_msg LRESULT OnCustomMessage(WPARAM wParam, LPARAM lParam);
Other choices: ON_COMMAND, ON_CONTROL that map WM_COMMAND messages from window or windows common control.
More info:
http://msdn.microsoft.com/en-us/library/6d1asasd(v=vs.100).aspx for VS 2010
I want to subclass RichEdit in my program (here is c++ code: http://dumpz.org/46182/). _native_log is a hwnd of richedit. At first all works fine and LogWindow::wndProc callback called normal, but if i set some text in RichEdit or click on them LogWindow::wndProc stops work (there no any further calls of it). Is there any thoughts what's i do wrong?
void LogWindow::replaceNativeLog(HWND native_log_handle) {
_native_log = native_log_handle;
SendMessage(_native_log, EM_GETOLEINTERFACE, 0, (LPARAM) &_rich_edit_ole);
_old_wnd_proc = (WNDPROC) SetWindowLongPtr(_native_log, GWLP_WNDPROC, (LONG) &wndProc);
}
LRESULT LogWindow::wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case EM_STREAMIN:
break;
case WM_SETTEXT:
break;
};
return CallWindowProc(_old_wnd_proc, _native_log, Msg, wParam, lParam);
}
Starting with Common Controls version 6 the procedure of subclassing windows has been revised to eliminate the issues with previous versions. In particular it is no longer a problem if a control is subclassed more than once.
A comparison between subclassing pre-v6 Common Controls and the v6 way of doing things can be found at "Subclassing Controls". Instead of calling SetWindowLongPtr to replace the window procedure there is SetWindowSubclass which in addition to replacing the window procedure does all the internal bookkeeping. A consequence of the redesign is that you do not have to store a pointer to the previous window procedure either; if you need to call into the original window procedure there is DefSubclassProc at your disposal.
This of course will only help if all competing clients trying to subclass the a control all agree on using the v6 style subclassing.
Finally, I found the problem. I actually develop a plugin for Miranda IM, and there was another function trying to subclass richedit i want. So there is a kind of conflict between my and that functions. Thanks all for trying to help.