I'm new to native c++. Right now, I made it so when I press the left mouse button, it has a for loop that does InvalidateRect and draws a rectangle, and increments X by the box size each time it iterates. But, C++ is so much faster and efficient at drawing than C# that, it draws all this instantly. What I would like is for it to invalidate the rectangle, show the rectangle, wait 50ms, then continue the loop. I tried Sleep(50) but it still waits until painting is done before showing the result. I also tried PeekMessage but it did not change anything.
Any help would be appreciated. Thanks
DoEvents basically translates as:
void DoEvents()
{
MSG msg;
BOOL result;
while ( ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE ) )
{
result = ::GetMessage(&msg, NULL, 0, 0);
if (result == 0) // WM_QUIT
{
::PostQuitMessage(msg.wParam);
break;
}
else if (result == -1)
{
// Handle errors/exit application, etc.
}
else
{
::TranslateMessage(&msg);
:: DispatchMessage(&msg);
}
}
}
I am a bit rusty in Win32 API, but the asynchronous way of doing this would be:
Invalidate the rect
Set a timer (see below) to send a message after 50ms
Return to the event loop to let WM_PAINT events happen
On receiving the timer message, move the rect, then repeat
This way integrates nicely with being event driven. I realize this is not exactly what you ask for, but I thought I'd mention it as a possible solution anyway :)
EDIT: A quick google turns up the Windows API call [SetTimer](http://msdn.microsoft.com/en-us/library/ms644906(VS.85,loband).aspx) which you can use to facilitate this. The message will be a WM_TIMER one.
Related
I am attempting to disable a window under certain conditions using EnableWindow(hWnd, false);
According to the documentation, this should "disable mouse and keyboard input to the specified window".
The problem I am seeing is that it does, in fact, disable like it says, except if the cursor is currently inside of a text box in the window and the window has the focus that does not get disabled. I was thinking of doing some sort of code to take the focus off of the window as well.
Is there a better way to go about this?
Note: The window being disabled is a binary ran via _spawnl().
I'm not sure if this is a Windows feature or a bug. Either way, disabling the foreground window is not a good idea.
If you are able to modify the program you start with _spawnl() then that is a better solution. You could make it respond to WM_APP or something like that when you need to control it.
If it is a 3rd-party application then you are left with hacks.
You could try to change the foreground window with SetForegroundWindow but this will only work if you do it very soon after _spawnl() before your thread loses the foreground lock. Using LockSetForegroundWindow before _spawnl() might be able to help you keep the lock longer. There are also various other hacks to change the foreground with AttachThreadInput etc.
If you don't want to change the foreground I was able to come up with a workaround:
ShellExecute(NULL, NULL, TEXT("Notepad"), NULL, NULL, SW_SHOW);
Sleep(2000);
HWND hNP = FindWindow(TEXT("Notepad"), NULL);
Sleep(2000); // Start typing in Notepad now...
if (hNP)
{
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, >i))
{
HWND hChild = NULL;
if (gti.hwndFocus != hNP && gti.hwndFocus)
{
EnableWindow(hChild = gti.hwndFocus, false);
}
if (GetForegroundWindow() == hNP)
{
SendNotifyMessage(hNP, WM_ACTIVATE, WA_INACTIVE, NULL);
SendNotifyMessage(hNP, WM_ACTIVATE, WA_ACTIVE, NULL);
SendNotifyMessage(hNP, WM_SETFOCUS, NULL, NULL);
// SendNotifyMessage(hNP, WM_NCACTIVATE, false, NULL); // Uncomment to make it look like it is inactive
}
EnableWindow(hNP, false);
if (hChild)
{
EnableWindow(hChild, true);
}
}
MessageBox(NULL, TEXT("Done?"), NULL, MB_TOPMOST);
SetForegroundWindow(hNP);
PostMessage(hNP, WM_CLOSE, 0, 0);
}
This is certainly not optimal, it leaves Notepad in a state where it looks like it is enabled but it is really not. The idea is to disable the focused child window and trigger a fake activation change and forcing the focus to change. It might not work with other applications, who knows.
If you are willing to risk a deadlock you can do this instead:
DWORD tid = GetWindowThreadProcessId(hNP, NULL);
GUITHREADINFO gti;
gti.cbSize = sizeof(gti);
if (tid && GetGUIThreadInfo(tid, >i))
{
if (GetForegroundWindow() == hNP)
{
if (AttachThreadInput(GetCurrentThreadId(), tid, true))
{
SetFocus(NULL);
AttachThreadInput(GetCurrentThreadId(), tid, false);
}
}
EnableWindow(hNP, false);
}
I'm trying to learn WTL / Win32 programming, and I don't quite understand the design of the CIdleHandler mixin class.
For WTL 9.1, The CMessageLoop code is as follows (from atlapp.h):
for(;;)
{
while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!OnIdle(nIdleCount++))
bDoIdle = FALSE;
}
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
{
ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n"));
continue; // error, don't process
}
else if(!bRet)
{
ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n"));
break; // WM_QUIT, exit message loop
}
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
if(IsIdleMessage(&m_msg))
{
bDoIdle = TRUE;
nIdleCount = 0;
}
}
The actual call to idle handlers is very straightforward.
// override to change idle processing
virtual BOOL OnIdle(int /*nIdleCount*/)
{
for(int i = 0; i < m_aIdleHandler.GetSize(); i++)
{
CIdleHandler* pIdleHandler = m_aIdleHandler[i];
if(pIdleHandler != NULL)
pIdleHandler->OnIdle();
}
return FALSE; // don't continue
}
As is the call to IsIdleMessage
static BOOL IsIdleMessage(MSG* pMsg)
{
// These messages should NOT cause idle processing
switch(pMsg->message)
{
case WM_MOUSEMOVE:
#ifndef _WIN32_WCE
case WM_NCMOUSEMOVE:
#endif // !_WIN32_WCE
case WM_PAINT:
case 0x0118: // WM_SYSTIMER (caret blink)
return FALSE;
}
return TRUE;
}
My analysis is as follows: it seems like once per "PeekMessage Drought" (a period of time where no messages are sent to the Win32 Application), the OnIdle handlers are called.
But why just once? Wouldn't you want background idle tasks to continuously be called over and over again in the case when PeekMessage ? Furthermore, it seems strange to me that WM_LBUTTONDOWN (User has left-clicked something on the Window) would activate idle processing (bDoIdle = True), but WM_MOUSEMOVE is explicitly called out to prevent reactivation of idle processing.
Can anyone give me the "proper" use scenario of WTL Idle Loops (or more specifically: CIdleHandler)? I guess my expectation was that Idle-processing functions would be small, incremental tasks that take no more than say... 100ms to complete. And then they'd be called repeatedly in the background.
But it seems like this is not the case in WTL. Or maybe I'm not fully understanding Idle loops? Because if I had an incremental background task registered as a CIdleHandler... then if the user stepped away from the window, the task would get run only once! Without any messages pumped into the system (such as WM_LBUTTONDOWN), the bDoIdle variable would remain false for all time!
Does anyone have a good explanation for all this?
As said in the comments, OnIdle handler is supposed to be called when idling starts after certain activity, esp. in order to update UI. This explains "once" calling of the handlers: something happened and then you have a chance to once update the UI elements. If you need ongoing background processing, you are supposed to use timers or worker threads.
WTL samples suggest the use of idle handlers, e.g. in \Samples\Alpha\mainfrm.h.
Window class picks up message loop of the thread and requests idleness updates:
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// ...
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
Later on after message processing and user interaction, the idleness handler updates toolbar to reflect possible state changes:
virtual BOOL OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
I am using C++ with MFC, and I have a ListBox tied to a variable that I'm updating as I run through a function:
void CFileSelection::OnBnClickedFiletousb()
{
m_LogC.AddString(_T("Starting move to USB, Please Wait..."));
UpdateData(FALSE);
// Code to move files from disk to USB
m_LogC.AddString(_T("Move to USB Successful."));
}
However, despite the UpdateData, the ListBox doesn't populate with either string until it has completed it's task. Is there a way to make it update the screen before the rest of the code is executed?
Use this function after changing the text on the listbox. Your issue is that the other calls are blocking the MessageThread, but you can force an update with this.
void ProcessWindowMessages()
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) // let them see the message before we go into longer term wait
{
TranslateMessage(&msg); // translate it
DispatchMessage(&msg); // and let windows dispatch it to WinProc
}
}
Alternatively you can also call
yourlistboxVariable->UpdateWindow();
I am doing a measurement system and I have got a do while loop in my program. In the loop, it is checking if any motor is moving before it could take measurement as it require it to reach the target position before doing anything.
While doing the measurement, it is suppose to tell me how long does it took to do this measurement.
However, whenever it runs in the do while loop, all my timer function stop as if they are put to Sleep mode.
Is there any other method where I could implement this? If there is, please help me.
Any help would be much appreciated.
SetTimer(TIMERECHO, 1000, NULL);
BOOL bMoving = FALSE;
do
{
if (IsMoving(ID, NULL, &bMoving))
GetPosition();
} while (bMoving);
void CLHMDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case TIMERECHO:
UpdateData(FALSE);
m_Seconds++;
m_TimerEcho.Format(_T("Total time: %ds"), m_Seconds);
break;
}
CDialogEx::OnTimer(nIDEvent);
}
MFC has a message loop that gets and dispatches messages such as WM_TIMER. If you do a while loop that message loop is not running. It's not sleeping, it's just waiting until you stop hogging the processor.
You have two options: (1) Get rid of the lengthy loop and do whatever it does periodically on a WM_TIMER message. (2) Use a second thread to do the lengthy operation. This has numerous difficulties for a beginner.
It's because your loop isn't processing messages. onTimer is called as a result of a windows message. You need to keep processing messages in the loop or use a callback based timer.
One method is using CreateTimerQueueTimer
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682485%28v=vs.85%29.aspx
A very simple solution (but not perfect) to get you running is to move your IsMoving to the timer as below:
void CLHMDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case TIMERECHO:
if (IsMoving(ID, NULL, &bMoving))
GetPosition();
UpdateData(FALSE);
m_Seconds++;
m_TimerEcho.Format(_T("Total time: %ds"), m_Seconds);
break;
}
CDialogEx::OnTimer(nIDEvent);
}
However for a proper solution you have to use threads for this, the complexity of that will vary for simple to better solutions there as well. I have written some code on the fly for you, it may not compile but you get the idea.
AfxBeginThread(monitor_motor, this);
UINT monitor_motor(LPVOId lParam)
{
CMyDlg * dlg = (CMyDlg *) lParam;
HWND hWnd = (HWND) dlg->m_hWnd;
do
{
if (IsMoving(ID, NULL, &dlg->bMoving))
GetPosition();
Sleep(100); // maybe you don't have to poll too hard and give other hardware chance to communicate?..that's upto you
PostMessage( hWnd, UPDATE_TIMER_AND_STUFF );
} while (dlg->bMoving);
PostMessage( hWnd, UPDATE_MOTOR_MOVED_COMPLETELY );
}
This is my current game loop in a normal Window:
while(running)
{
while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
running = false;
}
TranslateMessage( &msg );
DrawGame(&game);
DispatchMessage( &msg );
}
UpdateGame(&game);
InvalidateRect(hwnd, NULL, 1);
//Sleep(100);
}
... but should I actually place DrawGame between Translate and DispatchMessage? If I put DrawGame above/below UpdateGame nothing is ever drawn.
And after a while if I draw a simple rectangle they start overlapping eachother. It runs good for about a minute, draw a grid of rectangles (out of position due to: window size that you set isn't the correct size of the window. And after a while it draw another grid and sometimes it screws up totally and the window appears to have crashed and I must press "stop" button in Visual Studio.
So, where exactly do I place a Game loop and how do I know when to Draw the game? I need to draw rectangles primarly, although that isn't working so good either.
You should call DrawGame() from you Windows message callback when handling a WM_PAINT message.
In the message loop you are supposed to only fetch and dispatch Windows messages to the appropriate callback.
Additionally this is also the place to update the game world, but not for doing draw calls.