So I've been trying to figure the following:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC; // Display context handle
PAINTSTRUCT PaintSt; // Structure defining area to be drawn
RECT aRect; // A working rectangle
HPEN hPen; // A working pen
HBRUSH hBrush; // A working brush
switch(message)
{
case WM_TIMER:
switch(wParam)
{
case IDT_TIMER1:
redraw = true;
InvalidateRect(hWnd, NULL, TRUE);
case IDT_TIMER2:
if(keys[UP])
{
rect2.bottom -= 5;
rect2.top -= 5;
}
if(keys[DOWN])
{
rect2.bottom += 5;
rect2.top += 5;
}
if(keys[RIGHT])
{
rect2.left += 5;
rect2.right += 5;
}
if(keys[LEFT])
{
rect2.left -= 5;
rect2.right -= 5;
}
}
return 0;
case WM_PAINT:
//if(redraw)
{
redraw = false;
render_frame();
}
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_UP:
keys[UP] = true;
break;
case VK_DOWN:
keys[DOWN] = true;
break;
case VK_LEFT:
keys[LEFT] = true;
break;
case VK_RIGHT:
keys[RIGHT] = true;
break;
default:
break;
}
return 0;
case WM_KEYUP:
switch(wParam)
{
case VK_UP:
keys[UP] = false;
break;
case VK_DOWN:
keys[DOWN] = false;
break;
case VK_LEFT:
keys[LEFT] = false;
break;
case VK_RIGHT:
keys[RIGHT] = false;
break;
default:
break;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam); // default message processing
}
}
So here's the problem: in the case WM_PAINT:, when I uncomment the if statement, the time stops ticking for some reason. I have no idea why and don't know how to correlate this with anything. So, if I uncomment it, it will not render nor it will it recieve information from the other timer (there are two timers). Please help me, and please don't laugh if it is silly.
The WM_TIMER message is a "low priority" message, it is only generated when nothing else needs to be done. The trouble with your WM_PAINT handler is that it doesn't paint the first time it is generated, immediately after creating the window. EndPaint() isn't called, Which leaves the "window is dirty" status bit turned on. Which immediately causes another WM_PAINT message to be generated. Which still won't paint because redraw isn't true. Etcetera, your app is burning 100% core on the WM_PAINT messages and never gets idle enough to allow a WM_TIMER message to be generated.
Simply remove the redraw test to fix your problem. Always draw when Windows asks for it. Or pass the message to DefWindowProc().
Handling WM_PAINT without drawing anything (assuming redraw stays false), and without even calling DefWindowProc is very unorthodox. Your app might even be alive without you noticing.
From the doc:
An application must call BeginPaint and EndPaint in response to
WM_PAINT messages, or pass the message to the DefWindowProc function
to validate the window. DefWindowProc validates the update region; it
can send the WM_ERASEBKGND message if the window background needs to
be erased.
Related
Hi guys.
I have some overlay with lua support.
I need to create some WndProc callbacks, so I hooked WndProc of target window using SetWindowLong and saving old one
LRESULT CALLBACK nProc(HWND hWnd, UINT _Msg, WPARAM wP, LPARAM lP) // its new wndProc
{
switch (_Msg)
{
case WM_CUT: case WM_COPY: case WM_PASTE: case WM_CLEAR:
return 1;
case WM_DESTROY: case WM_NCDESTROY:
UnhookWndP(); // switching back to original wndProc
return 1;
case WM_KEYDOWN: case WM_KEYUP: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MOUSEWHEEL:
try
{
if (_Msg == WM_KEYUP && wP == 120) // restart LuaState
{
if (LuaInit)
DelLua();
else
CreLua();
}
for (luabridge::LuaRef f : wndCall) // call all our WndProc Lua callbacks
{
if (Msg != NULL && wP != NULL && f.isFunction() && f.isFunction() && lua_gettop(L) == 0)
{
f((int)_Msg, wP); // always in callstack when error occurs
}
}
}
catch (luabridge::LuaException ex) { Msg(ex.what()); }
default:
return CallWindowProc(OriWndP, hWnd, _Msg, wP, lP);
}
}
Created global function for adding callback, which is saving func to wndCall Vector(LuaRef)
Lua part is working fine. It shows messages of WM_KEY... events successfully.
The only problem is: When i hold some button or spamming commands I got Crash with Random error :(
I think its because CALLBACK got hit multiple times at one tick and something got broken in LuaState or idk.
Please help me find a solution or some extra checks for WndProc func.
my application is running in Background completely but shows it's activity via a notification icon in system tray. Now I wanted to add a popup-menu to that notification icon. Unfortunately I do not receive any events from it. That's what I'm doing currently to create the icon and its event handler:
First create an invisible window to use it's event handler
ZeroMemory(&wc,sizeof(WNDCLASSEX));
wc.cbSize=sizeof(WNDCLASSEX);
wc.lpfnWndProc=WndProc;
wc.hInstance=hInstance;
wc.lpszClassName=L"myCL";
RegisterClassEx(&wc);
hWnd=CreateWindowEx(WS_EX_CLIENTEDGE,L"myCL",L"myWN",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
CW_USEDEFAULT,1,1,NULL,NULL,hInstance,NULL);
Next create and show the icon itself:
ZeroMemory(&niData,sizeof(NOTIFYICONDATA));
niData.cbSize=sizeof(NOTIFYICONDATA);
niData.uID=IDI_AAAA; // the icon's identifier
niData.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
niData.hIcon=(HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_AAAA),IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
niData.hWnd=hWnd;
niData.uCallbackMessage=MY_TRAY_ICON_MESSAGE;
Shell_NotifyIcon(NIM_ADD,&niData);
And the event handler that is assigned to the invisible window and where I would have assumed the events from the icon should arrive too:
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case MY_TRAY_ICON_MESSAGE: // this should be related to notification icon but is never called
switch (lParam)
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
break;
}
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
Anybody an idea what is wrong here?
Currently I am developing some custom controls and the problem I'm currently facing is that I don't know how to detect when my custom control needs redrawing.
I use WM_PAINT to draw everything, so I relly on RedrawWindow() function. However when my custom control moves outside drawing area and then comes back, it doesn't redraw. I tried catching WM_NCPAINT which works great, but then it sends WM_PAINT messages every time I move mouse inside parent window.
So my question is - how do I detect when to redraw child window after it comes back to drawing area?
Below is my code for CALLBACK:
LRESULT CALLBACK WinMsgHandler(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
settings.TrackingEvent.hwndTrack = hWnd;
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
switch (settings.CurrentState)
{
case cctrl_UNSELECTED_HOVER:
On_UnselectedHover(&hdc, &ps.rcPaint);
break;
case cctrl_UNSELECTED:
On_Unselected(&hdc, &ps.rcPaint);
break;
case cctrl_SELECTED_HOVER:
On_SelectedHover(&hdc, &ps.rcPaint);
break;
case cctrl_SELECTED:
On_Selected(&hdc, &ps.rcPaint);
break;
case cctrl_3STATE_HOVER:
On_IntermediateHover(&hdc, &ps.rcPaint);
break;
case cctrl_3STATE:
On_Intermediate(&hdc, &ps.rcPaint);
break;
default:
break;
}
EndPaint(hWnd, &ps);
}
break;
case WM_NCPAINT:
RedrawWindow(hWnd, NULL, NULL, RDW_ERASE | RDW_FRAME
| RDW_INVALIDATE | RDW_ALLCHILDREN);
break;
case WM_MOUSEMOVE:
On_MouseMove();
break;
case WM_MOUSEHOVER:
On_MouseHover();
break;
case WM_MOUSELEAVE:
On_MouseLeave();
break;
case WM_LBUTTONDOWN:
On_LButtonDown();
break;
case WM_LBUTTONUP:
On_LButtonUp();
break;
case WM_DESTROY:
OnDestroy();
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
Currently, I am creating my own function onPress and onRelease. However, I am having problem with my onRelease function. Apparently, my onRelease kept on triggering even if I have not release my keyboard.
I suspected it has to do with the number of cycle inside the CPU but I wasn't sure of this theory. Somehow, maybe the cycle is slower than my frame, that why the PeerMessage return false? As no event was triggered.
Solution to it:
**Under the WinProc function create a new case called WM_KEYUP. This event will trigger once the user leave the button. It help to solve the number of cycle inside the CPU issued.
**
*Note:
I have update my detail of my code.
Description. Window Programming
I have two std::array that store my keyboard data
1) InputCurr
2) InputPrev
std::array<char, 256> inputPrev;
std::array<char, 256> inputCurr;
While(TRUE) {
std::copy(InputCurr.begin(), InputCurr.end(), InputPrev.begin());
inputCurr.fill(0);
while(PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&uMsg);
DispatchMessage (&uMsg);
}
if(onReleased(x030)) //Button 0
//do something
}
char onReleased(char key)
{
return (inputCurr[key] && !inputPrev[key])? 1 : 0;
}
void VEInputMessage(WPARAM key)
{
inputCurr[key]= 1; //Set to true of the keyboard key
}
LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC dc; /* device context */
PAINTSTRUCT ps; /* the paint struct */
RECT rect;
UNREFERENCED_PARAMETER(rect);
switch (msg)
{
/* when the window is created */
case WM_CREATE:
break;
/* when the rectangle is drawn */
case WM_LBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
case WM_PAINT:
dc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
/* When it's time for the window to be closed and removed */
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
VEINPUT::VEInputMessage(wParam); //Updated the input key
if(wParam == AEVK_ESCAPE)
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
I've created a custom message type for use in resizing my Window, called WM_NEED_RESIZE. I've defined it in my .h file, and initialized in my .cpp file. I have also registered my WindowProc function to accept messages. Here is the code for these items:
const uint32 WindowsGLWindow::WM_NEED_RESIZE = WM_USER + 100;
LONG WINAPI WindowsGLWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;// do I need this?
static sint32 newWidth = 0;
static sint32 newHeight = 0;
bool res = false;
switch (uMsg) {
case WM_PAINT:
//display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
//glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
res = PostMessage(hWnd, WindowsGLWindow::WM_NEED_RESIZE, wParam, lParam);
std::cout << "WM_SIZE: " << res << std::endl;
return 0;
case WindowsGLWindow::WM_NEED_RESIZE:
std::cout << "WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
break;
case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
In another function I am running through PeekMessage(..) to collect all messages. Here is the snippet of the message pump:
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) == TRUE) // maybe use GetInputState(?) as well?
{
if (msg.message == WM_QUIT)
retVal = -1;
if (msg.message == WindowsGLWindow::WM_NEED_RESIZE) {
uint32 newWidth = LOWORD(msg.lParam);
uint32 newHeight = HIWORD(msg.lParam);
std::cout << "PeekMessage: WindowsGLWindow::WM_NEED_RESIZE" << std::endl;
// call resize only if our window-size changed
if ((newWidth != width_) || (newHeight != height_)) {
resize(newWidth, newHeight);
}
PostMessage(msg.hwnd, WM_PAINT, 0, 0);
}
switch (msg.message) {
case WM_MOUSEMOVE:
// Retrieve mouse screen position
//int x = (short) LOWORD(lParam);
//int y = (short) HIWORD(lParam);
// Check to see if the left button is held down:
//bool leftButtonDown = wParam & MK_LBUTTON;
// Check if right button down:
//bool rightButtonDown = wParam & MK_RBUTTON;
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_KEYUP:
case WM_KEYDOWN:
/*
switch (msg.wParam) {
case 'W':
// w key pressed
break;
case VK_RIGHT:
// Right arrow pressed
break;
default:
break;
}
*/
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
My problem is that the WM_NEED_RESIZE message is only found once in the message queue when the window first opens, after which it is never found in the message queue by my PeekMessage(..). I'm really not sure why this is happening. It is, however, being received by the WindowProc(..) method (which doesn't really help me). I would appreciate any help you guys could provide.
Thanks
Jarrett
Dont use std::cout expecting to see that output in your debugger, insted use OutputDebugString(); .
You need to pass your class pointer to the last parameter of your call to CreateWindowEx, then retrieve that pointer from the LPCREATESTRUCT passed to you in the LPARAM of WM_CREATE, your class pointer will be in the lpCreateParmas feild of the struct. Set your clas pointer to the GWLP_USERDATA of your window, and on any other message calls , call GetWindowsLong , retrieve your class pointer, then pass the message, wparam, and lparam all off to your internal class message handler.
http://msdn.microsoft.com/en-us/library/ff381400%28v=VS.85%29.aspx
The message pump loop that you are showing will exit as soon as the queue is empty. I can't tell from what you've posted if it ever gets entered again.
If this is your main message pump, you should use GetMessage() instead, as it will wait until something is available before returning. Take a look at this MSDN article for more info.