Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionvoid CMonAppDlg::OnBRestart() { ... AfxBeginThread( g_PseudoThreadFunction, (LPVOID)this ) ; }
{ ((CMonAppDlg*)pParam) -> m_ThreadFunc() ; return 0 ; }
void CMonAppDlg::m_ThreadFunc() { ... UpdateData(false) ; ... return ; // ferme proprement le thread en remontant les appels }
//*************************************************************************************** // MFCThreadDlg.h : header file // //*************************************************************************************** #ifndef AFX_MFCTHREADDLG_H_INCLUDED_ #define AFX_MFCTHREADDLG_H_INCLUDED_ //*************************************************************************************** // Classe CMFCThreadDlg. //*************************************************************************************** class CMFCThreadDlg : public CDialog { //======================================================================================= // Membres privés. //======================================================================================= private : // icone associée à la boîte de dialogue HICON m_hIcon; // police de caractère pour l'affichage CFont* m_pFont; // heure de départ du chronomètre, offset éventuel à rajouter DWORD m_dwStartTime; DWORD m_dwOffsetTime; // thread du chronomètre, états (m_bThreadRunning est volatile pour que sa valeur // soit évaluée à chaque boucle et éviter des optimisations du compilateur menant // à un deadlock) CWinThread* m_pThread; BOOL m_bPause; volatile BOOL m_bThreadRunning; // synchronisation des threads (pour qu'un seul ai accès aux variables partagées // à un instant donné) CRITICAL_SECTION m_cs; //======================================================================================= // Méthodes privées. //======================================================================================= private : // met à jour l'état des boutons void UpdateButtons(); // point d'entrée du thread du chronomètre static UINT ThreadFunc(LPVOID lpData); //======================================================================================= // Méthodes publiques. //======================================================================================= public : // constructeur CMFCThreadDlg(CWnd* pParentWnd = NULL); //======================================================================================= // Données de la boîte de dialogue. //======================================================================================= protected : //{{AFX_DATA(CMFCThreadDlg) enum { IDD = IDD_MFCTHREAD }; CStatic m_StcCounter; CButton m_BtnStart; CButton m_BtnStop; CButton m_BtnPause; //}}AFX_DATA //======================================================================================= // Méthodes virtuelles redéfinies. //======================================================================================= //{{AFX_VIRTUAL(CMFCThreadDlg) protected : virtual void DoDataExchange(CDataExchange* pDX); //}}AFX_VIRTUAL //======================================================================================= // Traitement des messages. //======================================================================================= protected : //{{AFX_MSG(CMFCThreadDlg) virtual BOOL OnInitDialog(); afx_msg void OnBtnStart(); afx_msg void OnBtnStop(); afx_msg void OnBtnPause(); afx_msg void OnDestroy(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #endif // AFX_MFCTHREADDLG_H_INCLUDED_
//*************************************************************************************** // MFCThreadDlg.cpp : implementation file // //*************************************************************************************** #include "StdAfx.h" #include "MFCThread.h" #include "MFCThreadDlg.h" //======================================================================================= // Tables des messages pour CMFCThreadDlg. //======================================================================================= BEGIN_MESSAGE_MAP(CMFCThreadDlg, CDialog) //{{AFX_MSG_MAP(CMFCThreadDlg) ON_BN_CLICKED(IDC_MFCTHREAD_BTN_START, OnBtnStart) ON_BN_CLICKED(IDC_MFCTHREAD_BTN_STOP, OnBtnStop) ON_BN_CLICKED(IDC_MFCTHREAD_BTN_PAUSE, OnBtnPause) ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() //*************************************************************************************** // Constructeur. //*************************************************************************************** CMFCThreadDlg::CMFCThreadDlg(CWnd* pParentWnd) : CDialog(CMFCThreadDlg::IDD, pParentWnd) { //{{AFX_DATA_INIT(CMFCThreadDlg) //}}AFX_DATA_INIT // initialisation des paramètres m_pFont = NULL; m_dwStartTime = 0; m_dwOffsetTime = 0; m_pThread = NULL; m_bThreadRunning = FALSE; m_bPause = FALSE; // chargement de l'icone asociée à la boîte de dialogue m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } //*************************************************************************************** // DoDataExchange : //*************************************************************************************** void CMFCThreadDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMFCThreadDlg) DDX_Control(pDX, IDC_MFCTHREAD_STC_COUNTER, m_StcCounter); DDX_Control(pDX, IDC_MFCTHREAD_BTN_START, m_BtnStart); DDX_Control(pDX, IDC_MFCTHREAD_BTN_STOP, m_BtnStop); DDX_Control(pDX, IDC_MFCTHREAD_BTN_PAUSE, m_BtnPause); //}}AFX_DATA_MAP } //*************************************************************************************** // UpdateButtons : //*************************************************************************************** void CMFCThreadDlg::UpdateButtons() { // bouton [Démarrer] m_BtnStart.EnableWindow(m_pThread == NULL); // bouton [Arrêter] m_BtnStop.EnableWindow(m_pThread != NULL); // bouton [Pause\Reprendre] m_BtnPause.SetWindowText(m_bPause ? _T("Reprendre") : _T("Pause")); m_BtnPause.EnableWindow(m_pThread != NULL); } //*************************************************************************************** // ThreadFunc : //*************************************************************************************** UINT CMFCThreadDlg::ThreadFunc(LPVOID lpData) { // récupération objet CMFCThreadDlg associé CMFCThreadDlg* pMFCThreadDlg = (CMFCThreadDlg*)lpData; // tant que le thread doit tourner (m_bThreadRunning est volatile pour que sa valeur // soit évaluée à chaque boucle et éviter des optimisations du compilateur menant // à un deadlock. A priori inutile si utilisée à travers un pointeur) while(pMFCThreadDlg->m_bThreadRunning) { // pause de 5 ms Sleep(5); // calcul de la nouvelle valeur du chronomètre EnterCriticalSection(&pMFCThreadDlg->m_cs); DWORD dwTime = GetTickCount()-pMFCThreadDlg->m_dwStartTime+ pMFCThreadDlg->m_dwOffsetTime; LeaveCriticalSection(&pMFCThreadDlg->m_cs); // décomposition des minutes, secondes et centièmes de seconde int nMinutes = dwTime/60000; int nSeconds = (dwTime-60000*nMinutes)/1000; int nHundreth = (dwTime%1000)/10; // formatage chaîne et affichage (sauf si le thread a été arrêté entre temps) if(pMFCThreadDlg->m_bThreadRunning) { CString strTime; strTime.Format(_T("%02d:%02d:%02d"), nMinutes, nSeconds, nHundreth); pMFCThreadDlg->m_StcCounter.SetWindowText(strTime); } } return 0; } //======================================================================================= // Gestionnaire de messages pour CMFCThreadDlg. //======================================================================================= //*************************************************************************************** // OnInitDialog : //*************************************************************************************** BOOL CMFCThreadDlg::OnInitDialog() { // appel fonction de la classe de base CDialog::OnInitDialog(); // affectation des icones (grande et petite) SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // création police de caractères (3/4 de la hauteur du CStatic) CRect rcStcCounter; m_StcCounter.GetClientRect(&rcStcCounter); m_pFont = new CFont(); m_pFont->CreateFont(3*rcStcCounter.Height()/4, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, 0, 0, 0, 0, NULL); // affectation au contrôle CStatic m_StcCounter.SetFont(m_pFont, FALSE); // initialisation section critique InitializeCriticalSection(&m_cs); // mise à jour de l'état des boutons UpdateButtons(); // retour return TRUE; } //*************************************************************************************** // OnDestroy : //*************************************************************************************** void CMFCThreadDlg::OnDestroy() { // destruction de la police de caractères ASSERT(m_pFont != NULL); m_pFont->DeleteObject(); delete m_pFont; // on stoppe le chronomètre OnBtnStop(); // destruction section critique DeleteCriticalSection(&m_cs); // appel fonction de la classe de base CDialog::OnDestroy(); } //*************************************************************************************** // OnBtnStart : //*************************************************************************************** void CMFCThreadDlg::OnBtnStart() { // si un thread est déjà en cours if(m_pThread != NULL) return; // heure de début, offset m_dwStartTime = GetTickCount(); m_dwOffsetTime = 0; // création d'un nouveau thread (on met m_bAutoDelete car on gèrera la destruction) m_bPause = FALSE; m_bThreadRunning = TRUE; m_pThread = AfxBeginThread(CMFCThreadDlg::ThreadFunc, this, THREAD_PRIORITY_BELOW_NORMAL, 0, CREATE_SUSPENDED, NULL); m_pThread->m_bAutoDelete = FALSE; m_pThread->ResumeThread(); // mise à jour de l'état des boutons UpdateButtons(); } //*************************************************************************************** // OnBtnStop : //*************************************************************************************** void CMFCThreadDlg::OnBtnStop() { // si aucun thread en cours if(m_pThread == NULL) return; // arrêt du thread, si le thread était suspendu, on le reprend m_bThreadRunning = FALSE; if(m_bPause) m_pThread->ResumeThread(); m_bPause = FALSE; // on attend que le thread s'arrête (on traite les messages en attente car le thread // est susceptible d'envoyer des messages aux contrôles créé par le thread principal) while(::WaitForSingleObject(m_pThread->m_hThread, 10) != WAIT_OBJECT_0) { // traiter les messages en attente MSG msg; if(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } // destruction de l'objet CWinThread delete m_pThread; m_pThread = NULL; // mise à jour de l'état des boutons UpdateButtons(); } //*************************************************************************************** // OnBtnPause : //*************************************************************************************** void CMFCThreadDlg::OnBtnPause() { // si aucun thread en cours if(m_pThread == NULL) return; // pause/reprise du thread if(m_bPause) { // on affecte la nouvelle heure de départ EnterCriticalSection(&m_cs); m_dwStartTime = GetTickCount(); m_pThread->ResumeThread(); LeaveCriticalSection(&m_cs); } else { // on sauvegarde la valeur actuelle pour s'en servir d'offset EnterCriticalSection(&m_cs); m_pThread->SuspendThread(); m_dwOffsetTime = GetTickCount()-m_dwStartTime+m_dwOffsetTime; LeaveCriticalSection(&m_cs); } m_bPause = !m_bPause; // mise à jour de l'état des boutons UpdateButtons(); }
IDD_MFCTHREAD DIALOGEX 0, 0, 250, 110 STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "MFCThread" FONT 8, "MS Sans Serif" BEGIN CTEXT "00:00:00",IDC_MFCTHREAD_STC_COUNTER,10,10,230,70, SS_CENTERIMAGE PUSHBUTTON "Démarrer",IDC_MFCTHREAD_BTN_START,10,90,50,14 PUSHBUTTON "Arrêter",IDC_MFCTHREAD_BTN_STOP,70,90,50,14 PUSHBUTTON "Pause",IDC_MFCTHREAD_BTN_PAUSE,130,90,50,14 PUSHBUTTON "Fermer",IDCANCEL,190,90,50,14 END