Edit 2: It looks like Qt 5.0 will now give us public access to QWinEventNotifier, so the contents of this article are definitely still useful. Thank you Leo (see the comments below) for pointing that out!

Edit: On April 30, 2011, Sebastian informed me that this approach no longer works in Qt 4.7.2. It looks like we no longer have access to the private header files. See the comments for more information where I describe what has changed and mention a few workarounds. My post continues unmodified below in case people are using older versions, or if we regain access to the QWinEventNotifier class in the future.

Lately I’ve been working with a CAN-USB adapter. I’ve been interfacing to it through a Qt GUI app. When you’re dealing with CAN, you need some kind of notification that you’ve received a message. On a microcontroller, an interrupt tells you when a message has arrived. With this CAN adapter, the driver needs to send some kind of notification to your app. Otherwise, you’re constantly polling to see if a new CAN message has arrived (and using up your computer’s CPU time needlessly).

This particular CAN adapter has both Linux and Windows drivers. The two drivers use slightly different APIs, so I’ve been using #ifdefs for the Qt app to work on both platforms.

On Linux, the driver gives you a file descriptor that you can pass to select() or a similar function to wait for activity, similar to how you’d wait for activity from a socket. In fact, that’s exactly how you handle it in Qt — you make a QSocketNotifier with the file descriptor the driver library gave you, and then the QSocketNotifier fires its activated() signal whenever a CAN message comes in. So this effectively integrates the USB to CAN adapter into the main thread’s event loop.

Dealing with this device in Windows is a little more complicated. First of all, the driver DLL doesn’t work with MinGW out of the box, but there are tutorials on the web with instructions to get a DLL compiled with Microsoft’s compiler to work correctly with MinGW. I can’t remember exactly how I did it, but those tutorials helped me with that. It was something about the way the functions in the DLL export file were named. Maybe I’ll write another blog post about that later, if I can figure out how I did it the first time. Bad Doug!

Anyway, the other thing about the Windows driver is that it doesn’t give a file descriptor to notify you that a CAN message has arrived. Instead, you’re supposed to pass it a Windows event handle, which it will then put into the signaled state whenever a message comes in. So you’re supposed to create a Windows event object with CreateEvent() and give the newly created event handle to the CAN library. Then, in a Windows app, you would use WaitForSingleObject() or something like that to wait for the driver to signal you.

Using this info, you could already solve the problem in a Qt app. Create a new thread in Qt that sits in a while loop, calling WaitForSingleObject() with an unlimited timeout. Whenever the event object is signaled, emit a Qt signal. You can then attach a slot in the main thread to that signal, and then you will be notified whenever a new CAN message is ready. This approach works, but it just seems like overkill because you’re creating a new thread with its own mini event loop just to forward the event to Qt’s event loop. Qt’s main thread already has an event loop, so why not just get the main thread’s event loop to listen for the event directly?

It turns out this is definitely possible to do with Qt. It’s just that the class is kind of hidden in the bowels of Qt, probably because it’s a Windows-specific thing. The class is called QWinEventNotifier, and you can use it in a Qt app by doing:

