Why does GetMessage not process WM_POWERBROADCAST messages? - winapi

I'm creating a hidden window for the purpose of handling messages. I'm experiencing that I do not receive WM_POWERBROADCAST messages in it's GetMessage loop. I do, however, receive it via my WNDPROC. I have confirmed that I do receive other messages in both locations.
Why is GetMessage not receiving WM_POWERBROADCAST?
WNDCLASSEX classInfo = {0};
classInfo.cbSize = sizeof(classInfo);
classInfo.style = WS_DISABLED;
// CustomWndProc just outputs the message and chains to DefaultWndProc
classInfo.lpfnWndProc = CustomWndProc;
classInfo.hInstance = GetModuleHandle(NULL);
classInfo.hCursor = NULL;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = L"MyMessageWindow";
ATOM windowClass = RegisterClassEx(&classInfo);
HWND messageWindow = CreateWindowEx(WS_EX_NOACTIVATE, L"MyMessageWindow",
L"Message Handling Window", WS_DISABLED, 0, 0, 0, 0, 0, NULL,
GetModuleHandle(NULL), NULL);
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
// This condition is never true.
if (message.message == WM_POWERBROADCAST)
std::cout << "Got WM_POWERBROADCAST" << std::endl;
}

That's because WM_POWERBROADCAST is a dispatched synchronously and so is not placed on the message queue.
In order for you to process it you need to handle it in your window procedure.

Related

WM_INPUT_DEVICE_CHANGE messages get lost when reading RAWINPUT via GetRawInputBuffer

I trying to write program that is working properly with GetRawInputBuffer API and consuming all input with little overhead on separate thread.
But I found that WM_INPUT_DEVICE_CHANGE messages get lost when reading RAWINPUT via GetRawInputBuffer instead of usual WM_INPUT approach.
My code (I removed some error checking):
void RawInputDeviceManager::RawInputManagerImpl::ThreadRun()
{
// if I set it to true then WM_INPUT_DEVICE_CHANGE does not come
constexpr bool buffered = false;
// prepare buffer for up to 32 raw input messages
m_InputDataBuffer.resize(std::max({ sizeof(RAWKEYBOARD), sizeof(RAWMOUSE), sizeof(RAWHID) }) * 32);
m_WakeUpEvent = ::CreateEventExW(nullptr, nullptr, 0, EVENT_ALL_ACCESS);
WNDCLASSEXW wc{};
wc.cbSize = sizeof(wc);
wc.lpszClassName = L"Message";
wc.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT
{
RawInputManagerImpl* manager = reinterpret_cast<RawInputManagerImpl*>(::GetWindowLongPtrW(hWnd, 0));
if (manager)
{
switch (message)
{
case WM_INPUT_DEVICE_CHANGE: // <== get lost after ::GetRawInputBuffer(..) call
{
manager->OnInputDeviceChange();
return 0;
}
case WM_INPUT:
{
manager->OnInput(reinterpret_cast<RAWINPUT*>(lParam));
return 0;
}
}
}
return ::DefWindowProcW(hWnd, message, wParam, lParam);
};
wc.cbWndExtra = sizeof(RawInputManagerImpl*); // add some space for this pointer
wc.hInstance = ::GetModuleHandleW(nullptr);
ATOM classAtom = ::RegisterClassExW(&wc);
HWND hWnd = ::CreateWindowExW(0, reinterpret_cast<LPCWSTR>(classAtom), nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, wc.hInstance, 0);
::SetWindowLongPtrW(hWnd, 0, reinterpret_cast<LONG_PTR>(this));
Register(hWnd);
// enumerate devices before start
OnInputDeviceChange();
// main message loop
while (m_Running)
{
MSG msg;
if (buffered)
OnInputBuffered();
while (true)
{
bool haveMessage = false;
if (buffered)
{
// retrieve any message but WM_INPUT
haveMessage = ::PeekMessageW(&msg, 0, 0, WM_INPUT - 1, PM_REMOVE) ||
::PeekMessageW(&msg, 0, WM_INPUT + 1, 0, PM_REMOVE);
}
else
{
// retrieve any message
haveMessage = ::PeekMessageW(&msg, 0, 0, 0, PM_REMOVE);
}
if (!haveMessage)
break;
// not needed since we are not interested in WM_CHAR or WM_DEADCHAR
//::TranslateMessage(&msg);
// dispatch message to WndProc
::DispatchMessageW(&msg);
}
// wait for new messages
::MsgWaitForMultipleObjectsEx(1, &m_WakeUpEvent, INFINITE, QS_ALLEVENTS, MWMO_INPUTAVAILABLE);
}
Unregister();
::DestroyWindow(hWnd);
::UnregisterClassW(reinterpret_cast<LPCWSTR>(classAtom), wc.hInstance);
}
bool RawInputDeviceManager::RawInputManagerImpl::Register(HWND hWnd)
{
RAWINPUTDEVICE rid[] =
{
// register for all HID device generic types (keyboard/mouse/joystick etc)
{
HID_USAGE_PAGE_GENERIC,
0,
RIDEV_DEVNOTIFY | RIDEV_INPUTSINK | RIDEV_PAGEONLY,
hWnd
}
};
return ::RegisterRawInputDevices(rid, ARRAYSIZE(rid), sizeof(RAWINPUTDEVICE));
}
void RawInputDeviceManager::RawInputManagerImpl::OnInputBuffered()
{
// Processing all pending WM_INPUT messages in message queue
while (true)
{
UINT size = static_cast<UINT>(m_InputDataBuffer.size());
RAWINPUT* input = reinterpret_cast<RAWINPUT*>(m_InputDataBuffer.data());
UINT result = ::GetRawInputBuffer(input, &size, sizeof(RAWINPUTHEADER));
if (result == 0 || result == static_cast<UINT>(-1))
return;
// hack for a undefined QWORD used in NEXTRAWINPUTBLOCK macro
using QWORD = __int64;
for (; result; result--, input = NEXTRAWINPUTBLOCK(input))
{
OnInput(input);
}
}
}
Is this bug in Windows?
PS: This WM_INPUT_DEVICE_CHANGE event was added in Windows Vista and have proven that it has some bugs in its implementation.
PPS: As a workaround I can subscribe to WM_DEVICECHANGE message via RegisterDeviceNotification but I not sure if I doing something wrong in this case.

