Not getting WM_CLOSE or WM_DESTROY with Raw Input

Started by
4 comments, last by jwezorek 12 years, 3 months ago
Here is my Raw Input initialization code:


//init code
bool ExtendedWindowsAPI::ExtendedInput::CRawInputController::initialize(){
RAWINPUTDEVICE rid[2]; //2 RI Devices

rid[0].usUsagePage = 0x01; //Desktop controls
rid[0].usUsage = 0x02; //Mouse
rid[0].dwFlags = this->Mouse_Flags; //Mouse Flags
rid[0].hwndTarget = this->pInputWindow->GetHandle(); //Mouse Window
rid[1].usUsagePage = 0x01; //Desktop controls
rid[1].usUsage = 0x06; //Keyboard
rid[1].dwFlags = this->Keyboard_Flags; //Keyboard Flags
rid[1].hwndTarget = this->pInputWindow->GetHandle(); //Keyboard Window
if(!RegisterRawInputDevices(rid, 2, sizeof(rid[0]))){
this->log(LEVEL_ERROR, "Failed to register Raw Input devices (Mouse + Keyboard)");
return false;
}
//Set the current mouse position
POINT p;
GetCursorPos(&p);
this->mouse_info->absX = p.x;
this->mouse_info->absY = p.y;
return true;
}


Here's the problem. Whenever I use Raw Input in my code, my window does not receive messages such as WM_DESTROY and WM_CLOSE, which means the application cannot shut down properly. Whenever I comment out pRawInput->initialize() and all code that reads from Raw Input, I magically get WM_DESTROY and WM_CLOSE again. I think the problem is somewhere in my initialization code.

Thanks in advance,
Sepiantum
Follow and support my game engine (still in very basic development)? Link
Advertisement
Need more information ...

If you leave in the call to RegisterRawInputDevices but comment out your WM_INPUT handler, what happens?

Is the window actually closing or is the app crashing? How are you closing it? -- via DestroyWindow() or through the GUI or by keyboard shortcut?
The window closes, but the process stays open because WM_DESTROY is never received through WndProc so I cannot call PostQuitMessage and break out of the loop by testing for WM_QUIT.

This is the code for processing the messages:

//Message procedure
LRESULT CALLBACK CGameWindow::HandleMessage(UINT Msg, WPARAM wParam, LPARAM lParam){
//Handle stuff, return superclass method
switch(Msg){
case WM_DESTROY:
{
LRESULT ret = this->CWindow::HandleMessage(Msg, wParam, lParam);
PostQuitMessage(0);
return ret;
break;
}
case WM_INPUT:
//Dispatch off to RawInput and we don't care anymore >:D
//this->pRawInput->ProcessInputs(reinterpret_cast<HRAWINPUT>(lParam));
//MessageBox(this->hWnd, L"Received input message", L"YAY", MB_OK);
return 0;
break;
default:
return this->CWindow::HandleMessage(Msg, wParam, lParam);
}
return this->CWindow::HandleMessage(Msg, wParam, lParam);
}

LRESULT CALLBACK ExtendedWindowsAPI::ExtendedWindows::CWindow::HandleMessage(UINT Msg, WPARAM wParam, LPARAM lParam){
//We will setup vital stuff such as the menu and removing this from CWindowManager
//Upon destruction

switch(Msg){
case WM_CLOSE:
DestroyWindow(this->hWnd);
break;
case WM_DESTROY:
{
//2 cases, this has a parent or this does not have a parent
if(this->pParent == nullptr){
//No parent
//This will always break on error
//Remove from CWindowManager
int WndID = reinterpret_cast<int>(GetPropW(this->hWnd, L"ID")); //ID Stored by pManager->CreateWindow(...)
ExtendedWindowsAPI::ExtendedWindows::CWindowManager* pManager =
reinterpret_cast<ExtendedWindowsAPI::ExtendedWindows::CWindowManager*>(GetPropW(this->hWnd, L"pWindowManager")); //Local, do not use delete

if(!pManager){
//Null checks
this->log(LEVEL_ERROR, "pWindowManager is somehow null");
break;
}

if(!pManager->RemoveWindow(WndID)){
//This is bad...
//Will cause an error in delete pWindowManager?
this->log(LEVEL_ERROR, "Failed to remove a window with id: %d", WndID);
break;
}

//Remove all properties after window manager is done
RemovePropW(this->hWnd, L"pWindowManager");
RemovePropW(this->hWnd, L"ID");
RemovePropW(this->hWnd, L"this");
} else {
//Parent
//Child windows should be destroyed before the parent is destroyed
int WndID = reinterpret_cast<int>(GetPropW(this->hWnd, L"ID")); //ID Stored by pManager->CreateChild(...)
ExtendedWindowsAPI::ExtendedWindows::CChildManager* pManager =
reinterpret_cast<ExtendedWindowsAPI::ExtendedWindows::CChildManager*>(GetPropW(this->hWnd, L"pChildManager")); //Local, do not use delete

//Null checks
if(!pManager){
this->log(LEVEL_ERROR, "pChildManager is somehow null");
break;
}

if(!pManager->RemoveChild(WndID)){
//This is bad...
this->log(LEVEL_ERROR, "Failed to remove a child with id: %d", WndID);
break;
}

//Remove all extra properties
RemovePropW(this->hWnd, L"pChildManager");
RemovePropW(this->hWnd, L"ID");
RemovePropW(this->hWnd, L"this");
}

//Reset window_exists
this->window_exists = false;

//Break and return DefWindowProc(...)
break;
}
default:
return DefWindowProc(this->hWnd, Msg, wParam, lParam);
}

return DefWindowProc(this->hWnd, Msg, wParam, lParam);
}


UPDATE: I set breakpoints within WM_DESTROY, and I am getting the message. I do call PostQuitMessage(0), but testing for WM_QUIT in the message loop seems to always fail.

Message loop:

//run()
int CStemManager::run(){
//Message pump - Game oriented
MSG Msg;

while(TRUE){
//Loop through each message
while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)){
//Translate and dispatch each message received
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

//Check for quits
if(Msg.message == WM_QUIT){
break;
}

//Do stuff
//this->pGameWindow->run();
}

return static_cast<int>(Msg.wParam);
}
Follow and support my game engine (still in very basic development)? Link
The way you have your wndproc set up is wrong. After the switch statement, you are always returning the result of DefWindowProc(...). This is not what you want. Message handlers for a given message need to return values specific to the message. You can find out about what value you need to return for a given message by reading the docs on that message. You should only return DefWindowProc(...) for messages that you are intentionally not handling. Short version: all the "break" statements in your wndprox should be "return x" statements where x is some value that depends on the message.
As far as that goes, I have never seen a difference between using return and calling DefWindowProc. Is there any specific reason I should be returning values such as 0 instead of what DefWindowProc returns, or is it just convention? Anyways, adding a bool to control the outer loop, placing the quit checking inside the nested while and setting the bool to false seems to fix my problem.
Follow and support my game engine (still in very basic development)? Link
DefWindowProc actually does something: it provides default functionality. In many cases you don't want default functionality so you shouldn't call it in those cases.

This topic is closed to new replies.

Advertisement