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
- 2.1. Les Fichiers .ini (8)
- Comment récupérer le pointeur sur l'application?
- Comment récupérer le nom de l'application ?
- Comment trouver le nom de l'exécutable (uniquement) ?
- Comment retrouver le chemin de l'exécutable (uniquement) ?
- Comment changer le nom d'une application MFC ?
- Comment démarrer l'application en mode maximisé ?
- Comment récupérer le pointeur sur la fenêtre principale de l'application ?
- Comment parcourir dans un contexte MDI toutes les fenêtres de l'application ?
- Comment empêcher de lancer plusieurs instances d'un programme ?
- Comment enregistrer les extensions de documents dans l'explorateur Windows ?
- Comment récupérer la ligne d'arguments passée à l'application ?
- Comment mettre en place une variable globale dans un projet ?
- Comment récupérer une CString de la liste des fichiers récents ( Most Recently Used ) ?
en appelant la fonction globale:
Code c++ : | Sélectionner tout |
1 2 | AfxGetApp() ; |
Code c++ : | Sélectionner tout |
1 2 | CWinApp* AfxGetApp( ); |
Code c++ : | Sélectionner tout |
1 2 | AfxGetApp()->m_lpCmdLine |
Code c++ : | Sélectionner tout |
1 2 3 4 | AfxGetAppName() ; // ou AfxGetApp()->m_pszAppName |
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); } |
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); } |
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); |
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; } |
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('\\')); } |
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); |
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"); |
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(); |
Code c++ : | Sélectionner tout |
1 2 | CWnd* AfxGetMainWnd( ); |
Code c++ : | Sélectionner tout |
1 2 | CMyMainFrame *p=(CMyMainFrame *)AfxGetMainWnd() ; |
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 } } } } } |
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é. } |
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); } //................ |
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 ); |
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(); // ... } |
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.
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]); } //.......................... |
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(); |
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.
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]; } |
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 çaLes 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.