IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ VC++ et MFCConsultez toutes les FAQ

Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013  Ajouter une question

 

Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++

Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.

Sur ce, je vous souhaite une bonne lecture. Farscape

SommaireClasse d'application (CWinApp) (21)
précédent sommaire suivant
 

en appelant la fonction globale:

Code c++ : Sélectionner tout
1
2
  
AfxGetApp() ;
Code c++ : Sélectionner tout
1
2
  
CWinApp* AfxGetApp( );
On pourra aussi disposer de la ligne de commande de l'application :

Code c++ : Sélectionner tout
1
2
  
AfxGetApp()->m_lpCmdLine

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
3
4
  
AfxGetAppName() ; 
// ou  
AfxGetApp()->m_pszAppName

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
// trouver le nom (uniquement) de l'executable 
void GetNom(char *nom, DWORD taille) 
{ 
char *c; 
c = nom + GetModuleFileName(NULL,nom,taille); 
while(*c!='\\') c--; 
strcpy(nom,++c); 
}
ou

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
// trouver le nom (uniquement) de l'executable (CString) 
CString CGetNom(char *nom, DWORD taille) 
{ 
GetModuleFileName(NULL,nom,taille); 
CString Cnom(nom); 
return Cnom.Mid(Cnom.ReverseFind('\\')+1); 
}
Appel :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
char nom[MAX_PATH]; 
GetNom(nom,MAX_PATH); 
  
// ou 
char nom[MAX_PATH]; 
CString Cnom = CGetNom(nom, MAX_PATH);

Mis à jour le 4 avril 2005 nico-pyright(c)

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
  
// trouver le chemin (uniquement) de l'application 
void GetChemin(char *chemin, DWORD taille) 
{ 
char *c; 
c = chemin + GetModuleFileName(NULL,chemin,taille); 
while(*c!='\\') 
c--; 
*c=0; 
}
ou

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
// trouver le chemin (uniquement) de l'application (CString) 
CString CGetChemin(char *chemin, DWORD taille) 
{ 
GetModuleFileName(NULL,chemin,taille); 
CString Cchemin(chemin); 
return Cchemin.Mid(0,Cchemin.ReverseFind('\\')); 
}
Appel :

Code c++ : Sélectionner tout
1
2
3
4
5
6
char chemin[MAX_PATH]; 
GetChemin(chemin, MAX_PATH); 
  
// ou 
CString Cchemin = CGetChemin(chemin, MAX_PATH); 
AfxMessageBox(Cchemin);

Mis à jour le 4 avril 2005 nico-pyright(c)

En utilisant la fonction AfxSetWindowText.
Cette fonction n'est pas documentée !
Il faut l'appeler dans InitInstance après l'initialisation de la MainFrame

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
  
// a rajouter pour la définition  
#include <afxpriv.h>  
  
pMainFrame->ShowWindow(m_nCmdShow); 
pMainFrame->UpdateWindow(); 
AfxSetWindowText(m_pMainWnd->m_hWnd,"TestSDI- Farscape");

Mis à jour le 5 avril 2013 farscape

Dans la fonction InitInstance de la classe d'application modifier comme suit :

Code c++ : Sélectionner tout
1
2
3
4
  
m_nCmdShow = SW_SHOWMAXIMIZED ; 
m_pMainWnd->ShowWindow(m_nCmdShow); 
m_pMainWnd->UpdateWindow();

Mis à jour le 5 avril 2013 farscape

Code c++ : Sélectionner tout
1
2
  
CWnd* AfxGetMainWnd( );
Code c++ : Sélectionner tout
1
2
  
CMyMainFrame *p=(CMyMainFrame *)AfxGetMainWnd() ;

Mis à jour le 5 avril 2013 farscape

Le point de départ c'est la classe d'application qui donne accès aux documents Template.

Code c++ : Sélectionner tout
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
31
32
33
34
35
36
37
38
39
40
41
42
43
  
