Hello, respected professionals from CodeProject.
I have a following problem:
I need to create a modeless dialog box, which starts a thread when one of its buttons is pressed.
That button will be hidden, until thread finishes. Then it will be shown.
Thread does lengthy job ( populates Excel ),
so when I close my main app, although my dialog box and thread closes, Excel "zombie" process is left.
I have used MSDN example from here:
http://support.microsoft.com/kb/216686[
^] , and CodeProject article from here
MS Office OLE Automation Using C++[
^] , to learn OLE Automation.
I have found very similar question which helped me to start with threads here
Abort thread properly when dialog box close button is clicked[
^] , and I have also used an example about threads from Petzold's book Programming Windows 5th edition.
So far, it seems that everything works great, except for the underlined part.
I have tried sending the WM_CLOSE message to the dialog box to trigger thread abortion handler, but it doesn't work.
If I add a message box to the main window's WM_CLOSE handler, after sending the WM_CLOSE to the dialog box, all threads abort gracefully, I know that because I can see Excel closing in TaskManager, since I wait for them and only then click the message boxes OK button.
My question is:
Instead of a message box, how can I delay the closing of the main window, so my worker threads can abort gracefully ?
Thank you.
If code snippets are required, I will provide them. I have omitted them to keep this post short.
EDIT#1:
I have managed to implement proper thread function.
Code from the article above that fills Excel is inserted into thread function.
After each block of instructions a boolean variable is polled to see if thread function should be aborted.
In the thread function, data structure holding that boolean variable, is declared volatile, so compiler can not optimize the code, which would result in replacing while loop with if statement.
This solution is inspired by the example from
Charles Petzold's legendary book,
"Programming Windows" 5th edition.
Perhaps I could use event object, as it fits here better, but at this point I will satisfy myself with this solution, since I'm in a time trouble.
Thread handle is declared static, and is initialized to NULL in WM_INITDIALOG.
I have defined 2 custom messages, so thread function can inform dialog box if error occurred or a clean exit was performed.
These are defined as bellow:
#define WM_THREAD_OK ( WM_APP +1 )
#define WM_THREAD_ERROR ( WM_APP + 2 )
In my dialog box, either of these messages shows previously hidden Save button ( remember, to avoid multiple threads being fired off, I have hidden the button when user presses it and launches a thread ).
WM_CLOSE and IDCANCEL handlers are identical, and are implemented like this:
case WM_CLOSE:
if( threadHandle ) {
obj.bContinue = false;
WaitForSingleObject( threadHandle, INFINITE );
CloseHandle( threadHandle );
threadHandle = NULL;
}
DestroyWindow(hwnd);
return TRUE;
break;
All I need to do now, is to rework my button handler.
I need to set thread handle to NULL, before I launch a new thread.
My question is:
Should I set the handle to NULL in response to WM_THREAD_OK message like this:
case WM_THREAD_OK:
if( threadHandle ) {
WaitForSingleObject( threadHandle, INFINITE );
CloseHandle( threadHandle );
threadHandle = NULL;
}
ShowWindow( GetDlgItem( hwnd, IDC_BUTTON1 ), SW_SHOW );
return TRUE;
or should I do it in my button handler like this:
case IDC_BUTTON1:
{
ShowWindow( GetDlgItem( hwnd, IDC_SAVE ), SW_HIDE );
td.hwnd = hwnd;
td.PrimaryKey = primaryKey;
DWORD threadID;
if( threadHandle ) {
WaitForSingleObject( threadHandle, INFINITE );
CloseHandle( threadHandle );
threadHandle = NULL;
}
threadHandle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)MyThread,
(void*)&td, 0, &threadID );
if( !threadHandle )
{
MessageBox( hwnd, L"Error", L"Error", MB_ICONERROR );
DestroyWindow(hwnd);
}
}
break;
That is the only thing left, since I believe everything is in fine order now.
I would welcome a constructive advice/comment.
Thank you.