WinAPI. DeviceIoControl - Check overlapped request result

I've got kernel mode driver which handles user-mode requests asynchronously. Maximum number of requests in the queue, lats say, 32. All the following requests are completed with STATUS_INSUFFICIENT_RESOURCE status. I need to check in user-mode app if the requests was completed with this status. That's my user-mode app code:
HANDLE hEvents[40] = { 0 };
OVERLAPPED ovls[40] = { 0 };
int index = 0;
while (true)
{
hEvents[index] = CreateEvent(NULL, FALSE, FALSE, NULL);
ZeroMemory(&ovls[index], sizeof(OVERLAPPED));
ovls[index].hEvent = hEvents[index];
BOOL res = DeviceIoControl(hDevice, SEND_REQUEST_CTL, nullptr, 0,
nullptr, 0, &dwBytesRet, &ovls[index]);
++index;
if (res == FALSE)
{
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING)
{
WaitForMultipleObjects(index, hEvents, TRUE, INFINITE);
for (int i = 0; i < index; ++i)
CloseHandle(hEvents[i]);
}
}
}
I have array of hEvents and array of OVERLAPPED structures, because I need to wait for requests completion. So I the idea is that when driver returns STATUS_INSUFFICIENT_RESOURCE I just waiting for completion of all the IRPs that were queued to driver.
The problem is in that even when driver calls
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, 0);
GetLastError() from user-mode app returns ERROR_IO_PENDING so I can't handle STATUS_INSUFFICIENT_BUFFER driver error.
So my question is how can I check in user-mode app, that IRP was completed with STATUS_INSUFFICIENT_RESOURCE status?

Open WinAPI Window on non-Main Thread

I'm building a real time graphics application and I've noticed that under certain conditions the operating system will post nonqueued messages that block my program. For example, this will happen during the entire time that a user is resizing the window.
To solve this problem, I would like to put the window on a different thread, but I read that this is a terrible idea because of the way windows messages work. Is it still a problem if I process all messages on the other thread, and never send or receive messages from the main thread? I'm thinking about setting up my own message queue with a mutex so I can pass the data I care about back and forth. If this won't work, are there any other ways to solve this problem?
Here's a simplified version of the code I'm running:
LRESULT CALLBACK WindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_SIZE) {
// This event gets called a lot
// Handle window resize
return 0;
} else {
return DefWindowProc(window, message, wParam, lParam);
}
}
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int numCmd) {
WNDCLASSA class = {};
class.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
class.lpfnWndProc = WindowCallback;
class.lpszClassName = "Name";
class.hInstance = instance;
RegisterClassA(&class)l
HWND win = CreateWindowExA(0, class.lpszClassName, "Name",
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
0, 0, instance, 0);
while(true) {
// Handle Events
MSG msg = {};
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Do Updating of State and Graphics Rendering Here
}
}
Thanks in advance!

