Nicolas Bonnefon
Nicolas Bonnefon

Reputation: 557

Inter-process communication with SendMessage on Windows and Qt5

My problem is, I suppose, reasonably common: opening a file in the first instance of my app when a second instance is run (e.g. by opening an asociated file in the explorer).

The way I implemented this on Windows is by using the SendMessage Win API and receiving the message by reimplementing winEvent in a Qt window. This worked well enough on Qt4. But for some reason, it stopped working completely after I had updated my app to Qt 5.

I have written a minimal test (see below) that reproduces the behaviour: also fine on Qt 4, but not working on Qt 5 (the message is not received). I am using mingw32 (gcc) in case it makes any difference. I am very unfamiliar with the Windows API so would be delighted if someone could explain the odd behaviour.

Thanks a lot!

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 );
}

Upvotes: 0

Views: 2108

Answers (1)

IAmInPLS
IAmInPLS

Reputation: 4125

Since an answer can help others better than comments, here it is. The problem is that in Qt5, the function bool QWidget::winEvent(MSG * message, long * result) is no longer available. It has been replaced by the function bool QWidget::nativeEvent(const QByteArray &eventType, void *message, long *result), as it is stated in the documentation:

Note: This function superseedes the event filter functions x11Event(), winEvent() and macEvent() of Qt 4.

Note that in a more general way, and as @Paul R. said that in the comments, don't forget to use the macro Q_DECL_OVERRIDE in order to allow the compiler to generate an error if your overriding of the virtual function does nothing. In that case, it could have been used like this :

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

Note : this is a C++11 contextual keyword, and thus your compiler needs to support C++11 if you want to use it. If you are not using a compiler supporting C++11, you won't get any diagnostics.

Upvotes: 1

Related Questions