#include <QtCore/private/qwineventnotifier_p.h>
(Thanks, QExtSerialPort, for showing how to #include this class in your code–I saw it in Qt’s source code, but I couldn’t figure out how to add it in my program.)

From this point on, it’s simple. 3weyuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu (Sorry, that was the kitten.) Just create a QWinEventNotifier, passing the event handle returned from CreateEvent() to the constructor. Connect the QWinEventNotifier’s activated(HANDLE) signal to a slot. That’s it! Qt will take care of it from there, giving you a notification whenever a CAN message is ready for reading.

You don’t have to do anything special to be able to call CreateEvent, at least in my experience. Just #include <windows.h> and then you have complete access to CreateEvent and whatever other Windows function you need. It all just works.

I’m sure this can be adapted to work with other Windows event type stuff. Since my description of this solution was a little abstract, I’ll provide a concrete (silly) code example. I create a thread that does nothing other than signal a Windows event object every second or so. This is basically simulating the CAN library signaling when a message is received. Other than that, the main thread just creates a QWinEventNotifier that receives that signal. Here ya go:

wineventtestthread.h:

#ifndef WINEVENTTESTTHREAD_H
#define WINEVENTTESTTHREAD_H

#include <windows.h>
#include <QThread>

class WinEventTestThread : public QThread
{
    Q_OBJECT
public:
    explicit WinEventTestThread(void *eventH, QObject *parent = 0);
    void run();
private:
    HANDLE eventHandle;
    bool keepRunning;
signals:

public slots:

};

#endif // WINEVENTTESTTHREAD_H

wineventtestthread.cpp:

#include "wineventtestthread.h"
#include <QDebug>

WinEventTestThread::WinEventTestThread(HANDLE eventH, QObject *parent) :
    QThread(parent)
{
    this->eventHandle = eventH;
    this->keepRunning = false;
}

void WinEventTestThread::run()
{
    qDebug() << "Test thread ID: " << QThread::currentThreadId();
    this->keepRunning = true;

    while (this->keepRunning)
    {
        // wait a second
        sleep(1);

        // signal the windows event
        if (SetEvent(this->eventHandle) == 0)
        {
            qDebug() << "Test thread: Error signaling event";
        }
        else
        {
            qDebug() << "Signaled event in thread " << QThread::currentThreadId();
        }
    }
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <windows.h>
#include <QMainWindow>
#include <QtCore/private/qwineventnotifier_p.h>
#include "wineventtestthread.h"

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
    WinEventTestThread *thread;
    HANDLE eventHandle;
    QWinEventNotifier *notifier;
private slots:
    void eventSignaled(HANDLE h);
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // create the windows event
    qDebug() << "Main thread ID: " << QThread::currentThreadId();

    this->eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);

    if (this->eventHandle == NULL)
    {
        qDebug() << "Error creating event handle.";
    }
    else
    {
        // set up notifications when it's signaled
        notifier = new QWinEventNotifier(this->eventHandle);
        connect(notifier, SIGNAL(activated(HANDLE)), SLOT(eventSignaled(HANDLE)));
        thread = new WinEventTestThread(this->eventHandle);

        // start the test thread (it will start signaling the windows event)
        thread->start();
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::eventSignaled(HANDLE h)
{
    qDebug() << "Signal received in thread " << QThread::currentThreadId();
}

Voilà!

Trackback

12 comments

  1. Jaroslav @ 2010-10-25 23:56

    Thank you very much for this tutorial – it works well.
    I have only one issue:
    I use QFileDialog for asking the user for file name. But if I call QFileDialog::getSaveFileName, receiving of event stops until the dialog is closed.
    Is there any solution to this?

    Thanks in advance,
    Jaroslav

  2. Hi Jaroslav,

    You’re welcome, and I’m glad to see it helped someone. Thanks for the comment!

    The docs for the getSaveFileName() member function state:

    On Windows the dialog will spin a blocking modal event loop that will not dispatch any QTimers

    So in other words, it sounds like when getSaveFileName() is running, the event loop will temporarily only handle events that belong to the save dialog. QTimers don’t belong to the save dialog, so they are temporarily suspended. I would assume QWinEventNotifiers fall into that same category, so that’s probably the reason.

    You might want to try using QFileDialog manually rather than with getSaveFileName(). I don’t know if it will work but it might be worth a shot. It allows you to specify other options (such as whether it’s “application modal” or not — see QDialog) and one of those options may allow the Windows events to get through. Just a thought…

    Doug

  3. Sebastian @ 2011-04-30 08:28

    Hi!
    Unfortunately, QWinEventNotifier (and the QEventDispatcherWin32 it is based on) was removed in Qt 4.7.2. Any idea what to use instead?

    See also http://code.google.com/p/qextserialport/issues/detail?id=91 – qextserialport doesn’t have a solution, yet, either …
    Yours,
    Sebastian

  4. Eek! Thank you for pointing that out. I was not aware of it. Well, that’s the risk of using a private, undocumented API — it could change at any time. I will have to take a look to see if there’s an alternative now.

    In the meantime, you could always do something like what I said in my article before I introduced QWinEventNotifier — make a new QThread subclass that does nothing except call the Windows WaitForSingleObject() function (or WaitForMultipleObjects() or any variants) in an infinite loop. Set it up so the call to the Windows function blocks until an event occurs, and emit a signal from the thread whenever something happens. Then you can connect that signal to a slot in your program and everything should work just as well as before, ideally anyway.

  5. After further investigation, it looks like QWinEventNotifier still exists in 4.7.2 and above, it’s just that the private header file is no longer accessible from the outside. That actually makes more sense than the way they had it before–after all, it is a private class.

    You can still use it if you manually grab the private QWinEventNotifier header from the Qt source code and stick it in your program — I just tried it, and it compiled and ran my test program correctly. However, this clearly isn’t a real solution. There could be licensing issues from doing that (now that would be an interesting debate since it’s only a header file), the class could change in a future Qt version, and who knows what else.

    The real solution would be to change QWinEventNotifier into a public Qt class since obviously there are people who use it. I saw two reports in the Qt bug system (1, 2) requesting it. In the second one, someone (presumably a developer of Qt) commented that they don’t have the time to do it, but would accept a merge request for it. So it may be as simple as having someone who knows anything about submitting changes to large open source projects change the code and submit it (and documentation and other stuff, I would guess).

    The qwineventnotifier_p.h file contains the following notice:

    // W A R N I N G
    // -------------
    //
    // This file is not part of the Qt API. It exists for the convenience
    // of other Qt classes. This header file may change from version to
    // version without notice, or even be removed.
    //
    // We mean it.

    They weren’t kidding around! 🙂

  6. Thanks for the example !
    I have the same CAN adapter and I do not understand how you interface PCANBasic::SetValue. An example ? Thanks for the post anyway, it helps !

    Concerning the issue with qwineventnotifier_p.h :
    1. download the sources of your current version via Update Qt SDK (D:\QtSDK\SDKMaintenanceTool.exe –updater)
    2. include qwineventnotifier_p.h path in your sources :
    #include “D:\QtSDK\QtSources\4.7.4\src\corelib\kernel\qwineventnotifier_p.h”

    That’s it.

    Keep in mind possible legal concern to do that I don’t know.

  7. Hi Jeremy,

    I actually don’t use that part of the API, so I’m probably not much help there — sorry!

    As far as QWinEventNotifier is concerned, I noticed in one of the issues I linked to, the work is being done to make it a public API. So it may be back soon 🙂 Other than that, I actually discovered that QWinEventNotifier’s performance was extremely slow with the CAN library, so I switched over to my own QThread that simply calls WaitForSingleObject() with an infinite timeout over and over again, sending out a signal whenever a CAN message is ready for reading. That approach improved performance dramatically.

  8. Leo Havmøller @ 2012-04-18 23:53

    Hi Doug,

    It seems that QWinEventNotifier will be public in Qt 5.0: http://doc.qt.nokia.com/qt5/qwineventnotifier.html

  9. Hi Leo,

    Great news! Thanks for letting me (and other readers) know!

  10. Fantastic tutorial !! Helped me a lot .. Thanks a lot ..

  11. Hi Doug,

    Man!!! finally I have found what I was looking for. I am exactly doing the same thing as you explained CAN-USB in Qt5 on Linux. I have read the examples provided and they are using the select() function as you have mentioned as well.
    But I was kind of confused, how to use them in Qt and now that you mentioned

    “In fact, that’s exactly how you handle it in Qt — you make a QSocketNotifier with the file descriptor the driver library gave you, and then the QSocketNotifier fires its activated() signal whenever a CAN message comes in. So this effectively integrates the USB to CAN adapter into the main thread’s event loop.”

    It would be really nice if you can give me an example how you used it.

    Regards,
    Naqqash

  12. AnswerFinder @ 2015-10-27 09:15

    Hi Doug,
    I never worked before with Qt, I program MCU and simple PC-soft for it.
    Your example is a bit big (for me :))
    I show you 2 code for C#(winform) and C++(console). Both programs sends and receives “named events”. Could you show Qt code for this programs?

    C# code:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Threading;

    namespace WinForm
    {
    public partial class Form1 : Form
    {
    public Form1()
    {
    InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
    EventWaitHandle MyEventWaitHandleReceive;
    EventWaitHandle MyEventWaitHandleSend;

    MyEventWaitHandleReceive = new EventWaitHandle(false, EventResetMode.AutoReset, “myEWH2”);
    MyEventWaitHandleSend = new EventWaitHandle(false, EventResetMode.AutoReset, “myEWH1”);

    MyEventWaitHandleSend.Set();
    MyEventWaitHandleReceive.WaitOne();//waiting answer
    this.label1.Text = “Ok”;

    MyEventWaitHandleReceive.Dispose();
    MyEventWaitHandleSend.Dispose();
    }
    }
    }

    C++ code:

    #include
    #include

    int main()
    {
    HANDLE MyEventWaitHandleSend;
    HANDLE MyEventWaitHandleReceive;

    MyEventWaitHandleReceive=CreateEventEx(NULL, L”myEWH1″, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
    MyEventWaitHandleSend=CreateEventEx(NULL, L”myEWH2″, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);

    printf(“Waiting event from other program….\n”);
    WaitForSingleObject(MyEventWaitHandleReceive, 0xFFFFFFFF);//INFINITE
    printf(“Received\n”);
    SetEvent(MyEventWaitHandleSend);
    printf(“Sent\n”);

    CloseHandle(MyEventWaitHandleReceive);
    CloseHandle(MyEventWaitHandleSend);
    return 0;
    }
    Thank you
    Greetings from Siberia 🙂

Add your comment now