MFC programming

I believe I am in the right forum.
My project involves an exe and few dll. The dll does the work of reading the drive. Now while dll is reading the files, I want to be able to create a progress bar in the exe to display how long it is going to take for the dll to finish its work. I do realise that the dll can't access the exe resource, so I have an existing callback functions to access some of the exe functions. All I need is some direction as to how to proceed this task. Also, the dll has no idea how long it will take to finish reading the files, so this information also needs to come from the dll to the exe progress bar.
Would appreciate anyone shedding light in this project.
Thanks
Anderson.
I take it that you're coding the exe as well as the dlls?

If possible, I would have the exe display the progress information with the dll feeding back where it's gotten to via your callback mechanism. I mean, have the exe do all the feedback GUI work.

For this to work with the standard MFC controls, you'll need to avoid blocking the GUI thread. Is the file processing already being done on a worker thread?

Andy
Last edited on
Thanks for the reply Andy.

The exe and the dll are already in place. Now the task is to add the progress control to the project because some of the dlls (according to the user's query to browse through the entire disk or particular folder to read files)takes hours to display the list. The project does not include any thread at the moment.

So should I include a multi-threaded function here, one for the dll to do what it is doing now and another for the user-interface(in the exe) to update the progress bar? Can't these be done with the thread? I have not worked on thread before , so any thoughts is welcome.
Thanks
A
Well, the main UI thread should be able to not only update the progress bar, but redraw the main windows as required (e.g. if it was covered and upcovered).

It is also possible to create a second GUI thread to handle the progress bar while the main thread is off doing processing, but this would leave the main window without a thread to look after it. And the one time we were forced to do this, when adding a progress dialog to tortuous legacy code, I learnt how much harder extra GUI threads are than normal ones (not esp hard, but a good bit more work than the actual progress dialog).

I would create a UI-less worker thread to do the file processing and have it notify the main app of its progress using the message loop mechanism. Your DLL will still need to use a callback function, but that should itself use PostMessage to inform the main thread what's up. Etc.

Andy


Last edited on
Thanks again. Can you direct me to any specific link or any example I can follow as I am new to coding threads.
I have already created the callback functions from the dll to the exe with the increment number and the maximum position number for the progressbar. So every time the dll reads a file/files, it sends the message and update the progress bar in the exe. Just making some progress......
Found this tutorial article which includes a progress-bar related sample. It demos the principles using MFC as well as C#

The Practical Guide to Multithreading - Part 1
http://www.codeproject.com/Articles/43994/The-Practical-Guide-to-Multithreading-Part-1
Thank you for the link. Going into try some multi-threading coding today.
Thanks.
A
HI Again,
I need some help with my coding and would appreciate any input.

My program has a dialog box button which the user click to make the get the background task going. I have included a new dialog box with progress bar and text.
In the inital dialog box onbutton clicked event
<code>

MyDialog::ButtonClicked(){
m_progressbardialog.DoModal(); //this is added newly to bring in the //progress bar

mydll.ReadFilesFromDirectory();


}

Progress bar class
OnInitDialog()
I have set the range
set the position etc


</code>

Now the program goes to the progress bar class and starts the thread but the actual program never hit the mydll.ReadFilesFromDirectory() function.

I do realise that the program is stuck in the new thread and not sure what I am doing wrong.

Thanks



Given the code as you have written it:

1
2
3
4
5
6
7
MyDialog::ButtonClicked(){
m_progressbardialog.DoModal(); //this is added newly to bring in the //progress bar

mydll.ReadFilesFromDirectory();


}


The mydll.ReadFilesFromDirectory(); function call will not happen until the
DoModal dialog call completes.
Last edited on
I realised I have got the idea of multi-threading completly wrong and had rewritten my code. I have added the threading code in the dialog to call dll function rather than for the user-interface(progress bar).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MyDialog.cpp
MYDialog:: ButtonClicked(){
  m_pWorkerThread = ::AfxBeginThread(ThreadWorkerRoutine, this, THREAD_PRIORITY_NORMAL);
  m_progressBarDialog::DoModal();


}

static UINT ThreadWorkerRoutine(LPVOID pvParameter)
{
    CMyDialog *pRepDiag = (CMytDialog*)pvParameter;
	pRepDiag->WorkerRoutine();
	return 0;
}

MyDialog::WorkerRoutine(){

mydll.ReadFileFromDirectory();

}



Now the code will open the progressdialog simultaneously creates the thread for reading a file. Is this the right way to proceed?
THanks
Last edited on
The above code seems to do the work for me, though it throws a runtime exception on and off(haven't figured that out yet).

The dll readfilefromdirectory function includes a callback routine to update the updateProgressBar function of the Progressbar class.

1
2
3
4
5
6
7
8
9
void CProgBar::UpdateProgressControl(int iIncrementProgress, int iMaxProgress){
	if(iMaxProgress>iIncrementProgress)
		m_progBarCtrl.SetPos(IncrementProgress );
	else
		CDialog::EndDialog(true);

}


Though the EndDialog(true) is hit, the progressbar does not close by itself. And it throws the debug assertion failed error message. I believe I can sort that out. My question here is if a user clicks on cancel button in the progressbar, how do i send the message to the dll to stop what it is doing? Is there where the WM_USER come into picture?
THanks
Tip: NEVER touch the UI from a worker thread or you risk a deadlock. This article may shed some light on what you're trying to do.

http://www.codeproject.com/Articles/552/Using-Worker-Threads
A coupld of quick questions.

1 - How is "mydll" defined?

Is this a wrapper class?
Is mydll global?
Etc.

2 - Is you app using the usual Frame + View approach?

Andy
Last edited on
Thanks for the link Lodger. Will try to adapt some of the things mentioned. My idea is not to add any addition to the UI , but to let the UI know that the progress of the dll's work. Is that not possible?

THe exe is a subclass of CHtmlView. Yes it is frame/view approach.There are several dll in my project. The dlls are loaded(afxloadlibrary) at the start of the dialog and when the user chooses an option, the particular dll's function (readfiles..) is called. I hope it makes sense.
Never was keen on doing work on thread, well....I have to cross this hurdle one day or other.
The best way to inform your UI that your worker thread's progress is to use PostMessage to send your UI thread a custom Windows message. You can then catch this message in your main message loop and update your UI accordingly. Your milage may vary with the multi-DLL architecture of your project but I suspect the principles are the same. The link in my previous post explains how to do this with MFC.

I've used this method in the past (when I used to work in windows land) and it works a treat. It may be worth creating a small standalone sample application with a worker thread first then adapt it to work with your project. I'd post some sample code but I work in Mac land nowadays and don't have any to hand, sorry.
Thanks for the reply. I kind of understood what is need now. I followed what is mentioned in this link and was quite useful. http://vcfaq.mvps.org/mfc/12.htm

Now my dll will do a callback function and the actual function will postMessage with the dialog handler.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
dll.cpp

/*I am sending the max value as well as we know the maxvalue only when it's done */
mycallback.UpdateProgressControl(int incrementno, int maxvalue)


callback.cpp
UpdateProgressControl(int incrementno, int maxvalue){
 //I haven't figured out how to send an int/uint via wparam

PostMessage(m_progBar.m_hwnd, Progress_Message, wparam, Lparam)
}


progbar.cpp

ON_MESSAGE(Progress_Message, OnWorkerMessage)


LRESULT  OnWorkerMessage(WPARAM wParam, LPARAM lParam)
{	/*here i am supposed to check the current value of the progressbar to the value I got. But at the moment I am just checking if it's working by increasing the progressbar value*/

      m_progBarCtrl.SetPos(500);
	
	 
	return 0;
}

#define Progress_Message WM_USER+1 //in stdafx.h


I have defined the value of the Progress_Message in the stdafx.h as this used in two separate classes(callback and progbar.cpp which is in the exe project).

I have put a breakpoint in the callback and progbar class, but it never hits the progbar breakpoint. When I check the value of m_progbar in the callback.cpp it is 0x000000....Can some one tell me what I am doing wrong?
THanks a lot for all your help.
How are you initializing the m_progBar member of mycallback?

Andy

PS to pass an int or unsigned int value as an LPARAM or WPARAM, just cast them.

PostMessage(m_progBar.m_hwnd, Progress_Message, (WPARAM)intValue, (LPARAM)uintValue);

And recover the values with the appropriate cast the other end.

Note that for Win32, both are 32-bit values. For Win64, they're both 64-bit. (LPARAM is signed but WAPRAM unsigned)
I initialise this way in the callback class.
1
2

CProgBarDialog m_progBar;



I tried to do it this way
1
2
3
4
CProgBarDialog m_progBar;
if(!m_progBar.m_hWnd)
  m_progBar.Create();
  m_progBar.SendMessage(WM_USER, wparam, (LONG_PTR)incrementvalue)

This seems to work the first time (the OnMessage break point in the progressbar class is hit though the progressbar value remains at the same place), but the second time it does not go to the progressbar class.
I solved the problem by sending the dialog handle from the main thread to the worker thread, so the worker thread knows what dialog I am talking about. This has resolved lot of debug assertion as well.
Now I am working on how to close the dialog and send the message to the workthread.
Thanks.
I am still a little unclear about what you are doing.

Note that
- the worker thread should not be using any of MFC's GUI classes.
- when you need another thread to process a message, you need to use PostMessage (as Lodger mentioned) not SendMessage. Or PostThreadMessage().
Topic archived. No new replies allowed.