Click here to Skip to main content
15,890,123 members
Please Sign up or sign in to vote.
2.20/5 (3 votes)
See more:
I have a dialog box with a Save button.

When that button is clicked, I should populate excel with data from database.

To do that, I have modified code from here: http://support.microsoft.com/kb/216686[^], which suites my purposes .

The problem is that this operation is lengthy and doesn’t allow user to use GUI until it is finished.

That is why I have decided to put Excel automation in a thread function, and to launch thread when Save button is clicked.

Earlier, I have posted here on CP, questions about multithreading, but have decided to stay away from it, since I am inexperienced.

I have decided to hide the Save button while thread is running, to prevent other threads being spawned with multiple clicks on a Save button.

This will ensure that there will be only one thread running, and will avoid thread synchronization.

I have created thread function which does the Excel automation as above, and it works.

The problem is that zombie process can appear ( Excel doesn’t close ) if the user interrupts thread execution by closing the dialog box, or closing the program.

That is my problem:

How to close dialog box/main window and to abort thread properly, so the zombie process does not appear ?

I work on Windows XP using MS Visual C++ and pure Win32 API ( no MFC ).

NOTE:

Here is what I have so far:

My thread function:
C++
struct ThreadData
{
	HWND hDlg; // handle of a dialog box
	int PrimaryKey; // so I can query database
};

DWORD WINAPI MyThread( LPVOID lp )
{
	ThreadData* td = (ThreadData*)lp;

	wchar_t query[100];

	swprintf_s( query, 100, 
		L"select * from MyTable where Primary_Key = %d ;",
		td->PrimaryKey);

	HRESULT hr;

	try
	{
		CoInitialize(NULL);

		hr = // open database and perform query;

		// populate Excel as described in article

		// perform cleanup

		return 0;
	}
	catch( _comm_error & ) // no need to display textual messages , just cleanup
	{
		// do cleanup

		return 1;
	}
}


Dialog box snippet:
C++
INT_PTR CALLBACK DialogBoxProcedure(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	static ThreadData td;

	HANDLE threadHandle = NULL;

	static int primaryKey; // we get this value from combo box

	 switch(Message)
	 {
	 case WM_COMMAND:
		{
		    switch(LOWORD(wParam))
		    {
		     case IDCANCEL:
				
                        if( threadHandle )
		        {
			    WaitForSingleObject( threadHandle, INFINITE );

			    CloseHandle( threadHandle );
		        }

			DestroyWindow(hwnd);

			break;

		    case IDC_BUTTON1:
			{
				ShowWindow( GetDlgItem( hwnd, IDC_SAVE ), 
                                           SW_HIDE ); 

				td.hwnd = hwnd;
				td.PrimaryKey = primaryKey;

				// create thread

				DWORD threadID;

				threadHandle = CreateThread( NULL,
                                                   0,
                                                   MyThread,
                                                   (void*)&td,
                                                   0,
                                                   &threadID );
								
				if( !threadHandle )
				{
				    MessageBox( hwnd, L"Error", L"Error",
                                               MB_ICONERROR );

				    DestroyWindow(hwnd);
			        }
						
			}
			break;
		    }
		}
	// other messages
	}
// other stuff in dialog procedure
}


IMPORTANT UPDATE:

Code for Excel generation is too big, but since I have a similar thread that populates predefined Word document, here is the link to that thread procedure, since the abort mechanism is practically the same:

http://pastebin.ca/2441960[^]
Posted
Updated 1-Sep-13 18:43pm
v4

You can not close/terminate a thread especially if it contains blocking function calls. You have to send a signal to the thread and then you have to wait for it to exit gracefully. You can not finish/kill a thread properly from another thread without causing possibly serious damage to the process state and without leaks.

"Earlier, I have posted here on CP, questions about multithreading, but have decided to stay away from it, since I am inexperienced."
And you are still inexperienced and you will remain inexperienced by asking the same question again and again. Multithreading is not roses all the way and sometimes there are no very good solutions. You have to wait your blocking function calls on your worker thread to finish. Period. No way to kill a thread instantly, sometimes a thread is terminating for seconds depending on the function calls it performs and the period in which it checks your cancel/exit request flag. In case of some function calls there are platform/api specific tricks that can radically speed up thread termination but since we have no clue about the code inside your try block we can not help in that.

BTW, previously you got fairly good answers to your question (with step-by-step instructions) and the answers are the same to this very same question: Delaying WM_CLOSE so I can allow threads to exit gracefully[^]

You won't get better answers. If you have no clue about multithreading but you want to write multithreading applications then learn multithreading.
 
Share this answer
 
Comments
AlwaysLearningNewStuff 2-Sep-13 0:54am    
Code is linked at the bottom of my question.

As for "multithreading" part, I have meant that I just want to spawn one thread on button press and then disable button, so I do not have to handle the case when I have a user clicking multiple times on a button, and thus spawns multiple threads.

As for my earlier questions, I didn't want to rewrite/edit them, so I have posted a new one.

Why? Because reading through those questions I have concluded that I have no sufficient control over my threads, so I wanted to resolve that problem once and for all.

I thank you for trying to help me, but at this point I think that I really need someone to browse through my code, in order to suggest me the improvements. That is why I have linked my code at the bottom of the question.

I need CODE SNIPPET, theory doesn't help. I believe that my problem can be easilly solved by adding two event objects, but I do not know how to implement them in this case. All other tutorials have main window + some threads, I have yet to find a tutorial that has main window + dialog box + thread. That is why I needed to ask this question, to clarify things via few code snippets.

I did most of the stuff you described, and it works, but I need this final piece of the puzzle by providing those who want to help my code.

Regards.
[no name] 2-Sep-13 1:06am    
What you are asking is way outside the scope of this forum. I concur with pasztorpisti that a great deal has been done by members here to assist you already. It's over to you now.
AlwaysLearningNewStuff 2-Sep-13 1:14am    
I agree, that is why I have linked my code. I believe I am close, but at this point only posting a full code can help people to show me where am I doing things wrong.
[no name] 2-Sep-13 1:16am    
Please take a break and read the answers/comments carefully. Your response bears no relationship to what I have said. This is not a forum for posting reams of code for others to analyse.
AlwaysLearningNewStuff 2-Sep-13 1:22am    
All right.

Regards.
I would create a (manual reset) event (see http://www.youtube.com/watch?v=d9AsH5i5nJ8[^]), before creating the thread, but which the thread can also access, which I would "set" when wanting to terminate the thread early (e.g. when cancel is clicked - before the wait for single object; or in the close event, etc). Then in the thread itself I would be regularly checking that the event is not set, at suitable regular intervals (again using wait for single object on the event, but with 0 time) and if it is set, exit the thread gracefully, if possible performing any "rollback" that is needed.

Is that enough help to get you started?

(You could also use a Boolean instead of an event, since setting and checking a Boolean is a single operation so should be effectively thread safe, but an event, which are also designed to be thread safe, fit more nicely into the threading model. E.g. you can use the wait to create a "periodic thread" - a job that loops but where the thread effectively "sleeps" for a time - or you could have jobs that wait on more than on event or object using the wait for multiple objects function, etc, etc).

Regards,
Ian.
 
Share this answer
 
Comments
AlwaysLearningNewStuff 1-Sep-13 20:00pm    
Thank you so much for your answer.

I did something similar, and have provided a link at the bottom of my question to the similar code. Excel function is big, but this thread function is smaller and has similar abort mechanism.

If you can take a look at it, and comment it I will greatly appreciate it.

Hopefully we will "speak" soon.

P.S. Recheck the link, currently it links to a cartoon! :))

Regards.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900