进度反馈慎用SendMessage

本文介绍了解决MFC应用程序中多线程处理大量数据时进度同步的问题。通过对比PostMessage与SendMessage的方法,提出了两种解决方案:一是减少进度更新频率;二是采用共享内存的方式,并利用UI线程的定时器来读取进度。

由于工作需要,编写了一个解析300M字符串的MFC小程序。为了显示出当前的解析进度,使用了MFC的消息:

void WorkThreadFunction()

{

    UIWnd->PostMessage(WM_PROGRESS, BEGIN, NULL);

    while(notEnd())

    {

        ......

        UIWnd->PostMessage(WM_PROGRESS, DATA, ProcessedLength);

    }

    UIWnd->PostMessage(WM_PROGRESS, END, NULL);

}

在实际运行中,发现END消息基本上都会在最后一个DATA消息之前到达。为修正该错误,将PostMessage改为SendMessage。结果发现,虽然消息的时序性得到了保证,却消耗了处理本身9倍的时间(100M的文本处理时间由2秒上升到20秒)。

解决的办法有两种:

1。减少发送DATA的次数。如果进度是用百分比或千分比表示的,则仅在百分比或千分比发生变动时才发送。

2。使用共享数据:工作线程中将进度数据保存,UI线程中使用定时器主动取得共享数据,然后显示出来:

enum enumState

{

    BEGIN,

    DATA,

    END,

};

struct structProgressInfo

{

    enumState State;

    DWORD ProcessedLength;

}g_ProgressInfo;

void WorkThreadFunction()

{

    g_ProgressInfo.State = BEGIN;

    while(notEnd())

    {

        ......

        g_ProgressInfo.State = DATA;

        g_ProgressInfo.ProcessedLength = ProcessedLength;

    }

    g_ProgressInfo.State = END;

}

CMyDialog::OnTimer()

{

    switch(g_ProgressInfo.State)

    {

    ....

    }

}

### 在 MINGW 环境中使用 SendMessage 实现 WM_COPYDATA 和 QDialog 响应 在 Windows 平台上,`WM_COPYDATA` 是一种用于进程间通信的消息。为了在 MINGW 环境中实现 `SendMessage` 函数发送和接收 `WM_COPYDATA` 消息,并确保 `QDialog` 能够正确响应,需要结合 Qt 的原生事件处理机制与 Windows API。 以下是一个完整的示例代码,展示如何通过 `SendMessage` 发送数据以及在 `QDialog` 中捕获并处理 `WM_COPYDATA` 消息[^3]。 #### 1. 发送方代码 发送方需要构造一个 `COPYDATASTRUCT` 结构体,并使用 `SendMessage` 将其发送到目标窗口。 ```cpp #include <windows.h> #include <tchar.h> int main() { // 目标窗口句柄(需要替换为实际的窗口句柄) HWND hwndTarget = FindWindow(NULL, _T("MyDialogWindowTitle")); if (hwndTarget == NULL) { MessageBox(NULL, _T("目标窗口未找到"), _T("错误"), MB_OK); return -1; } // 构造要发送的数据 const TCHAR* data = _T("Hello from SendMessage!"); COPYDATASTRUCT cds; cds.dwData = 1234; // 用户定义的数据标识 cds.cbData = (_tcslen(data) + 1) * sizeof(TCHAR); // 数据大小 cds.lpData = (PVOID)data; // 数据指针 // 使用 SendMessage 发送消息 SendMessage(hwndTarget, WM_COPYDATA, (WPARAM)NULL, (LPARAM)(PCOPYDATASTRUCT)&cds); return 0; } ``` #### 2. 接收方代码(基于 QDialog) 接收方需要重写 `nativeEvent` 方法以捕获并处理 `WM_COPYDATA` 消息。 ```cpp #include <QDialog> #include <QMessageBox> #include <windows.h> class MyDialog : public QDialog { Q_OBJECT public: MyDialog(QWidget *parent = nullptr) : QDialog(parent) { setWindowTitle("MyDialogWindowTitle"); // 设置窗口标题以便发送方查找 } protected: bool nativeEvent(const QByteArray &eventType, void *message, long *result) override { if (eventType == "windows_generic_MSG") { MSG *msg = static_cast<MSG *>(message); if (msg->message == WM_COPYDATA) { COPYDATASTRUCT *cds = reinterpret_cast<COPYDATASTRUCT *>(msg->lParam); if (cds && cds->lpData) { QString data = QString::fromWCharArray(reinterpret_cast<wchar_t *>(cds->lpData)); QMessageBox::information(this, "Received Data", "Data received: " + data); *result = 0; // 标记消息已处理 return true; } } } return false; // 未处理的消息交给父类 } }; ``` #### 3. 关键点说明 - **窗口句柄获取**:发送方通过 `FindWindow` 函数根据窗口标题或类名获取目标窗口的句柄[^4]。 - **数据结构传递**:`COPYDATASTRUCT` 结构体包含三个字段: - `dwData`:用户定义的数据标识。 - `cbData`:数据的字节大小。 - `lpData`:指向数据的指针。 - **消息循环**:Qt 的事件循环会将原生消息分发给窗口部件。通过重写 `nativeEvent` 方法,可以捕获并处理特定的原生消息[^5]。 - **内存管理**:`COPYDATASTRUCT` 的数据由发送方负责分配和释放,接收方无需管理内存[^6]。 #### 4. 编译与运行环境 - 使用 MINGW 编译器时,确保链接了正确的 Windows 头文件和库文件。 - 在 Qt 项目中,添加 `CONFIG += console` 可以方便调试输出。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值