vc6.0转vs2017:error C2440: “static_cast”: 无法从“void (__thiscall CMainFrame::* )(WPARAM,LPARAM)...

博客指出从vs2005后对消息检查严格,会出现“static_cast”转换错误。解决办法是将返回类型从void改为LRESULT,函数实现添加return TRUE,参数为(WPARAM,LPARAM)。还提到项目从vc6转到vs2017时,ON_NOTIFY的NMTOOLBAR提示错误,需转换参数类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

错误信息:

error C2440: “static_cast”: 无法从“void (__thiscall CMainFrame::* )(WPARAM,LPARAM)转换为“LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)”

说明:

从vs2005之后,对消息的检查较为严格,所以都会出现此错误,不仅仅是2017

解决办法:

改变返回类型即可:void--->LRESULT,由于返回类型改变,所以函数实现中需要添加 return TRUE;

当然,参数也要是(WPARAM,LPARAM),不管有没有用~

---------------------------20180828更新

补充说明:

将一个项目由vc6转到vs2017下面,ON_NOTIFY的NMTOOLBAR老是提示错误  error C2440: “static_cast” : 无法从“void (__thiscall CMainFrame::* )(NMTOOLBARA *,LRESULT *)”转换为“void (__thiscall CCmdTarget::* )(NMHDR *,LRESULT *)”

解决办法:

根据提示就可以看出来,是函数的参数类型不对,所以需要把 NMTOOLBARA* 转换为 NMHDR *

当然,函数实现里边 pnmh->item 也要改为 ((NMTOOLBARA*)pnmh)->item 进行强制转换