Proper way of destroying window resources

This is excerpt from my code based on win32 api:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void __fastcall TMyThread::Execute(void)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = class_name.c_str();
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return;
}
hwnd = CreateWindowEx(0, class_name.c_str(), NULL, 0, 0, 0, 100, 100, HWND_MESSAGE, NULL, wc.hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error", MB_ICONEXCLAMATION | MB_OK);
return;
}
MSG msg;
BOOL ret;
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0)
{
if (ret != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
My questions:
Is it required to do some resource cleanup after quitting message loop (like CloseHandle for example)? Quite often i am seeing code samples without any such things. Is it correct?
Can newly created window receive messages into thread queue before first call of GetMessage function (we suppose that window was successfully created i.e. function CreateWindowEx returned without errors)?
Please take in mind that TMyThread is not main thread of application. So it can be created and destroyed many times in one application run. Please don't pay attention to quite simplified window creation. This particular window is not meant to be visible on screen. It is created solely for purpose of receiving messages from another application. This is highlighted by using HWND_MESSAGE value of hWndParent parameter when calling CreateWindowEx function.
By creating, running and destroying thread in the above example again and again I have found out that two methods needs to be called after quitting from message loop. First is DestroyWindow and second is UnregisterClass. In regular application DestroyWindow function should be called in WM_CLOSE handler after the user confirms that he really wants to close the application. DestroyWindow function then sends WM_DESTROY and WM_NCDESTROY messages to window. In response to WM_DESTROY message application should call PostQuitMessage(0) function which results to immediately quitting message loop. So this part of code is not neccessary in all scenarios. I needed to call DestroyWindow function explicitly because I exit message loop by simply sending WM_QUIT message. When not doing it sometimes I received error 1412 (ERROR_CLASS_HAS_WINDOWS) when trying to unregister window class.
if (hwnd != NULL)
{
ret = DestroyWindow(hwnd);
if (ret == 0)
{
str.printf(L"Window destroying failed (GetLastError = %d)!", GetLastError());
ShowError(str);
}
hwnd = NULL;
}
ret = UnregisterClass(class_name.c_str(), wc.hInstance);
if (ret == 0)
{
str.printf(L"Window class unregistration failed (GetLastError = %d)!", GetLastError());
ShowError(str);
}
You must be very careful with resources in Win32. Make sure you've looked at the documentation carefully to determine what Windows itself will unload for you and what you have to unload yourself.
For examples, HWNDs will get destroyed as parent HWNDs get destroyed.
The best trick is to attempt to unload everything you've personally created. If you get an error returned from a particular function on unload, you likely should not unload it as it's been unloaded by Windows or some related resource.
It is important not to unload things when it is not necessary, as that could cause a crash.
So for example, an icon created with a window that's directly from a resource likely shouldn't be unloaded. But an HBITMAP you create that you draw to other windows, should most definitely be unloaded.
Your section question can be determined by a quick test with breakpoints. I do not know off the top of my head.

Does marshaling a marshaled interface give me a marshaller to the proxy or the original interface?

Here is a concrete example:
I create a IWeBrowser2 interface by calling wb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);. This gives me a marshaled interface from my process into whichever of the running iexplore.exe processes happens to contain this browser tab in my thread A.
Now I use the IGlobalInterfaceTable to get a cookie for this interface, pass it to my thread B and request the marshaled interface from there.
Question: Do I get a proxy to the proxy in my thread A or directly to the instance in the IE process?
It seems sensible to me that I will get a direct proxy to the instance with its own reference to it, however:
If I end my thread A, the cookie I created there becomes invalid and I can't retrieve (and close) the interface pointers to the web browsers I created any more. This does not make sense unless there is a thunk in that thread that is destroyed when the thread quits.
Edit: Oh, both threads are STA.
I finally had some time to figure out what is happening, so I wrote a short test to see what is going on.
// MarshalTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
enum { WM_THEREYOUGO = WM_USER+1, WM_THANKYOU, WM_YOURWELCOME };
DWORD WINAPI TheOtherThread(DWORD * main_thread_id)
{
MSG msg = { 0 };
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
assert(SUCCEEDED(hr));
{
// create web browser
CComPtr<IWebBrowser2> wb;
hr = wb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);
assert(SUCCEEDED(hr) && wb);
// navigate
hr = wb->Navigate2(&CComVariant(_T("stackoverflow.com")), &CComVariant(0), &CComVariant(_T("")), &CComVariant(), &CComVariant());
assert(SUCCEEDED(hr));
hr = wb->put_Visible(VARIANT_TRUE);
assert(SUCCEEDED(hr));
// Marshal
DWORD the_cookie = 0;
{
CComPtr<IGlobalInterfaceTable> com_broker;
hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
assert(SUCCEEDED(hr));
hr = com_broker->RegisterInterfaceInGlobal(wb, __uuidof(IWebBrowser2), &the_cookie);
}
// notify main thread
PostThreadMessage(*main_thread_id, WM_THEREYOUGO, the_cookie, NULL);
// message loop
while(GetMessage(&msg, 0, 0, 0)) {
if(msg.hwnd == NULL) {
// thread message
switch(msg.message) {
case WM_THANKYOU:
PostQuitMessage(0);
break;
}
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
CoUninitialize();
PostThreadMessage(*main_thread_id, WM_YOURWELCOME, 0, NULL);
return msg.wParam;
}
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg = {0};
DWORD main_thread_id = GetCurrentThreadId();
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
assert(SUCCEEDED(hr));
{
DWORD ThreadId = 0;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TheOtherThread, &main_thread_id, 0, &ThreadId);
DWORD the_cookie = 0;
CComPtr<IWebBrowser2> wb, wb2;
while(GetMessage(&msg, 0, 0, 0)) {
if(msg.hwnd == NULL) {
// thread message
switch(msg.message) {
case WM_THEREYOUGO:
// we got the cookie.
the_cookie = msg.wParam;
// get the browser. This should work.
{
CComPtr<IGlobalInterfaceTable> com_broker;
hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
assert(SUCCEEDED(hr));
hr = com_broker->GetInterfaceFromGlobal(the_cookie, __uuidof(IWebBrowser2), (void**)&wb);
assert(SUCCEEDED(hr) && wb);
}
// do something with it.
hr = wb->put_FullScreen(VARIANT_TRUE);
assert(SUCCEEDED(hr));
// signal the other thread.
PostThreadMessage(ThreadId, WM_THANKYOU, 0, NULL);
break;
case WM_YOURWELCOME:
// the other thread has ended.
PostQuitMessage(0);
break;
}
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// the other thread has ended. Try getting the interface again.
{
CComPtr<IGlobalInterfaceTable> com_broker;
hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
assert(SUCCEEDED(hr));
hr = com_broker->GetInterfaceFromGlobal(the_cookie, __uuidof(IWebBrowser2), (void**)&wb2);
//assert(SUCCEEDED(hr) && wb2); // this fails, hr == E_INVALIDARG.
// clean up, will not be executed.
if(SUCCEEDED(hr)) {
hr = com_broker->RevokeInterfaceFromGlobal(the_cookie);
}
}
// try using it
if(wb2) {
hr = wb2->put_FullScreen(VARIANT_FALSE);
assert(SUCCEEDED(hr));
} else if(wb) {
// this succeeds
hr = wb->put_FullScreen(VARIANT_FALSE);
assert(SUCCEEDED(hr));
}
CloseHandle(hThread);
}
CoUninitialize();
return msg.wParam;
}
The bottom line is this:
Ending the thread that registered the interface invalidates the cookie.
The already marshaled interface stays valid. (In this case, that is.)
This means that I get a proxy to the IE process instead of to the other thread's object.
You already got a proxy on thread A since you asked for an out-of-process server. What happens next depends on the kind of apartment that thread A lives in, the argument to CoInitializeEx(). If it is MTA you will definitely get the same proxy in thread B, assuming it is MTA as well. The added reference count should keep it alive if Thread A exits. If it is STA then I'm not 100% sure but think you ought to get a new one. Easy to test btw, just use the one from thread A and you'll get RPC_E_WRONGTHREAD if a new one would have to be created.
I don't have a great explanation for why the thread A exit kills the proxy for thread B. Unless you call IGlobalInterfaceTable::RevokeInterfaceFromGlobal(). Which you'd normally do.

Resources