ntdll.dll!_KiFastSystemCallRet@0() user32.dll!_NtUserMessageCall@28() + 0xc bytes user32.dll!_RealDefWindowProcWorker@20() - 0x79d6 bytes user32.dll!_RealDefWindowProcW@16() + 0x27 bytes uxtheme.dll!DoMsgDefault() + 0x29 bytes uxtheme.dll!OnDwpSysCommand() + 0x29 bytes uxtheme.dll!_ThemeDefWindowProc() + 0x61a8 bytes uxtheme.dll!_ThemeDefWindowProcW@16() + 0x18 bytes user32.dll!_DefWindowProcW@16() + 0x815 bytes > Tutorial02.exe!D3DWindow::WndProc(unsigned int uMsg=274, unsigned int wParam=61458, long lParam=5636612) Line 227 + 0x1b bytes C++ Tutorial02.exe!D3DWindow::StaticWndProc(HWND__ * hWnd=0x000a06fa, unsigned int uMsg=274, unsigned int wParam=61458, long lParam=5636612) Line 169 + 0x1a bytes C++ user32.dll!_InternalCallWinProc@20() + 0x23 bytes user32.dll!_UserCallWinProcCheckWow@32() - 0xddcf bytes user32.dll!_DispatchClientMessage@20() + 0x4b bytes user32.dll!___fnDWORD@4() + 0x24 bytes ntdll.dll!_KiUserCallbackDispatcher@12() + 0x2e bytes user32.dll!_NtUserMessageCall@28() + 0xc bytes user32.dll!_RealDefWindowProcWorker@20() - 0x79d6 bytes user32.dll!_RealDefWindowProcW@16() + 0x27 bytes uxtheme.dll!DoMsgDefault() + 0x29 bytes uxtheme.dll!OnDwpNcLButtonDown() + 0x32 bytes uxtheme.dll!_ThemeDefWindowProc() + 0x61a8 bytes uxtheme.dll!_ThemeDefWindowProcW@16() + 0x18 bytes user32.dll!_DefWindowProcW@16() + 0x815 bytes Tutorial02.exe!D3DWindow::WndProc(unsigned int uMsg=161, unsigned int wParam=2, long lParam=5636612) Line 227 + 0x1b bytes C++ Tutorial02.exe!D3DWindow::StaticWndProc(HWND__ * hWnd=0x000a06fa, unsigned int uMsg=161, unsigned int wParam=2, long lParam=5636612) Line 169 + 0x1a bytes C++ user32.dll!_InternalCallWinProc@20() + 0x23 bytes user32.dll!_UserCallWinProcCheckWow@32() + 0xb3 bytes user32.dll!_DispatchMessageWorker@8() + 0xe6 bytes user32.dll!_DispatchMessageW@4() + 0xf bytes Tutorial02.exe!WinMain(HINSTANCE__ * hInstance=0x009f0000, HINSTANCE__ * __formal=0x00000000, HINSTANCE__ * __formal=0x00000000, HINSTANCE__ * __formal=0x00000000) Line 22 + 0xf bytes C++ Tutorial02.exe!__tmainCRTStartup() Line 578 + 0x35 bytes C Tutorial02.exe!WinMainCRTStartup() Line 403 C kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
Size/move loop and delay in DefWindowProc
#1 Moderators - Reputation: 1918
Posted 14 January 2009 - 07:59 AM
Steve Macpherson
Senior programmer, Firebrand Games
#2 Moderators - Reputation: 6623
Posted 14 January 2009 - 08:28 AM
#3 Moderators - Reputation: 1918
Posted 14 January 2009 - 08:33 AM
Quote:Currently the render is very basic (A single triangle), and the timer is set to 0ms, so just "as fast as possible".
Original post by SiCrane
How complex are your renders and what kind of delay are you putting on your timer? If you have a relatively simple render and a relatively low update frequency, then you might want to just start the timer up when the window is created and let it run.
However, this is for a tutorial / article on D3D rendering, and I'd like to do things as "correctly" as possible, even if it means leaving the 500ms lag.
Also, this is D3D (In case that's not obvious from the call stack function names [smile]), so running rendering in another thread is out of the question.
EDIT: And I'm curious about what exactly is going on under the hood here.
[Edited by - Evil Steve on January 14, 2009 3:33:36 PM]
#4 Members - Reputation: 102
Posted 14 January 2009 - 01:16 PM
#5 Members - Reputation: 169
Posted 14 January 2009 - 04:11 PM
EDIT: You may find Spy++ will give you useful information about what messages are occuring. To me it is worlds easier than a call stack for windows message monitoring.
#6 Members - Reputation: 1148
Posted 14 January 2009 - 04:43 PM
If that's the case, then there's probably not a lot you can do about it (but maybe make a note in your tutorial or something [smile]).
#7 Moderators - Reputation: 1918
Posted 14 January 2009 - 10:06 PM
Quote:For the stall, DefWindowProc doesn't return for over 500ms. It's as if it's an extremely expensive function call. Putting a timer in the main loop wouldn't help, and for now GetTickCount() is accurate enough (You don't need to render at full speed when the user is moving the window).
Original post by kittycat768
What kind of stall are you referring to? To my knowledge the window will NEVER update while it's being dragged. Your program will keep executing though. Have you considered throwing your timer code into the main loop instead of relying on your window procedure? I recommend QueryPerformanceCounter() if you do. 64-bit calculations... Nummy. Also, what is your definition of "correctly?"
My definition of "correctly" is to render in the main loop, not from a timer handler - the timer handler isn't called all that frequently as far as I'm aware.
Quote:Ah, I didn't notice that the wParam can include HTCAPTION, thanks. It's the WM_SYSCOMMAND handling in DefWindowProc that causes the 500ms stall - that's what I'm trying to fix or work around.
Original post by lordikon
There are some other things that cause about a 500ms stall, such as grabbing a window title bar. In fact, now that I think about it, grabbing a window title bar causes WM_SYSCOMMAND with a wparam value of 0xf012 which is in fact (SC_MOVE + HTCAPTION).
EDIT: You may find Spy++ will give you useful information about what messages are occuring. To me it is worlds easier than a call stack for windows message monitoring.
Quote:I don't think that's it, I always have my double click delay set to as fast as possible, and that should be less than 500ms. I'll give that a try when I get a chance though.
Original post by Codeka
This is a guess, but I'm thinking DefWindowProc is waiting to see whether you're about to double-click or not. Try setting your double-click delay really slow or really fast to see if that affects things.
If that's the case, then there's probably not a lot you can do about it (but maybe make a note in your tutorial or something [smile]).
Cheers,
Steve
#8 Moderators - Reputation: 6623
Posted 15 January 2009 - 01:21 AM
Quote:
Original post by Evil Steve
My definition of "correctly" is to render in the main loop, not from a timer handler - the timer handler isn't called all that frequently as far as I'm aware.
You could try starting a timer at window creation and calling InvalidateRect() in the timer handler, which will cause WM_PAINT messages to be generated even when your window is being dragged.
#10 Moderators - Reputation: 1918
Posted 15 January 2009 - 01:50 AM
Quote:Setting my double click speed to extremely slow still takes the same time for DefWindowProc to return, so that doesn't seem to be related.
Original post by Codeka
This is a guess, but I'm thinking DefWindowProc is waiting to see whether you're about to double-click or not. Try setting your double-click delay really slow or really fast to see if that affects things.
Quote:Hmm, it's possible - but still seems a bit ugly to me. This is beginning to look like the only option though...
Original post by SiCrane
You could try starting a timer at window creation and calling InvalidateRect() in the timer handler, which will cause WM_PAINT messages to be generated even when your window is being dragged.
Quote:Disabling D3D completely (Commenting out any reference to any D3D interface) still yields the same problem.
Original post by Endurion
Could this be because you've got a Direct3d device open inside the window?
#11 Members - Reputation: 1984
Posted 15 January 2009 - 02:08 AM
It doesn't happen if you start dragging the window right away, moving the mouse already when you click. It also pauses if you hold down the button on the minimize button for example. I think all such things are handled in some loop that doesn't return, except for that once the window starts moving it returns to allow for interactive moving.
Don't know why it waits 500 ms before returning unless the mouse moves.. the reply about double-clicking sounds plausible to me..
It also freezes if you hold down the right mouse-button in the title bar.
#12 Members - Reputation: 169
Posted 15 January 2009 - 02:20 AM
Quote:
Original post by Evil Steve
Hmm, it's possible - but still seems a bit ugly to me. This is beginning to look like the only option though...
I create the timer the first time WM_MOVING is reached, and remove the timer when WM_EXITSIZEMOVE is reached. This doesn't help with the delay though. There is about a 500ms delay between the time the user clicks the title bar and I receive SC_MOVE + HTCAPTION. During this time the window stops updating.
#13 Moderators - Reputation: 1918
Posted 15 January 2009 - 03:05 AM
Quote:Yep, it's that 500ms delay that I'm trying to avoid.
Original post by lordikon
I create the timer the first time WM_MOVING is reached, and remove the timer when WM_EXITSIZEMOVE is reached. This doesn't help with the delay though. There is about a 500ms delay between the time the user clicks the title bar and I receive SC_MOVE + HTCAPTION. During this time the window stops updating.
#16 Moderators - Reputation: 1918
Posted 15 January 2009 - 03:42 AM
Quote:Yeah, I found that post while Googling, but decided not to necro the thread [smile]
Original post by lordikon
So, it appears you've been having this problem for awhile. :D
http://www.gamedev.net/community/forums/topic.asp?topic_id=440341
#17 Members - Reputation: 703
Posted 15 January 2009 - 03:47 AM
case WM_NCLBUTTONDOWN:
if( SendMessage( hWnd, WM_NCHITTEST, wParam, lParam ) == HTCAPTION )
{
SetTimer( hWnd, 1000, 0, NULL );
SendMessage( hWnd, WM_SYSCOMMAND, SC_MOVE, 0 );
return 0;
}
break;
case WM_TIMER:
Render();
break;
case WM_EXITSIZEMOVE:
KillTimer( hWnd, 1000 );
break;
But personally I would recommend against messing with this because, well, you're just nitpicking one of Windows' insignificant quirks. That's not patriotic!
[Edited by - hikikomori-san on January 15, 2009 10:47:56 AM]
#18 Members - Reputation: 169
Posted 15 January 2009 - 04:31 AM
They mention the same delay problem.
#19 Moderators - Reputation: 1918
Posted 15 January 2009 - 05:09 AM
Quote:Yes, I've been through Google. I've found plenty of reports of the problems, but no solutions.
Original post by lordikon
Just found this: http://developer.popcap.com/forums/showthread.php?p=19636
They mention the same delay problem.
Quote:Hmm, I'll give that a go later tonight, thanks.
Original post by hikikomori-san
Here is a quick workaround. Note that this has the little quirk of setting the cursor position to the middle of the window's caption. Also, if the app has other windows and he starts dragging them, the problem remains. Also, the delay will remain if the window is sizable and the user [EDIT: referred to in the previous sentence as "he"] clicks on the borders to resize it. Also, this will effectively disable double-clicking the title bar to maximize the window. Plus possibly a few more things I haven't thought about yet.
#20 Moderators - Reputation: 1918
Posted 15 January 2009 - 08:04 AM
Quote:This seems to work pretty well, with a bit of an ajustment:
Original post by hikikomori-san
Here is a quick workaround. Note that this has the little quirk of setting the cursor position to the middle of the window's caption. Also, if the app has other windows and he starts dragging them, the problem remains. Also, the delay will remain if the window is sizable and the user [EDIT: referred to in the previous sentence as "he"] clicks on the borders to resize it. Also, this will effectively disable double-clicking the title bar to maximize the window. Plus possibly a few more things I haven't thought about yet.
LRESULT D3DWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static bool sbMoving = false;
static POINT sptOffset;
switch(uMsg)
{
case WM_NCLBUTTONDOWN:
if(SendMessage(m_hWnd, WM_NCHITTEST, wParam, lParam) == HTCAPTION)
{
POINT ptCursor;
RECT rcWnd;
GetWindowRect(m_hWnd, &rcWnd);
GetCursorPos(&ptCursor);
sptOffset.x = ptCursor.x - rcWnd.left;
sptOffset.y = ptCursor.y - rcWnd.top;
SetCapture(m_hWnd);
sbMoving = true;
return 0;
}
break;
case WM_NCLBUTTONUP:
case WM_LBUTTONUP:
sbMoving = false;
ReleaseCapture();
break;
case WM_MOUSEMOVE:
case WM_NCMOUSEMOVE:
if(sbMoving)
{
POINT ptCursor;
RECT rcWnd;
GetWindowRect(m_hWnd, &rcWnd);
GetCursorPos(&ptCursor);
SetWindowPos(m_hWnd, NULL, rcWnd.left+(ptCursor.x-(rcWnd.left+sptOffset.x)),
rcWnd.top+(ptCursor.y-(rcWnd.top+sptOffset.y)), 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
break;
}
return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}
I dread to think what horrible bugs this will cause though, so I think I'm just going to use the method with the 500ms delay for this, and add the above method as an alternative.
Another issue is that the user can still access the system menu of the window (Which will cause a stall), and select "Move" from there - which will stall. The second issue can be fixed with the timer as before, but probably not the stall when selecting the system menu.
Thanks for all the replies,
Steve