CWinApp* pApp = AfxGetApp();         
// parcourir tous les templates 
CDocTemplate* pTemplate; 
POSITION pos = pApp->GetFirstDocTemplatePosition(); 
while (pos != NULL) 
{ 
    pTemplate = pApp->GetNextDocTemplate(pos); 
    ASSERT(pTemplate); 
  
    // tous les documents du template. 
    POSITION pos2 = pTemplate->GetFirstDocPosition(); 
    while (pos2) 
    { 
        CDocument* pDoc = pTemplate->GetNextDoc(pos2); 
        ASSERT(pDoc); 
  
        // toutes les vues du document 
        POSITION pos3 = pDoc->GetFirstViewPosition(); 
        while (pos3 != NULL) 
        { 
            CView* pView = pDoc->GetNextView(pos3); 
            ASSERT(pView); 
            if (::IsWindow(pView->GetSafeHwnd())) 
            { 
                if(pView->IsKindOf(RUNTIME_CLASS(CFormView))) 
                { 
                // une forme view 
                } 
                else 
                if(pView->IsKindOf(RUNTIME_CLASS(CScrollView))) 
                { 
                // une  Scrollview 
                } 
                else 
                if(pView->IsKindOf(RUNTIME_CLASS(CView))) 
                { 
                    // une  view 
                } 
            } 
        } 
    } 
}

Mis à jour le 5 avril 2013 farscape

Plusieurs solutions peuvent être employées.
La plus simple à mon avis consiste à utiliser la possibilité de partager des variables pour tous les processus du programme.

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  
// déclaration d'une section TestApp 
  
#pragma data_seg("TestApp")  
  
// la variable commune a tous les process 
LONG nCtApp = -1;  
#pragma data_seg() 
  
// directive pour le link. 
  
#pragma comment(linker, "/section:TestApp,rws")  
  
// Test incrémentation de la variable.  
  
bool bFirstInstance =  (InterlockedIncrement(&nCtApp) == 0); 
if(!bFirstInstance) 
{ 
       // erreur le prog est déjà lancé. 
}
Voir la note d'information MSDN sur le sujet : HOWTO: Specify Shared and Nonshared Data in a DLL Q100634
Autre solution possible, utiliser un objet Mutex.
exemple:

Code c++ : Sélectionner tout
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
31
  
