Certain Windows notifications, such as mixer control changes or device arrival/removal, are only delivered as window messages. Since window message handling is inside the JUCE native code, I have implemented my own hidden window whose sole purpose is to receive these notifications.
To use it, have one of your classes inherit from this one:
class Win32MessageListener
{
protected:
virtual void Win32MessageReceived(UINT uMsg,WPARAM wParam,LPARAM lParam) = 0;
friend class Win32NotificationWindow;
};[/code]
Then, implement the Win32MessageReceived method in you class and then do this:
[code]Win32NotificationWindow::instance()->addListener(this);
Here is the class definition for the notification window:
[code]class Win32NotificationWindow :
public DeletedAtShutdown
{
public:
static Win32NotificationWindow *instance();
virtual ~Win32NotificationWindow();
HWND handle()
{
return hWindow;
}
void addListener(Win32MessageListener *wml);
void removeListener(Win32MessageListener *wml);
protected:
Win32NotificationWindow();
static DWORD WINAPI WndThread(LPVOID context);
static LRESULT CALLBACK WndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam );
HWND hWindow;
HANDLE hThread;
Array<Win32MessageListener *> listeners;
CriticalSection cs;
};
[/code]
And the implementation:
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "juce.h"
#include "NotificationWindow.h"
static char classname[] = "notification msg window";
static Win32NotificationWindow *gInstance = NULL;
Win32NotificationWindow *Win32NotificationWindow::instance()
{
if (NULL == gInstance)
gInstance = new Win32NotificationWindow;
return gInstance;
}
Win32NotificationWindow::Win32NotificationWindow() :
hThread(NULL),
hWindow(NULL),
listeners(3)
{
//
// register the window class
//
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Win32NotificationWindow::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(NULL);
wcex.hIcon = 0;
wcex.hCursor = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = classname;
wcex.hIconSm = 0;
RegisterClassEx(&wcex);
//
// make the window
//
hWindow = CreateWindow(classname, NULL, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL);
if (hWindow == NULL)
return;
//
// Save the "this" pointer in the window
//
SetWindowLongPtr(hWindow,GWLP_USERDATA,(LONG_PTR) this);
//
// start the thread for the window messsage loop
//
DWORD threadid;
hThread = CreateThread(NULL,
0,
&Win32NotificationWindow::WndThread,
this,
0,
&threadid);
}
Win32NotificationWindow::~Win32NotificationWindow()
{
if (hWindow)
{
PostMessage(hWindow,WM_CLOSE,0,0);
if (hThread)
{
WaitForSingleObject(hThread,2000);
CloseHandle(hThread);
}
}
}
LRESULT CALLBACK Win32NotificationWindow::WndProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
Win32NotificationWindow *that;
int i;
that = (Win32NotificationWindow *) GetWindowLongPtr(hwnd,GWLP_USERDATA);
if (that)
{
ScopedLock sl(that->cs);
for (i = 0; i < that->listeners.size(); i++)
{
that->listeners[i]->Win32MessageReceived(uMsg,wParam,lParam);
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
DWORD WINAPI Win32NotificationWindow::WndThread(LPVOID context)
{
MSG Msg;
Win32NotificationWindow *that;
int rval;
that = (Win32NotificationWindow *) context;
//
// listen to the message loop
//
while ( (rval = GetMessage(&Msg, that->hWindow, 0, 0)) != 0)
{
if (-1 == rval)
return 0;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return (DWORD) Msg.wParam;
}
void Win32NotificationWindow::addListener(Win32MessageListener *wml)
{
ScopedLock sl(cs);
listeners.addIfNotAlreadyThere(wml);
}
void Win32NotificationWindow::removeListener(Win32MessageListener *wml)
{
ScopedLock sl(cs);
listeners.removeValue(wml);
}
#endif