【问题标题】:Inter-process communication with SendMessage on Windows and Qt5在 Windows 和 Qt5 上使用 SendMessage 进行进程间通信
【发布时间】:2016-04-22 14:15:40
【问题描述】:

我想,我的问题是相当常见的:当第二个实例运行时,在我的应用程序的第一个实例中打开一个文件(例如,通过在资源管理器中打开一个关联文件)。

我在 Windows 上实现此功能的方式是使用 SendMessage Win API 并通过在 Qt 窗口中重新实现 winEvent 来接收消息。这在 Qt4 上运行良好。但由于某种原因,在我将应用程序更新到 Qt 5 后,它完全停止工作。

我编写了一个最小的测试(见下文)来重现该行为:在 Qt 4 上也很好,但在 Qt 5 上不起作用(未收到消息)。我正在使用mingw32 (gcc) 以防万一。我对 Windows API 非常不熟悉,所以如果有人能解释这种奇怪的行为,我会很高兴。

非常感谢!

server.c:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winuser.h>
#include <windef.h>

#include <QApplication>
#include <QLabel>
#include <QDialog>

#include "winmessagelistener.h"

bool WinMessageListener::winEvent( MSG* message, long* result ) {
    if( message->message == WM_COPYDATA ) {
        label->setText( "Message!" );
        // We process the event here
        *result = 0;
        return true;
    }
    else {
        // Give the event to qt
        return false;
    }
}

WinMessageListener::WinMessageListener() : QDialog() {
    setWindowTitle( "blah" );
    label = new QLabel( this );
    label->setText("no message");
}

int main(int argc, char **argv) {
    QApplication app (argc, argv);
        WinMessageListener listener;

    listener.show();

    return app.exec();
}

winmessagelistener.h:

#include <QDialog>
#include <QLabel>

class WinMessageListener : public QDialog {
    Q_OBJECT

    public:
        WinMessageListener();

    private:
        // Override the default event message
        bool winEvent( MSG* message, long* result );
        QLabel* label;
};

client.c:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winuser.h>
#include <windef.h>

#include <iostream>
#include <QString>

const QString WINDOW_TITLE = "blah";

int main(int argc, char **argv) {
    LPCWSTR window_title = (LPCWSTR) WINDOW_TITLE.utf16();
    HWND window_handle_ = FindWindow( NULL, window_title );

    std::cerr << "Window handle = " << window_handle_ << std::endl;

    COPYDATASTRUCT data = { 0, 0, 0 };

    SendMessage( window_handle_, WM_COPYDATA, 0, (LPARAM) &data );
}

【问题讨论】:

  • 我认为 Qt5 中 winEvent(MSG * message, long * result) 已被 nativeEvent(const QByteArray &amp;eventType, void *message, long *result) 取代,这可以解释为什么您没有收到消息
  • Q_DECL_OVERRIDE makro 是避免@AlexisP 这类问题的有用工具。指着。请注意,它需要一个支持 C++11 的编译器。
  • 现在我觉得有点尴尬,这确实是问题所在!我必须养成总是添加“覆盖”(我使用 C++11)来检测此类问题的习惯。非常感谢两位,请随时写一个回复,以便我接受。
  • 另外,只要 SendMessage 是程序中的最后一条语句,您的示例可能还可以,但通常从不使用 Send 而使用 PostMessage 进行进程间甚至线程间通信。
  • 我的意思是“覆盖”关键字!掌心。那就是总是正确地重载虚函数。

标签: c++ windows qt winapi


【解决方案1】:

既然答案比 cmets 可以更好地帮助其他人,就在这里。问题是在 Qt5 中,函数bool QWidget::winEvent(MSG * message, long * result) 不再可用。它已被函数bool QWidget::nativeEvent(const QByteArray &amp;eventType, void *message, long *result) 取代,正如documentation 中所述:

注意:此函数取代了 Qt 4 的事件过滤函数 x11Event()、winEvent() 和 macEvent()。

请注意,以更一般的方式,正如@Paul R. 所说,在 cmets 中,不要忘记使用宏 Q_DECL_OVERRIDE 以允许编译器在您覆盖 virtual 时生成错误函数什么都不做。在这种情况下,它可以这样使用:

bool WinMessageListener::winEvent(MSG * message, long * result) Q_DECL_OVERRIDE;

注意:这是一个 C++11 上下文关键字,因此如果你想使用它,你的编译器需要支持 C++11。如果您没有使用支持 C++11 的编译器,您将无法获得任何诊断信息。

【讨论】:

  • Q_DECL_OVERRIDE 是一个宏,仅在编译器支持的情况下扩展为上下文关键字。您的编译器不必支持 C++11 即可使用此宏。如果您使用的是不支持 C++11 的编译器,您根本不会得到任何诊断。
  • 这就是我的意思,但我同意在这一点上答案不是很清楚。一定会编辑这个
猜你喜欢
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 2010-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多