<think>我们正在处理MFC框架中的自定义标签栏实现。用户询问如何触发`CMainFrame::OnMDIChildCreate(CWnd* pChild)`函数。 在MFC中,当创建MDI子窗口时,框架会自动调用该函数。但是,这个函数并不是MFC的标准消息映射函数,因此需要我们自己实现消息路由。 步骤: 1. 首先,我们需要在CMainFrame类中声明该函数。 2. 然后,我们需要在MDI子窗口创建时,从子窗口发送一个自定义消息到主框架,或者重写MDI子窗口的创建过程,以便主框架能够捕获创建事件。 然而,MFC本身并没有直接提供这样的消息。我们可以通过以下方式之一来实现: - 在MDI子窗口的OnCreate函数中,获取主框架指针并调用主框架的自定义函数。 - 使用MFC的消息映射机制,自定义一个消息,并在子窗口创建时发送该消息到主框架。 这里我们采用第一种方法,因为它更直接。 实现示例: 在MainFrm.h中声明函数: ```cpp class CMainFrame : public CMDIFrameWndEx { // ... 其他声明 ... protected: // 声明处理MDI子窗口创建的函数 void OnMDIChildCreate(CWnd* pChild); }; ``` 在MDI子窗口的OnCreate函数中,调用主框架的这个函数: ```cpp int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // 获取主框架指针 CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(AfxGetMainWnd()); if (pMainFrame != nullptr) { pMainFrame->OnMDIChildCreate(this); } return 0; } ``` 但是,如果希望使用MFC的消息映射,我们可以定义一个用户消息: 在MainFrm.h中: ```cpp #define WM_MDICHILD_CREATE (WM_USER + 100) ``` 然后在CMainFrame的消息映射中添加: ```cpp BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx) // ... 其他消息 ... ON_MESSAGE(WM_MDICHILD_CREATE, &CMainFrame::OnMDIChildCreate) END_MESSAGE_MAP() ``` 在MDI子窗口的OnCreate中发送消息: ```cpp int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // 发送消息到主框架 AfxGetMainWnd()->SendMessage(WM_MDICHILD_CREATE, (WPARAM)this); return 0; } ``` 然后,在CMainFrame中实现OnMDIChildCreate函数: ```cpp LRESULT CMainFrame::OnMDIChildCreate(WPARAM wParam, LPARAM lParam) { CWnd* pChild = reinterpret_cast<CWnd*>(wParam); // 处理子窗口创建 // ... 比如将子窗口添加到自定义标签栏 ... return 0; } ``` 注意:使用SendMessage是同步的,会立即处理。如果不需要立即处理,也可以用PostMessage。 但是,根据用户之前的问题,他们正在实现自定义标签栏,所以当MDI子窗口创建时,他们需要将子窗口添加到标签控件中。 因此,我们采用第二种方法(自定义消息)可能更符合MFC的消息机制,避免直接依赖具体的子窗口类。 现在,我们给出完整的修正和实现步骤: 步骤1:在MainFrm.h中定义消息和声明消息处理函数 ```cpp // MainFrm.h class CMainFrame : public CMDIFrameWndEx { // ... 其他代码 ... protected: afx_msg LRESULT OnMDIChildCreate(WPARAM wParam, LPARAM lParam); // ... 其他代码 ... }; ``` 步骤2:在MainFrm.cpp中实现消息映射和函数 ```cpp // MainFrm.cpp BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx) // ... 其他消息映射 ... ON_MESSAGE(WM_MDICHILD_CREATE, &CMainFrame::OnMDIChildCreate) END_MESSAGE_MAP() // 定义消息值 #define WM_MDICHILD_CREATE (WM_USER + 100) LRESULT CMainFrame::OnMDIChildCreate(WPARAM wParam, LPARAM lParam) { CWnd* pChild = reinterpret_cast<CWnd*>(wParam); if (pChild != nullptr) { // 在这里将子窗口添加到标签控件 // 例如:m_wndCustomTabs.AddTab(pChild, _T("New Tab")); } return 0; } ``` 步骤3:在MDI子窗口的OnCreate中发送消息 ```cpp // ChildFrm.cpp int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // 发送自定义消息给主框架 AfxGetMainWnd()->SendMessage(WM_MDICHILD_CREATE, (WPARAM)this, 0); return 0; } ``` 这样,每当一个MDI子窗口被创建时,就会触发CMainFrame::OnMDIChildCreate函数。 注意:如果子窗口在创建时还没有完全初始化,可能需要考虑在OnCreate之后发送消息,或者使用PostMessage以确保子窗口已经完全创建。 另外,还需要处理子窗口的销毁事件,以便从标签栏中移除对应的标签。 因此,我们可以类似地处理WM_MDICHILD_DESTROY消息。 总结:通过自定义消息,我们可以实现MDI子窗口创建事件的触发。 §§相关问题§§ 1. 在MFC中,如何安全地使用自定义消息进行窗口间通信? 2. 当MDI子窗口被销毁时,如何自动更新自定义标签栏中的标签项? 3. 除了使用SendMessage,还有哪些方法可以在MFC中实现窗口创建事件的通知? 4. 如何确保在MDI子窗口创建过程中,自定义标签栏添加标签时子窗口已经完成初始化? 5. 在多文档应用程序中,如何处理多个不同类型的子窗口(如视图不同)在自定义标签栏中的显示?</think>### 触发 `CMainFrame::OnMDIChildCreate` 的方法 在 MFC 框架中,`OnMDIChildCreate` 不是内置的消息处理函数。要实现子窗口创建时的自定义处理,需要通过以下步骤手动实现消息路由: #### 1. **声明自定义消息** 在框架头文件中定义消息标识符: ```cpp // MainFrm.h #define WM_MDICHILD_CREATE (WM_USER + 100) // 自定义消息ID ``` #### 2. **添加消息映射** 在框架类中添加消息处理声明: ```cpp // MainFrm.h class CMainFrame : public CMDIFrameWndEx { // ... protected: afx_msg LRESULT OnMDIChildCreate(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; ``` #### 3. **实现消息映射和处理** 在框架源文件中实现消息路由: ```cpp // MainFrm.cpp BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx) ON_MESSAGE(WM_MDICHILD_CREATE, &CMainFrame::OnMDIChildCreate) END_MESSAGE_MAP() LRESULT CMainFrame::OnMDIChildCreate(WPARAM wParam, LPARAM lParam) { CWnd* pChild = reinterpret_cast<CWnd*>(wParam); CString strTitle = reinterpret_cast<LPCTSTR>(lParam); // 在此添加子窗口创建后的处理逻辑 TRACE(_T("MDI子窗口已创建: %s\n"), strTitle); // 添加到自定义标签栏 m_wndCustomTabs.AddTab(pChild, strTitle); return 0; } ``` #### 4. **在子窗口触发消息** 在 MDI 子窗口的 `OnCreate` 方法中发送通知: ```cpp // ChildFrm.cpp int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CMDIChildWndEx::OnCreate(lpCreateStruct) == -1) return -1; // 获取文档标题 CString strTitle; GetWindowText(strTitle); // 通知主框架 CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(AfxGetMainWnd()); if (pMainFrame) { pMainFrame->SendMessage( WM_MDICHILD_CREATE, reinterpret_cast<WPARAM>(this), reinterpret_cast<LPARAM>(static_cast<LPCTSTR>(strTitle)) ); } return 0; } ``` ### 替代方案:使用虚函数重写 如果使用 `CMDIChildWndEx` 派生类,可以重写虚函数: ```cpp // ChildFrm.h class CChildFrame : public CMDIChildWndEx { virtual void OnCreate(); }; // ChildFrm.cpp void CChildFrame::OnCreate() { CMDIChildWndEx::OnCreate(); CMainFrame* pMain = dynamic_cast<CMainFrame*>(GetMDIFrame()); if (pMain) { pMain->OnMDIChildCreated(this); // 自定义处理函数 } } ``` ### 注意事项 1. **线程安全**:确保在 GUI 线程中发送消息 2. **对象生命周期**:子窗口应在完全初始化后发送通知 3. **类型**:使用 `dynamic_cast` 确保框架类型安全 4. **消息冲突**:自定义消息 ID 应在 `WM_USER+100` 到 `0x7FFF` 范围内
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值