// .h 
// 
class CSdisamplesApp : public CWinApp 
{ 
public: 
CSdisamplesApp(); 
    ~CSdisamplesApp(); 
    CMutex     m_Mutex; 
    bool       m_bLock; 
    //................ 
  
// .cpp 
CSdisamplesApp::CSdisamplesApp():m_bLock(false),m_Mutex(FALSE,"SDISAMPLE") 
{ 
// TODO: add construction code here, 
// Place all significant initialization in InitInstance 
} 
CSdisamplesApp::~CSdisamplesApp() 
{ 
// Destruct 
    if(m_bLock) m_Mutex.Unlock();     
}     
BOOL CSdisamplesApp::InitInstance() 
{     
    if(!(m_bLock=m_Mutex.Lock(0))) 
    { 
        AfxMessageBox("Application active"); 
        return(0); 
    } 
//................

Mis à jour le 10 septembre 2005 farscape

Dans un projet MFC pour chaque document template on peut associer une extension de fichier .
Comment faire pour que lorsque l'on double-clique sur un document géré par l'application celle -ci s'exécute ?
Il faut enregistrer les extensions dans la base de registre .
Pour un programme MFC il y a une fonction qui fait ce travail :

Code c++ : Sélectionner tout
1
2
  
void RegisterShellFileTypes( BOOL bCompat = FALSE );
La valeur bCompat a TRUE permet l'insertion des entrées impression et impression sur dans la base de registre ainsi que le sélectionner glisser lâcher du document sur une imprimante.

Cette fonction est à insérer derrière le dernier AddocTemplate dans la fonction InitInstance de la classe d'application.
La fonction EnableShellOpen doit être appelée.

Code c++ : Sélectionner tout
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
31
32
33
34
  
BOOL CMyApp::InitInstance()  
{  
   // ...  
  
   CMultiDocTemplate* pDocTemplate;  
   pDocTemplate = new CMultiDocTemplate(  
      IDR_MYTYPE,  
      RUNTIME_CLASS(CMyDoc),  
      RUNTIME_CLASS(CMDIChildWnd),        // standard MDI child frame  
      RUNTIME_CLASS(CMyView));  
   AddDocTemplate(pDocTemplate);  
  
   // Create main MDI Frame window.  
   CMainFrame* pMainFrame = new CMainFrame;  
   if (!pMainFrame->LoadFrame(IDR_MAINFRAME))  
      return FALSE;  
   // Save the pointer to the main frame window.  This is the  
   // only way the framework will have knowledge of what the  
   // main frame window is.  
   m_pMainWnd = pMainFrame;  
  
   // enable file manager drag/drop and DDE Execute open  
   EnableShellOpen();  
   RegisterShellFileTypes();  
   // ...  
  
   // Show the   main window using the nCmdShow parameter  
   // passed to the application when it was first launched.  
   pMainFrame->ShowWindow(m_nCmdShow);  
   pMainFrame->UpdateWindow();  
  
   // ...  
}

Mis à jour le 5 avril 2013 farscape

La classe CWinApp (classe d'application) permet d'accéder à la ligne de commande par l'intermédiaire de sa donnée membre m_lpCmdLine

On pourra l'utiliser directement dans la fonction InitInstance, ou y accéder de partout dans l'application grâce à la fonction globale AfxGetApp()

Code c++ : Sélectionner tout
AfxGetApp()->m_lpCmdLine.
Les arguments sont séparés par un blanc, pour disposer de la liste comme dans un programme classique en C avec la fonction main, on pourra procéder de la manière suivante :

Code c++ : Sélectionner tout
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
  
BOOL CSampleSDIApp::InitInstance() 
{ 
    AfxEnableControlContainer(); 
  
    char szName[MAX_PATH];     
    GetModuleFileName(NULL,szName,MAX_PATH); 
  
    CArray<CString ,const char *> argv; // attention il faut mettre #include <afxtempl.h> dans stdafx.h 
  
    char *szArg=strtok(m_lpCmdLine," "); 
  
    argv.Add(szName); // argv[0]=path de l'application. 
    if(szArg)  
    { 
        do 
       { 
          argv.Add(szArg); 
       } 
       while(szArg=strtok(NULL," ")); 
   } 
  
    int argc=argv.GetSize(); 
    for(int i=0;i<argc;i++) 
    { 
        TRACE("\nArgv[%d]=%s",i,argv[i]); 
    } 
//..........................

Mis à jour le 27 novembre 2005 farscape

L'utilisation d'une variable globale objet a travers un projet est parfois nécessaire.
Je vous propose deux méthodes pour y parvenir:
Utiliser l'instance d'application pour stocker notre variable globale :
En effet une application MFC génère une seule instance de la classe d'application qui a la particularité d'être disponible à tout instant en utilisant la fonction globale AfxGetApp().
Il me suffira donc de déclarer l'objet ou la fonction à partager dans le projet dans la classe d'application et d'y accéder comme suit :

Code c++ : Sélectionner tout
1
2
3
4
  
CMyApp *pApp=static_cast<CMyApp *>(AfxGetApp()); 
pApp->m_Global.MyFunction();     //exemple de fonction globale  
CListCtrm &rList=pApp->m_Global.GetLisCtrl(); // variable globale.

Autre solution utiliser le pattern Singleton : Définition
Le pattern Singleton garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global à cette instance.

L'Exemple qui suit est adapté de ma lecture du livre : Design Patterns tête la première (en java mais très accessible à un lecteur C++).

Code c++ : Sélectionner tout
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  
namespace Singleton { 
  
class MyClass 
{ 
    private: static MyClass*  m_pUniqueInstance; 
    private: static CMutex      m_LockInstance; // warning -> :#include <afxmt.h> 
  
    private: MyClass(const MyClass&); // Disable copy constructor 
    private: void operator=(const MyClass&); // Disable assignment operator 
  
    private: MyClass() 
    { 
        // Initialisations 
    } 
    private: ~MyClass() 
    {  
        m_pUniqueInstance = 0; 
    } 
    public: static MyClass &GetInstance() 
    { 
        if (m_pUniqueInstance == 0) 
        {             
            m_LockInstance.Lock(); 
            if (m_pUniqueInstance == 0) 
                m_pUniqueInstance = new MyClass(); 
            m_LockInstance.Unlock(); 
        }         
        return *m_pUniqueInstance; 
    } 
    public: static void FreeInstance() 
    { 
        m_LockInstance.Lock(); 
        delete m_pUniqueInstance; 
        m_LockInstance.Unlock(); 
    } 
    // users functions.     
    void UserFunction() 
   { 
        ASSERT(m_pUniqueInstance); 
   } 
  
}; 
  
} 
// namespace Singleton 
// init static data 
CMutex     Singleton::MyClass::m_LockInstance; 
Singleton::MyClass*  Singleton::MyClass::m_pUniqueInstance=NULL; 
  
// utilisation. 
Singleton::MyClass &theClass=Singleton::MyClass::GetInstance(); 
theClass.UserFunction(); 
// ou 
Singleton::MyClass::GetInstance().UserFunction(); 
// libération 
Singleton::MyClass::FreeInstance();
Il existe de multiples exemples où le singleton est utile : objet de journalisation, de préférence de l'application etc ..
L'exemple que j'ai implémenté utilise un Mutex pour contrôler la création de l'instance, ce qui est préférable dans un contexte d'utilisation multithreads.
Ce même mutex pourra être utilisé pour gérer des accès à des variables ou des fonctions de la classe.
On placera la définition de la classe singleton dans l' include de la classe d'application pour que sa définition soit disponible dans toute l'application.
La déclaration des variables static pourra être faite dans le source de la classe d'application.

Mis à jour le 22 janvier 2007 farscape

Une application MFC met en place une MRU ( Most Recently Used ), mais ne fournit pas d'accès directe à celle-ci pour y accéder .
En cherchant dans le code des MFC et plus exactement dans la fonction LoadStdProfileSettings on s'aperçoit que la liste est gérée par la donnée membre m_pRecentFileList de la classe CRecentFileList

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  
void CWinApp::LoadStdProfileSettings(UINT nMaxMRU) 
{ 
    ASSERT_VALID(this); 
    ASSERT(m_pRecentFileList == NULL); 
  
    if (nMaxMRU != 0) 
    { 
        // create file MRU since nMaxMRU not zero 
        m_pRecentFileList = new CRecentFileList(0, _afxFileSection, _afxFileEntry, 
            nMaxMRU); 
        m_pRecentFileList->ReadList(); 
    } 
    // 0 by default means not set 
    m_nNumPreviewPages = GetProfileInt(_afxPreviewSection, _afxPreviewEntry, 0); 
}

Pour accéder à cette liste déclarée protect dans la classe CWinApp on rajoutera un accesseur dans notre classe d'application :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
  
class CMyApp : public CWinApp 
{ 
public: 
    CMyApp (); 
    inline CRecentFileList *GetRecentFileList(){return m_pRecentFileList;} 
//... 
};

On rajoutera aussi le fichier :

Code c++ : Sélectionner tout
1
2
  
#include <afxadv.h>

Dans stdafx.h

Exemple Utilisation :

Code c++ : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
  
void CTestToolBarView::OnInitialUpdate() 
{ 
//... 
  CMyApp *TheApp=static_cast<CMyApp *>(AfxGetApp()); 
  
    CString str; 
    for( int i=0;TheApp->GetRecentFileList()->GetSize( );i++) 
        str=(*TheApp->GetRecentFileList())[i]; 
}

Mis à jour le 22 janvier 2007 farscape

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.