1. 声明:
1. afx_msg void OnPhone(UINT nID);
  1. 消息映射:
BEGIN_MESSAGE_MAP(CMenu2View, CView)
//{{AFX_MSG_MAP(CMenu2View)

//}}AFX_MSG_MAP

ON_COMMAND_RANGE(IDM_PHONE1, IDM_PHONE20, OnPhone)

END_MESSAGE_MAP()
  1. 实现函数:
void CMenu2View::OnPhone(UINT nID)
{
// TODO: Add your command handler code here
CClientDC dc(this);

CString str;
str.Format("nID = %d", nID);
dc.TextOut(0,0,str);
}

===============================================

下面是不对的, release 不通过:

afx_msg  void  OnOutPutStatusButtonUp  (WPARAM wParam, LPARAM lParam);


BEGIN_MESSAGE_MAP(CIOStatue, CDialog)
// {{AFX_MSG_MAP(CIOStatue)
// }}AFX_MSG_MAP
ON_COMMAND_RANGE(IDC_STATIC_OUT1,IDC_STATIC_OUT16,OnOutPutStatusButtonUp)
END_MESSAGE_MAP()
// 注意IDC_STATIC_OUT1,IDC_STATIC_OUT16之间是连续的


void CIOStatue::OnOutPutStatusButtonUp(WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case IDC_STATIC_OUT1:
//代码1
break;
case IDC_STATIC_OUT2:
//代码2
break;

case IDC_STATIC_OUT3:
//
break;
//等
}

}


注释:
当按下IDC_STATIC_OUT1按钮,执行 代码1的程序。
当按下IDC_STATIC_OUT2按钮,执行 代码2的程序。

等等

==========================================================

多个菜单对应一个函数:

1.声明 afx_msg void OnButtonPort();

2.在

BEGIN_MESSAGE_MAP(CXXXDlg, CDialog)
//{{AFX_MSG_MAP(CXXXDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
//这里的IDC_BUTTON_PORT_1和 IDC_BUTTON_START_ALL之间有很多个Button,并且ID连续
ON_COMMAND_RANGE(IDC_BUTTON_PORT_1, IDC_BUTTON_START_ALL, OnButtonPort)
ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()
  1. 实现响应函数 void CXXXDlg::OnButtonPort()

注:此代码DEBUG OK,Relase异常,不可直接参考,且听下面分解:


先MSDN:

Use this macro to map a contiguous range of command IDs to a single message handler function.

ON_COMMAND_RANGE(id1, id2, memberFxn )
Parameters
id1
Command ID at the beginning of a contiguous range of command IDs.
id2
Command ID at the end of a contiguous range of command IDs.
memberFxn
The name of the message-handler function to which the commands are mapped.
Remarks
The range of IDs starts with id1 and ends with id2.
Use
ON_COMMAND_RANGE to map a range of command IDs to one member function.
Use ON_COMMAND to map a single command to a member function. Only one
message-map entry can match a given command ID. That is, you can't map a
command to more than one handler. For more information on mapping
message ranges, see Handlers for Message-Map Ranges.There is no automatic support for message map ranges, so you must place the macro yourself.


如果声明成:

afx_msg void OnCommandMy(WPARAM wParam, LPARAM lParam );​

而不是MSDN建议的:

OnCommandMy(UINT nID);
// 通过switch(nID) case **:进行针对不同菜单进行消息响应.nID就是菜单传入消息的ID号


那么DEBUG下没事, RELEASE下出错.原因如下:

利用VC查看相应的汇编代码发现, 应该是函数调用和返回时栈操作不平衡导致Release版本下出现了内存错误的问题, ON_COMMAND_RANGE在MFC默认的消息响应函数中, 参数只有一个, 如:

#define ON_COMMAND_RANGE(id, idLast, memberFxn) \
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)idLast, AfxSig_vw, \
(AFX_PMSG)(void (AFX_MSG_CALL CCmdTarget::*)(UINT))&memberFxn },
// ON_COMMAND_RANGE(id, idLast, OnFoo) is the same as
// ON_CONTROL_RANGE(0, id, idLast, OnFoo)


函数调用过程中, 会将传入的参数进行压栈操作, 因为MFC默认的传入参数只有一个, 因此调用OnCommandMy时会有系统传入的一个消息参数进行压栈操作. 在函数返回时, 应该进行出栈操作, 并且保证调用完成后栈维持平衡, 否则会出现可能的内存错误.



在DEBUG上没有出现内存错误在于在调用OnCommandMy函数返回时编译器在返回代码处添加了如下的汇编代码:




       pop edi
pop esi
pop ebx
add esp, 48h
cmp ebp, esp
call __chkesp (0041e680)
mov esp, ebp
pop ebp
ret 8(两个参数出栈)

在Release版本下, 就没有了检测栈的操作,

只是简单的下面几句汇编代码完成出栈操作:

      mov esp, ebp
pop ebp
ret 8两个参数出栈)


可以明显看到, Release下出现了栈操作不平衡的情况, 即入栈数小于出栈数, 从而导致栈区地址错误, 当其它函数两次对栈区进行地址访问时就极有可能出现内存错误的现象了

终于明白了,原来是ON_COMMAND_RANGE只能带一个参数,带两个或不带都会异常

所以重新定义

afx_msg void OnButtonPort(UINT nID);

而且此nID就是你点击的按钮ID值,再也不用之前的麻烦代码了

CWnd *pWnd = GetFocus();
int nPortID = pWnd->GetDlgCtrlID() ;

问题解决!