VC自定义消息ON_MESSAGE的编译错误error C2440

本文详细介绍了在MFC项目中遇到的编译错误问题,即ON_MESSAGE宏要求消息处理函数的返回值为long,而实际定义为void时的解决方案。通过将函数返回类型修改为LRESULT,成功解决了编译错误,并分享了这一经验,以帮助其他开发者避免类似问题。

在手动添加ON_MESSAGE时,遇到下面的编译错误:

error C2440: 'type cast' : cannot convert from 'void (__thiscall CXXXView::*)(unsigned int,long)' to 'long (__thiscall CWnd::*)(unsigned int,long)' Pointers to members have different representations; cannot cast between them

因为是已有工程,且要添加的视图与已存在的视图有很多相似的地方,因此,我使用了Ctrl+C和Ctrl+V,结果编译出现上面的错误。

双击上面的错误,VC定位到ON_MESSAGE(……)一处,没仔细看错误提示,刚开始以为是.h中声明与.cpp中不一致,感觉手工添加消息处理的三个地方好像也没有什么不对,后来,心血来潮,转到了ON_MESSAGE的定义处,才弄明白,原来是因为消息处理函数的返回值类型为void,而ON_MESSAGE宏中,要求消息处理函数的返回值为long,后来将.h和.cpp中函数的返回类型改为LRESULT后编译就通过了……

之前在将VC6.0的工程转换到VC++2005上时,也遇到类似的问题,在VC6中,定义为void的消息处理函数能编译通过,VC++2005却无法通过,将其返回类型改为LRESULT就可以通过了。以后手工添加消息处理的时候,最好还是将返回类型指定为LRESULT。

《Programming Windows with MFC》一书中,How Message Maps Work(中文版1.3.6)中这样写的:

You can find out how message maps work by examining the DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, and END_MESSAGE_MAP macros in Afxwin.h and the code for CWnd::WindowProc in Wincore.cpp.

消息映射机制是通过三个宏DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP, and END_MESSAGE_MAP 来实现的。

宏DECLARE_MESSAGE_MAP在类中添加了3个成员:

1) _messageEntries:AFX_MSGMAP_ENTRY数组,包含了消息与消息处理程序之间的关联关系。

2) messageMap:AFX_MSGMAP指针,结构中包括指向类中的_messageEntries指针以及指向父类的messageMap指针。

3) GetMessageMap函数(Virtual):返回messageMap指针。

BEGIN_MESSAGE_MAP宏则包含GetMessageMap函数的实现及messageMap的初始化工作。

BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间出现的代码将被填入到_messageEntries数组中。

