-
July 30th, 2014, 05:31 PM
#1
How to get rid of 'not responding' message
I have a simple dialog based app that performs some time consuming file manipulations. The activating method contains the customary
The hour glass initially appears, than after a few seconds, the dialog title bar indicates 'not responding'.
This is misleading to users as it suggests the application has ceased to function when, in fact, it's working just fine. I would like very much
to eliminate this 'not responding' message but havn't a clue how to do it. Have any of you dealt with this problem, if so, how?
Thanks.
mpliam
-
July 30th, 2014, 05:43 PM
#2
Re: How to get rid of 'not responding' message
-
July 30th, 2014, 06:13 PM
#3
Re: How to get rid of 'not responding' message
If you are doing the processor intensive file manipulation in the main UI thread, you are blocking the app.
As mentioned, you either need to do the labor intensive operations in a worker thread, or if doing the operations in the main thread, pump messages while processing.
Btw, the 'Not responding' message appears when an app hasn't processed any messages within the last 2 seconds. While you might think your app is 'working properly' most users would think your app is hung.
Generally you shouldn't block the UI because the user can't do anything with the app - they can't cancel the operation, minimize or move the window - not a good user experience.
Last edited by Arjay; July 30th, 2014 at 06:17 PM.
-
July 31st, 2014, 12:47 AM
#4
Re: How to get rid of 'not responding' message
Victor Nijegorodov
-
July 31st, 2014, 07:35 AM
#5
Re: How to get rid of 'not responding' message
Originally Posted by Mike Pliam
I have a simple dialog based app that performs some time consuming file manipulations.
As it was said many times here, any time consuming manipulation does not belong with main GUI thread.
The activating method contains the customary
Not sure what activating method really is. In case it's the method where DoModal() is called, I don't think this is going to give you what you expect. The hourglass is to keep showing until dialog closes, in case my guess is correct.
The hour glass initially appears, than after a few seconds, the dialog title bar indicates 'not responding'.
This is misleading to users as it suggests the application has ceased to function when, in fact, it's working just fine.
Working just fine should include dialog responsiveness as well. Besides, hourglass looks more misleading than, say, a progressbar in statusbar or something similar. Hourglass is kinda fossil from Jurassic period.
I would like very much to eliminate this 'not responding' message but havn't a clue how to do it.
Originally Posted by GCDEF
Threads
Message pump
Best regards,
Igor
-
August 1st, 2014, 11:22 PM
#6
Re: How to get rid of 'not responding' message
OK. I get it. Thank you all for your suggestions. One of the best examples I've found is that of our beloved Arjay.
VC++ MFC Thread Tutorial: _beginthreadex, WaitForSingleObject, pausing,
resuming, and stopping threads. Arjay
http://www.********.net/Visual_C_MFC...FC-Example.htm
(For some reason, Codeguru won't let me post the full url - but you can probably google it as that's how I found it.)
Using this code as a starting point, I tried to insert a test class (CCryptTest) action (EncryptFile(LPCTSTR)) into the ThreadProc of Arjay's CProgressMgr class:
Code:
//+------------------------------------------------------
// Secondary thread procedure
//+------------------------------------------------------
static UINT WINAPI ThreadProc( LPVOID lpContext )
{
// Turn the passed in 'this' pointer back into a CProgressMgr instance
CProgressMgr* pProgressMgr = reinterpret_cast< CProgressMgr* >( lpContext );
/*
for( UINT uCount = 0; uCount < 100; uCount++ )
{
if( WAIT_OBJECT_0 == WaitForSingleObject( pProgressMgr->GetShutdownEvent( ), 0 ) )
{
return 1;
}
// Send the progress message to the UI
pProgressMgr->NotifyUI( NOTIFY_INC_PROGRESS );
// Sample code - delay the operation a bit
Sleep( 50 );
//_RPT1(0, "What the **** #%d\n", uCount);
//CCryptTest.EncryptFile(L"MyTestFile.txt");
CCryptTest::EncryptFile(L"MyTestFile.txt");
}
*/
CCryptTest::EncryptFile(L"MyTestFile.txt");
// Send the thread completed message to the UI
pProgressMgr->NotifyUI( NOTIFY_THREAD_COMPLETED );
return 0;
}
Notice that I have put my action method outside of the thread loop. It works to encrypt the file but, of course, provides no progress notification. Were I to insert it within the loop as I initially attempted to do, it still works quit well, about 100 times, as it provides the expected progress bar notifications.
So my question at this point is two-fold:
1 - How do I implement a progress report from the encryption algorithm (one which I have written that resides in a dll) in order to feed back to the progress bar control ?
2 - How does one estimate what sort of progress percentage of the total task is actually being acomplished (otherwise such progress reporting is rather fictional)?
If it's a different Arjay, please accept my apologies. If it is our Arjay, thank you for making the very nice code example available.
Last edited by Mike Pliam; August 1st, 2014 at 11:26 PM.
mpliam
-
August 2nd, 2014, 12:54 PM
#7
Re: How to get rid of 'not responding' message
About the percentage. It may be a number of files processed to total number, or number of bytes to total size, whatever. In case the whole work is done inside encrypting method, that one should be responsible for calling some callback or posting progress message.
Best regards,
Igor
-
August 2nd, 2014, 03:19 PM
#8
Re: How to get rid of 'not responding' message
Thanks Igor. Here's a little demo app that calculates the total number of file bytes in each file to be processed, then processes (simply loads a file for demo), calculating the cumulative number of file bytes loaded as a percentage of the total expected. This takes place in the ManipulateFiles method which uses a couple of helper functions to get the bytes from each file. In this demo, the percent 'progress' is printed out.
What i do not know is how to make or associate this ManipulateFiles with a callback function that would work from within a dll. I've looked at a number of online dll callback demos, the most helpful being:
Callback Functions Tutorial Posted by Marius Bancila on September 16th, 2005
http://www.codeguru.com/cpp/cpp/cpp_...s-Tutorial.htm
but cannot figure out how to do it.
Any help greatly appreciated. Thanks. : )
mpliam
-
August 4th, 2014, 06:45 AM
#9
Re: How to get rid of 'not responding' message
note that changing the UI elements should only be done FROM the UI thread, never from the worker threads.
So the proper way to update your UI is to post a message to the UI thread or window to inform it of a percentage change.
-
August 5th, 2014, 01:33 AM
#10
Re: How to get rid of 'not responding' message
the proper way to update your UI is to post a message to the UI thread or window to inform it of a percentage change
Yes. That would be nice. But cannot figure out how to get that to work.
Say I have a dll method like that in the ProgFeedBack program posted in this thread, and I code as follows:
Code:
// global definition in dll class
UINT __declspec(selectany) WM_PROGRESS = 9;
#define WM_PROGSTR _T("Progress")
WM_PROGRESS = RegisterWindowMessage(WM_PROGSTR); // (in ctor of that class)
void CMyDllClass::ManipulateFiles(...)
{
for(size_t i = 0; i < vFilesIn.size(); i++)
{
CurrentFileBytes = LoadFile((char*)sfile.c_str());
CumulativeBytesLoaded += (float)CurrentFileBytes;
PercentTotalBytes = (float) CumulativeBytesLoaded / (float)TotalFileBytes;
::PostMessageW(NULL, WM_PROGRESS, (WPARAM) PercentTotalBytes, 0);
}
}
Now this might work - but I do not know how to create a GetMessage loop in the User Interface thread that will capture the series of posted messages. Or is this completely erroneous in approach and should I try to fashion some callback function?
mpliam
-
August 5th, 2014, 01:50 AM
#11
Re: How to get rid of 'not responding' message
Originally Posted by Mike Pliam
Now this might work - but I do not know how to create a GetMessage loop in the User Interface thread that will capture the series of posted messages. Or is this completely erroneous in approach and should I try to fashion some callback function?
In MFC you usually don't call GetMessage directly. The Framework does it for you.
But you must implement a message handler (in the GUI thread window) for the user defined message being posted by threads.
See the essay I referred to in the post#4
Victor Nijegorodov
-
August 5th, 2014, 04:29 AM
#12
Re: How to get rid of 'not responding' message
Originally Posted by Mike Pliam
What i do not know is how to make or associate this ManipulateFiles with a callback function that would work from within a dll.
GUI <- Callback <- DLL sample attached
ProgFeedBack_callback.zip
Best regards,
Igor
-
August 5th, 2014, 07:11 AM
#13
Re: How to get rid of 'not responding' message
If the dll manages the thread, then what Igor said:
GUI <- Callback <- DLL sample attached
If not,
GUI <- Thread <- Callback <- DLL
P.S. Thank you for the kudos for my threading sample. I've been very busy lately; otherwise I would have responded sooner.
-
August 5th, 2014, 12:17 PM
#14
Re: How to get rid of 'not responding' message
I'm still trying to digest Igor's code. While it's easy to copy and paste, understanding it is quite another matter for me. I've got it working in my own mileau, having separated the dll project and the GUI project more succinctly, but in either case I notice that if one selects Cancel before the progress has fully updated, a large memory leak occurs. Any good way to prevent this leak from happening?
Additionally, Arjay's remarks leave me a bit puzzled. They suggest that Igor's callback method does not involve a worker thread when, in fact, the 'not responding' message is gone and one can move and/or Cancel the progress operation, suggesting that it must be operating in a separate thread. I'm afraid I'm confused as usual.
Last edited by Mike Pliam; August 5th, 2014 at 12:22 PM.
mpliam
-
August 5th, 2014, 02:27 PM
#15
Re: How to get rid of 'not responding' message
Mike, the sample was made to be a simplistic representation of C-style callback use in GUI. Your additional DLL aspect adds almost nothing to it, but as long as you asked for it, the demo includes one as well.
Now let's see what we have. A GUI app which main thread is not to be blocked. The instrument for unblocking is Worker thread. The thread being created calls DLL code, Run function in particular.
What GUI app knows about DLL? It's only Run function accepting a function pointer of certain prototype, i.e. the callback.
What DLL knows about host app? Nothing but a callback function to be called.
What callback function knows about DLL? Effectively, almost nothing, as it's only a set of parameters the DLL passes to it. But it knows all the details about app code, the details enough to update the GUI controls, i.e. progress bar in our case, in accordance with the passed information.
So, interoperation is provided by establishing a well-defined data exchange interface in a form of DLL export function and callback prototype the former accepts. DLL just does its work and calls the callback with the values it produces on the run. App just initiates the DLL call and waits for its return. Nevertheless, while it waits the callback function is called by DLL. It appears to be driven by the DLL function.
It's worth to mention, that GUI app can be replaced with a console app alright, and this won't change things for DLL at all. Say, the callback making use of printf will do perfect for it.
Last edited by Igor Vartanov; August 5th, 2014 at 02:29 PM.
Best regards,
Igor
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|