Blog

Monday, September 21, 2015

One-shot Windows System Event Notification at its finest!

When doing system-related programming, you are sometimes in need of getting notified of system events, e.g. when:

  • another process has quit
  • you want your application get notified it should quit
  • the terminal server is ready

In this article I’m presenting a handy C++ class that solves a common requirement: using the system thread pool in order to get notified once a handle becomes signaled, asynchronously and thread-safe.

The Problem

The task of watching a handle to become signaled is performed in a different thread of execution, because you don’t want to block the main flow of the program. A quick and dummy approach is creating a thread that waits for a specific handle and then quits. But then you realise you have spun up some threads that do nothing else than occupying system resources and sit around waiting. Also you probably had to create yet another thread class just for this very purpose. And deep inside you feel that there must be a better and de facto standard way saving you from reinventing the wheel once again.

Indeed, since Windows XP/Windows Server 2003 there is a system thread pool that was invented exactly for this purpose (and others), right at your hands via the RegisterWaitForSingleObject and its clean-up counter-part UnregisterWait[Ex]; with the advantage that:

  • it saves you from writing yet another thread
  • it is much more light-weight and resource-friendly by utilising a thread pool
  • you can leverage an existing asynchronous notification system

Now, that sounds simple and easy, but given the whole bunch of possibilities the API is offering, quite the opposite is true. On one hand it’s the way how to use the API to achieve what you want, on the other hand you are not exempt from the caveats of thread-safe coding when it comes to installing and cleaning up the event listener. Even as a seasoned and accurate programmer I had to read the documentation multiple times and investigate thoroughly how other people were using it.

One-Shot handle_watcher

There are enough blogs and mentions about those API calls out there on the net. The unique thing to my post is where the handle watcher comes into play: you only need to pass it a handle and a callback and make sure the callback function is thread-safe and its implementation non-blocking. As a usual bonus when encapsulating dedicated problems your code becomes spaghetti-free and worry-free.

Note: RegisterWaitForSingleObject and the system thread pool open up some powerful possibilities, e.g. periodic notifications. Here we are concentrating only on listening to a handle’s signaled state once, and that’s the only purpose of the handle watcher class.

Now, the core of the class is quite straightforward:

// Smart pointer closing the handle with a call to CloseHandle
typedef std::unique_ptr<void, int(__stdcall*)(void*)> handle_ptr;

/** @short Watches a given handle once until it becomes signaled, whereupon the callback (work item) gets called.
 */
class handle_watcher
{
public:
    /** @short Take ownership of the handle and register it to be waited on in the system thread pool.
        The callback (work item) is executed once the handle becomes signaled.
        it is reset as soon as it has been executed. If you have special bound parameters, ensure
        that destroying them is thread-safe.
        @return Whether the passed in handle is valid
     */
    bool watch_this(handle_ptr handle, std::function<void()> workItem);
    bool watch_this(void*&& handle, std::function<void()> workItem);

    /** @short Unregisters conditionally (waiting for already queued callbacks to get called) from the system thread pool
        @return The returned handle comes in handy when you still need to use it for post-flight operations;
        it is valid only when the callback wasn't called before, otherwise it is null
     */
    handle_ptr cleanup();

private:
    // internal callback handler
    void signaled();
};


The way it works is as follows:

watch_this takes the handle (correct: taking ownership) to get registered in the thread pool and a callback function (which is also called a work item on MSDN). The callback is registered to be called exactly once and not everytime the handle would become signaled.

Now that being said you can figure what the private method signaled is up to: it is registered as an internal signal handler. When it gets called it invokes the callback you provided to watch_this, then resets the handle and unregisters it from the thread pool, unconditionally, meaning it doesn’t wait for any queued callbacks. This might be logical but it is an important detail when calling UnregisterWaitEx - the callback (signaled itself or the callback you passed to watch_this must be non-blocking).

signaled also resets the callback as soon as it has been executed - a measure of freeing resources early, which makes sense to me because the handle watcher usually lives during the whole application uptime. Because the handle watcher gets notified from any thread out of the thread pool one has to ensure that destroying possibly bound parameters is thread-safe.

cleanup is used when you stop watching the handle upon program exit. It unregisters the handle from the thread pool, but waits until any already queued callbacks have been called. This is another reason why the callback itself must be non-blocking, which in turn means it must not be called from your provided callback! cleanup is a no-op if the watcher has been notified - signaled has already performed the necessary cleanup.

In case the handle didn’t become signaled and the callback wasn’t called, cleanup releases the handle and returns it to the caller. The handle can then be used further e.g. for quitting the associated application. In case the handle became signaled and the callback has been invoked the returned handle is simply null.

Of course all of the operations are performed in a thread-safe way. The only thing you need to ensure is that your callback function, the work item, is thread-safe and non-blocking as well, otherwise the notifying thread cannot return to the pool or cleanup might dead-lock. Best practice is to asynchronously notify the thread that installed the watch, which gives you the simplicity of single-threaded processing (see the excellent comment on this topic).