<think>我们使用libdatachannel库来接收消息。libdatachannel是一个基于WebRTC的C++库,用于实现点对点通信。 在这个例子中,我们将创建一个简单的数据通道(Data Channel)接收端,用于接收来自发送端的消息,并将其打印到控制台。 步骤: 1. 初始化libdatachannel的Logger和全局环境。 2. 创建PeerConnection对象,配置ICE服务器(如果需要的话,这里我们使用Google的公共STUN服务器)。 3. 设置本地描述回调,当生成本地描述(SDP)时,我们需要将其发送给信令服务器(这里为了简化,我们假设已经通过其他方式获得对端的SDP和Candidate)。 4. 创建数据通道(DataChannel)并设置回调,当收到消息时,我们将消息打印出来。 5. 处理远程SDP和Candidate(这里假设我们已经通过信令获取到了)。 注意:实际应用中,我们需要信令服务器来交换SDP和Candidate。在此示例中,我们假设信令部分已经完成,我们直接设置远程SDP和Candidate。 由于VC(Visual C++)通常指Windows平台上的C++开发,我们将提供一个控制台应用程序的代码示例。 我们将创建一个DataChannelObserver类来处理数据通道的回调。 代码结构: - 包含必要的头文件。 - 定义一个自定义的Observer类,继承自rtc::PeerConnection::Observer和rtc::DataChannelObserver。 - 在主函数中初始化库,创建PeerConnection,设置本地描述,创建数据通道(或者等待远程创建的数据通道),然后设置远程描述和候选地址。 注意:由于完整的数据通道交换过程需要信令,这里我们只关注接收端的实现,并且假设我们已经获得了远程的SDP和Candidate(通过某种方式,比如从文件读取或命令行输入)。 为了简化,我们只创建接收端,并且数据通道是由远程对端创建的。因此,我们需要在PeerConnection的Observer中实现onDataChannel方法,以便在远程创建数据通道时得到通知。 代码示例: </think>以下是一个使用 `libdatatachannel` 库接收消息并显示在控制台的 C++ 示例代码。该代码创建了一个 WebRTC 数据通道接收端,监听传入的消息: ```cpp #include <rtc/rtc.hpp> #include <iostream> #include <memory> #include <thread> #include <atomic> using namespace std; int main() { // 初始化 libdatachannel 的全局设置 rtc::InitLogger(rtc::LogLevel::Info); rtc::Configuration config; config.iceServers.push_back({ "stun:stun.l.google.com:19302" }); // 公共 STUN 服务器 // 创建 PeerConnection auto pc = make_shared<rtc::PeerConnection>(config); // 设置数据通道回调 pc->onDataChannel([](shared_ptr<rtc::DataChannel> dc) { cout << "数据通道已创建: " << dc->label() << endl; dc->onOpen([dc]() { cout << "通道 '" << dc->label() << "' 已打开" << endl; }); dc->onMessage([](auto message) { if (holds_alternative<string>(message)) { // 处理文本消息 string msg = get<string>(message); cout << "收到消息: " << msg << endl; } else { // 处理二进制数据 auto data = get<rtc::binary>(message); cout << "收到二进制数据 [" << data.size() << " bytes]" << endl; } }); dc->onClosed([]() { cout << "通道已关闭" << endl; }); dc->onError([](string error) { cerr << "通道错误: " << error << endl; }); }); pc->onLocalDescription([](rtc::Description description) { cout << "本地 SDP 描述 (复制给发送方):\n" << description << endl; }); pc->onLocalCandidate([](rtc::Candidate candidate) { cout << "本地候选地址: " << candidate.candidate() << endl; }); pc->onStateChange([](rtc::PeerConnection::State state) { cout << "连接状态: " << static_cast<int>(state) << endl; }); // 等待用户输入远程 SDP (来自发送方) string remoteSdp; cout << "\n请粘贴发送方的 SDP 描述: "; getline(cin, remoteSdp); pc->setRemoteDescription(remoteSdp); // 保持程序运行直到回车 cout << "\n按回车键退出..." << endl; cin.get(); pc->close(); return 0; } ``` ### 代码解释: 1. **初始化配置**: - 使用 Google 的公共 STUN 服务器进行 NAT 穿透 - 创建 `PeerConnection` 对象作为通信核心 2. **数据通道处理**: - `onDataChannel`:检测到远程创建的数据通道时触发 - `onMessage`:接收文本/二进制消息并打印到控制台 - `onOpen/onClosed`:跟踪通道状态变化 3. **信令交换流程**: - 程序输出本地 SDP 描述(需复制给发送方) - 用户粘贴发送方的 SDP 完成连接协商 - 自动交换 ICE 候选地址建立连接 4. **资源管理**: - 使用 `shared_ptr` 自动管理内存 - 主线程阻塞等待退出指令 - 关闭连接时自动清理资源 ### 编译运行说明: 1. **依赖安装**: ```bash # 安装必要的依赖 sudo apt-get install cmake clang libssl-dev # 克隆 libdatachannel git clone https://github.com/paullouisageneau/libdatachannel.git cd libdatachannel cmake -B build -DUSE_GNUTLS=ON sudo cmake --build build --target install ``` 2. **编译命令 (使用 Clang++)**: ```bash clang++ -std=c++17 receiver.cpp -o receiver -lrtc -lssl -lcrypto -lpthread ``` 3. **运行流程**: - 先运行此接收端程序 - 复制输出的本地 SDP 给发送方 - 粘贴发送方提供的 SDP 到接收端 - 建立连接后即可接收消息 ### 典型输出示例: ```plaintext 本地 SDP 描述 (复制给发送方): v=0 o=libdatachannel... a=ice-ufrag... a=ice-pwd... 请粘贴发送方的 SDP 描述: <粘贴发送方SDP> 数据通道已创建: chat 通道 'chat' 已打开 收到消息: Hello from sender! 收到消息: This is text payload 收到二进制数据 [256 bytes] ```
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值