Avec les MFC nous avons deux sortes de threads qui puissent être crées :

A. Les threads de travail sont ceux qui généralement ne nécessitent aucune interaction directe avec les éléments de l'I.H.M (Objets fenêtres, boîtes de dialogues, contrôles, etc...). Ce genre de thread servent souvent à faire des traitements ou calculs relativement longs et à retourner leur résultat au thread principale. La communication entre le thread principale et les thread de travail se font soit par partage des objets globaux tels que des objets de synchronisations ou par des messages utilisateurs windows. Ces threads là sont parfois utiles pour éviter de figer le thread principale et de permettre à l'utilisateur d'avoir la main (souris) libre sur l'IHM de l'application.

B. Les threads d'interface utilisateur sont ceux qui possèdent leurs propres pompes à messages et donc permettent de gérer les messages windows au même titre que le thread principal où l'emploie de tous les objets MFC tels que les documents, les vues, les frames, les boites de dialogues, les contrôles etc... sont permis contrairement au thread de travail où certaines concessions doivent être faîtes.

Pour créer un thread UI:

1. Vous devez ajouter une classe application ou une classe de thread c'est à dire un CWinThread dans votre projet pour le nouveau thread.

Ici l'idée est que chaque thread UI possède :
- son objet application (objet Win Thread),
- sa pompe à message et
- sa fenêtre windows principale qui lui est propre.

Vous retiendrez au fait que votre CWinApp de toujours n'est qu'un CWinThread pour lequel les assistants code initialise correctement le thread principale pour vous.

Donc vous vous retrouvez avec votre application MFC avec au moins deux têtes c'est à dire deux objets applications ou objets win thread.

2. Chaque objet application nécessite qu'il soit initialisé à partir de sa méthode virtuelle InitInstance(). C'est ce que faît généralement votre thread principal. Bien entendu vous nettoyez votre thread UI dans ExitInstance().

3. Vous n'oubliez pas non plus à indiquez à votre objet win thread dans son InitInstance() ça fenêtre principale.

4. Quelques parts dans votre code vous lancer votre thread UI en transmettant à AfxBeginThread le runtime class de votre CWinThread.

5. Pour fermer votre thread UI vous fermez simplement sa fenêtre principale de la même manière que vous mettez fin à votre thread principale. C'est à dire que le thread UI recoit un WM_QUIT qui lui permet de sortir de sa boucle de messages dans CWinThread::Run().

Bon un peu de code :

La classe du Win thread que j'ajoute au projet
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
#pragma once
 
// CMyUIThread  est la classe de mon objet win thread
 
class CMyUIThread : public CWinThread
{
	DECLARE_DYNCREATE(CMyUIThread)
 
protected:
	CMyUIThread();           // protected constructor used by dynamic creation
	virtual ~CMyUIThread();
 
public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();
 
protected:
	DECLARE_MESSAGE_MAP()
};
J'initialise mon objet win thread
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
BOOL CMyUIThread::InitInstance()
{
	// TODO:  perform and per-thread initialization here
 
             // la boite de dialogue "A propos" est la fenêtre principale de mon UI thread
 
	CAboutDlg dlg; 
 
	m_pMainWnd = &dlg;  // j'indique à mon objet la fenêtre principale
 
             dlg.DoModal();    // bon j'affiche.
	return TRUE;
}
Noter que la fenêtre principale de votre UI Thread peut être une frame entière où vous utilisez votre modèle document-vues et le tout dans un thread.

A partir d'une commande de menu je lance mon UI Thread où je transmet non pas une fonction globale ni une méthode statique mais le runtime class de mon CWinThread à AfxBeginThread().

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
 
void CMainFrame::OnUiThread()
{
	// TODO: Add your command handler code here
 
	CWinThread* pUIThread = AfxBeginThread(RUNTIME_CLASS(CMyUIThread));
 
             // je peux stocker mon pUIThread si je veux intéragir directement par programmation avec mon UI Thread en faisant par exemple un CWinThread::PostThreadMessage()
 
}
A partir de cet exemple c'est comme si on a une application dialog based (dans le UI Thread) à l'intérieur d'une application MDI (le thread principale).

Et donc deux modèles de programmation MFC dans un seul projet.

Voilà