Shudrik Nikolay
Shudrik Nikolay

Reputation: 23

Cannot receive WM_CLIPBOARDUPDATE messages

I am trying to use Clipboard Format Listener for my C++ Console Application. The goal is to monitor every change in the clipboard. I create MessageOnly window, successfully call AddClipboardFormatListener in WM_CREATE, but never get WM_CLIPBOARDUPDATE message in WindowProc function.

#include <iostream>
#include "windows.h"

using namespace std;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        if (AddClipboardFormatListener(hwnd))
            cout << "    Listener started" << endl;
        else
            cout << "    Start listener failed" << endl;
        break;

    case WM_DESTROY:
        if (RemoveClipboardFormatListener(hwnd))
            cout << "    Listener stopped" << endl;
        else
            cout << "    Stop listener failed" << endl;
        break;

    case WM_CLIPBOARDUPDATE:
        // Clipboard content has changed

        cout << "    Clipboard updated" << endl;
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int main(int argc, char* argv[])
{
    HWND hWindow = nullptr;

    static const wchar_t* className = L"ClipboardListener";
    WNDCLASSEX wx = {};
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = WindowProc;
    wx.hInstance = GetModuleHandle(NULL);
    wx.lpszClassName = className;
    if (!RegisterClassEx(&wx)) {
        cout << "Cannot register class" << endl;
    }
    else
    {
        hWindow = CreateWindowEx(
            0,
            className,
            L"ClipboardListener",
            0, 0, 0, 0, 0,
            HWND_MESSAGE,
            NULL, NULL, NULL);
    }

    if (!hWindow)
    {
        cout << "Cannot create window" << endl;
    }
    else
    {
        while (true)
        {
            // Peek for a WM_CLIPBOARDUPDATE message
            MSG message = { 0 };
            PeekMessage(&message, hWindow, WM_CLIPBOARDUPDATE, WM_CLIPBOARDUPDATE, PM_REMOVE);
            if (message.message == WM_CLIPBOARDUPDATE)
            {
                cout << "Sample window received WM_CLIPBOARDUPDATE message" << endl;
            }
        }   
    }

    cin.get();

    DestroyWindow(hWindow);

    return 0;
}

PeekMessage works well, but I don't want to use loop to receive messages. If I delete PeekMessage or replace PM_REMOVE with PM_NOREMOVE, nothing changes.

Upvotes: 1

Views: 637

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597016

Your message loop is wrong.

CreateWindowEx() sends a WM_CREATE message before exiting, which is why your WindowProc() receives that message.

However, PeekMessage() does not dispatch messages to windows, which is why your WindowProc() does not receive the WM_CLIPBOARDUPDATE messages. Your message loop needs to call DispatchMessage() for that. You should also be using GetMessage() instead of PeekMessage(), so that the loop makes the calling thread sleep when there are no messages to process.

A standard message loop looks more like this:

MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
    TranslateMessage(&message);
    DispatchMessage(&message);
}

Upvotes: 2

Related Questions