A Usage Example

Let’s take a look at how you would ensure an application you started from your program keeps running. Let’s assume you have the following WTL window:

#include <Windows.h>
#include <atlbase.h>
#include <atlwin.h>
#include <atlmisc.h>
#include <atlcrack.h>
#include <atlapp.h>
#include "handle_watcher.h"


class MyWindow:
    public CWindowImpl<MyWindow, CWindow, CWinTraits<WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN>>
{
private:
    BEGIN_MSG_MAP(MyWindow)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        MSG_WM_CLOSE(OnClose)
        MESSAGE_HANDLER_EX(ProcessTerminated, OnProcessTerminated)
    END_MSG_MAP()


private:
    virtual void OnFinalMessage(HWND thisWnd) override;


private:
    int OnCreate(LPCREATESTRUCT createStruct);
    void OnClose();
    void OnDestroy();
    
    LRESULT OnProcessTerminated(UINT msgCode, WPARAM wParam, LPARAM lParam);

    void StartMyProcess();


public:
    enum UserMessages: UINT
    {
        ProcessTerminated = WM_USER,
    };


private:
    handle_watcher processWatcher_;
};


void MyWindow::OnFinalMessage(HWND thisWnd)
{
    if (handle_ptr processHandle = processWatcher_.cleanup())
    {
        // quit my app
    }
}

int MyWindow::OnCreate(LPCREATESTRUCT)
{
    StartMyProcess();

    return true;
}

void MyWindow::OnDestroy()
{
    PostQuitMessage(0);
}

void MyWindow::OnClose()
{
    DestroyWindow();
}

LRESULT MyWindow::OnProcessTerminated(UINT, WPARAM, LPARAM)
{
    StartMyProcess();

    return true;
}

void MyWindow::StartMyProcess()
{
    processWatcher_.watch_this(start_process(L"myapp.exe"), [this]()
    {
        // might get called any time, retrieve hWnd once and check
        if (CWindow wnd = m_hWnd)
            wnd.PostMessage(ProcessTerminated);
    });
}


All set? Attached you will find the whole implementation of the handle watcher. Have fun and keep the copyright!

Klaus Triendl, Software Engineering Director @ FireDaemon Technologies Limited
Wednesday, September 16, 2015

Fixing InstallShield's Visual C++ 2015 Runtime Preqrequisite

NOTE: InstallShield Professional 2015 SP1 has been released which addresses this issue.

At FireDaemon we’re using cutting-edge production tools like Visual Studio 2015 Professional and InstallShield Professional 2015.

A C++ program usually depends on the C/C++ runtime and the recommended way of deploying it along with your product is by utilising the Visual C++ Redistributable for Visual Studio 2015 from Microsoft.

In order to create a pleasant end-user experience we are integrating the runtime package into our Session 0 Viewer installer as a "prerequisite". These are simply installer conditions packaged as .prq file. You can create such prerequisites on your own by using Installshield’s Prerequisite Editor. InstallShield however already provides a lot of such prerequisites, as you can figure from the following screenshot:

InstallShield Redistributables

The prerequisite file for the Visual C++ 2015 runtime isn’t included yet in InstallShield Professional 2015, but one can download it from their saturn server where they upload all the prerequisite files: download for x86, download for x64.

When we tested our installers we discovered a problem with the 32-bit installation on a 64-bit machine: Session 0 Viewer 32-bit wouldn’t work at all when we installed it after having installed and removed Session 0 Viewer 64-bit. We noticed that the 32-bit runtime wouldn’t get installed!

After investigating the problem further it turned out that the prerequisite for the 32-bit runtime checks the following registry key by default to have a certain value:

HKLM\SOFTWARE\Wow6432Node
    \Microsoft\DevDiv\VC\Servicing\14.0\RuntimeMinimum\UpdateVersion


Unfortunately, this key is not only set by the 32-bit redistributable but also by the 64-bit redistributable:

InstallShield Prerequisites

The quick solution is simple: create your own prerequisite that doesn’t check for this specific registry value but where the DLL is explicitly present: %SystemRoot%\SysWOW64\vcruntime140.dll.

Since this is clearly an InstallShield issue we opened a support case and they confirmed the prerequisite needs to be updated. Good news! Here’s an excerpt of the communication with Flexera support:

“Hi Klaus,

I have an update from our engineering team regarding this case. They have updated the conditions on the C++ 2015 Prerequisite so that it is not incorrectly detected as installed when the x64 redistributable is installed. So the conditions will be correct when this prerequisite is released with InstallShield 2015 SP1. Thanks for reporting the issue.

Regards,

Flexera Software Support”


Klaus Triendl, Software Engineering Director @ FireDaemon Technologies Limited

Recent Posts



Tags


Archive

    Sign up for Product Updates and Discounts
    Captcha Image
    ×