| auteur : Farscape |
Avant toute chose vérifier que les includes des classes sont bien situés dans le dossier «headers files» et non dans le dossier « external dependencies » .
Si ce n'est pas le cas procéder à un glisser déplacer avec la souris des fichiers dans le dossier «headers files».
Pour regénérer le « ClassView » la méthode la plus directe consiste à :
- Fermer le projet.
- Détruire avec l'explorateur les fichiers : .clw ,.opt ,.ncb situés dans le répertoire du projet.
- Ouvrir à nouveau le projet lancer le « ClassView ».
- Il détecte l'absence du fichier et vous ouvre alors une boîte de dialogue vous demandant de lui ré indiquer les fichiers sources.
- Indiquer le répertoire source du projet.
- Valider.
Logiquement on doit recouvrer l'usage de « intellisens » et le « ClassView » doit être opérationnel.
|
| auteur : Farscape | Plusieurs raisons possibles à ce problème :
Les includes des classes concernées ne sont pas dans le dossier header files mais dans le dossier external dependencies.
Solution faire un glisser déplacer des fichiers en question dans le bon dossier.
La ou les classes en questions ont été rajoutées manuellement ou par l'insertion d'un nouveau fichier include dans le projet sans passer par le générateur de classe.
Reconstruire le classview comme indiquer dans la faq : Que faire si le ClassView n'affiche pas toutes les classes ?
|
| auteur : Farscape | L'arborescence d'un projet Visual n'est pas figée ,
On peut créer des sous répertoires par un click droit avec l'option « new folder » sur le dossier sources ou headers files.
Pensez à récupérer la liste des extensions de fichiers gérée par dossier en faisant click droit propriétés sur un dossier existant (sources ou headers) et procéder par copier coller pour recopier les extensions.
Ensuite il suffira de déplacer les fichiers par glisser déplacer ou de les insérer par un click droit « add files ».
On pourra organiser les sources par thèmes exemple :
Les sources concernant les différents outils,
Les gestions de fichiers,
Les traitements etc ...
On procédera de la même manière pour les « includes »
|
| auteur : Farscape | Pour disposer du browser de code sélectionner :
Le menu projects option settings puis l'onglet C++ »
Dans la zone category sélectionner listing files .
Puis cocher « generate browse info. ».
Le fichier se construit et suivra l'évolution du projet.
Pour accéder au browser sélectionner le ClassView faire click droit et
sélectionner une des trois options :
- references ;
- derived classes ;
- base classes.
|
| auteur : Farscape |
L'option RTTI ou Run-Time Type Information permet l'utilisation du mot clef dynamic_cast . (Voir documentation MDSN)
Pour l'activer sélectionner le menu Projects option Settings Onglet C++ .
Category : C++ Language.
Cocher :Enable Run-Time Type Information (RTTI).
|
| auteur : Farscape | L'environnement de Visual 6.0 peut être sauvegardé en exportant la clef suivante de la base de registre:
HKEY_CURRENT_USER\Software\Microsoft\Devstudio\6.0
Pour sauvegarder uniquement les chemins des includes ,des librairies etc ..:
HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Build System\Components\Platforms\Win32 (x86)\Directories
|
| auteur : Farscape |
Au niveau de la librairie :
Attention au départ des numéros d'id des contrôles dans le fichier resources.h
Celui-ci doit être renommé pour éviter les conflits avec le projet maître (voir ci-dessous).
Au niveau du projet maître :
il suffira de rajouter dans le menu :
View - ressources includes :
Dans la première partie de la fenêtre après axfres.h le fichier ressource de la librairie (dont il faudra changer le nom pour éviter les conflits :autre chose que resource.h !)
Exemple ici MyLibRes.h
# include "afxres.h"
# include "MyLibRes.h"
|
Deuxième partie de la fenêtre:
Il faudra rajouter le fichier .rc de la librairie ici MyLib.rc.
# define _AFX_NO_SPLITTER_RESOURCES
# define _AFX_NO_OLE_RESOURCES
# define _AFX_NO_TRACKER_RESOURCES
# define _AFX_NO_PROPERTY_RESOURCES
# if ! defined ( AFX_RESOURCE_DLL ) | | defined ( AFX_TARG_FRA )
# ifdef _WIN32
LANGUAGE 12 , 1
# pragma code_page ( 1252 )
# endif
# include "res\MonProjet.rc2" // non-Microsoft Visual C++ edited resources
# include "l.fra\afxres.rc" // Standard components
# include "l.fra\afxprint.rc" // printing/print preview resources
# include "MyLib.rc"
# endif
|
Et procéder à la compilation des ressources.
|
| auteur : Farscape | Exemple : Prenons le cas d'une fenêtre CDialog où l'on voudrait intercepter le message WM_ACTIVATE.
Il n'apparaît pas par défaut dans la liste des messages de la boîte de dialogue .
Pour y remédier sélectionner l'onglet "Class Info" et mettre dans la liste déroulante "message filter": Windows à la place de Dialog ,revenir ensuite sur l'onglet "message maps" maintenant le message est disponible?
|
| auteur : Farscape | Lors de la compilation de sources employant les STL on rencontre souvent le Warning C4786 avec un message à rallonge ressemblant à ceci :
warning C4786: 'blablabla ' : identifier was truncated to '255' characters in the debug information
Ce qui est souvent bénin, la solution pour enlever ce Warning est de rajouter la ligne suivante dans stdafx.h
# pragma warning ( disable : 4786 )
|
|
| auteur : Farscape | Après le lancement de l'option File new, sélectionner l'option Custom AppWizard
Entrer le nom du projet qui servira de modèle dans l'édit Project Name :
Exemple :MyCustomApp.
Valider le choix par le bouton Ok .
Sur le deuxième volet laisser l'option : An existing Projet
Cliquer sur le bouton Next pour choisir le projet source qui servira de modèle de génération.
Valider le choix par le bouton Finish.
Le projet est généré il ne reste plus qu'à le compiler et le linker.
Un nouveau type de projet sera alors disponible dans la boîte de dialogue de création de projets.
Description visuelle du procédé:
http://farscape.developpez.com/Samples/MakeCustomApp.pdf
|
| auteur : Farscape | Il faut choisir le type : projet win32 ,et dans les paramètres application cocher l'option bibliothèque statique.
|
| auteur : Loulou24 | Visual C++ 6 est sorti en 1998, et donc n'inclus pas la dernière norme du C++ , datant de la même année. Il en résulte certains manques, et des résultats parfois étonnants avec du code pourtant parfaitement valide.
Voici quelques exemples de codes standards mais qui ne compilent pas sous VC++ 6
for (int i = 0 ; i < 50 ; + + i)
{
}
for (int i = 0 ; i < 20 ; + + i)
{
}
|
Ce code est pourtant correct : en effet la portée de la variable i devrait être limitée au bloc de la boucle concernée.
Une solution (de derrière les fagots) pour corriger ce manque : inclure systématiquement nos boucles dans un if, ainsi la portée sera bien limitée
# define for if ( true ) for
|
struct A
{
static const int Taille = 12 ;
int Tab[Taille];
} ;
|
Ce code devrait compiler, car les constantes entières statiques peuvent être initialisées dans leur définition.
struct A
{
void Func ()
{
}
} ;
std:: vector< A> Tab;
std:: for_each (Tab.begin (), Tab.end (), std:: mem_fun_ref (A:: Func));
|
Cette écriture devrait être possible, mais VC6 ne sait pas la gérer du fait de son manque de spécialisation partielle de template.
std:: set< int > s;
std:: vector< int > v (s.begin (), s.end ());
std:: list< int > l;
l.sort (std:: less< int > ());
|
VC6 ne gère pas correctement les fonctions membres template de classe template, ce qui entre autre vous empêchera d'utiliser les fonctions de la STL prenant en entrée une paire d'itérateurs quelconques, ou list::sort avec un foncteur personnalisé.
|
| auteur : nico-pyright(c) |
Touche |
Action |
CTRL+F2 |
marquer une ligne / F2 : passer à la marque suivante |
ALT+F8 |
indentation de la sélection |
CTRL+E |
identifier les accolades, parenthèses, crochets |
CTRL+Espace |
complétion automatique |
CTRL+SHIFT+Espace |
prototype de la fonction |
F4 |
aller à la 1ere erreur de compilation, puis erreur suivante |
|
| auteur : Farscape | Le compilateur suivant les cas à l'exécution peut affecter des valeurs spécifiques à une variable pointeur,
Connaître ces valeurs peut s'avérer fort utile en mode Debug :
0xFDFDFDFD indique une adresse en dehors de l'espace d'adressage du processus.
0xDDDDDDDD indique que la mémoire vient d'être libérée.
Attention ça ne veut pas dire que l'instruction delete va mettre cette valeur dans un pointeur.
0xCDCDCDCD mémoire globale non initialisée par exemple un pointeur membre d'une classe .
0xCCCCCCCC mémoire locale (pile /stack ) non initialisée par exemple un pointeur déclaré dans une fonction membre d'une classe.
On comprend l'utilité de toujours initialiser les pointeurs à NULL ,et de leur affecter cette valeur après libération de la mémoire.
Ce qui nous amène à l'erreur la plus commune : 0xc0000005 Access Violation
Un exemple simple :
Dans la fonction OnInitialUpdate d'une CFormView je fais la chose suivante :
CDialog * pdlg;
pdlg- > ShowWindow (1 );
|
J'ai droit à un beau message de violation d'accès 0xc0000005
En debug si je regarde la valeur de this dans ShowWindow il a la valeur reconnaissable 0xcccccccc et le debugger met des ??? Dans le handle de fenêtre.
Pour résumer lorsque vous tracez un programme en debug et que vous tombez sur ce message,
Pensez à regarder la valeur affectée à this ,
Ou remonter d'un cran dans la pile des appels pour regarder la valeur du pointeur.
|
| auteur : Farscape | Il est tout à fait possible de mélanger des sources en C extension .c et des sources en C++ au sein du même projet.
Détail de la procédure :
Il faudra veiller à enlever au niveau des options de compilation des fichiers en C l'option entêtes pré compilés :
Avec Visual C++6.0 :
Dans la gestion de projet à gauche sélectionner le(s) fichier(s) en C
Puis faire clic droit settings .
Dans l'onglet onglet C++ sur la catégorie precompiled header cocher not using precompiled headers.
Astuce : Pour la multi sélection des fichiers utiliser la touche CTRL+clic gauche.
Enfin tous les prototypes des fonctions en C devront être déclarés avec extern "C" :
Exemple de .h pour déclarer les fonctions en C pour utilisations en C et C++
# ifdef __cplusplus
extern " C "
{
# endif
void myfct (int c);
# ifdef __cplusplus
}
# endif
|
|
| auteur : Farscape | Microsoft avec un outil gratuit dénommé HTML Help Workshop permet de fabriquer un système d'aide à partir de fichier HTML, remplaçant ainsi avantageusement l'ancien système à base de fichier RTF.
Ceux-ci pouvant être composés avec FrontPage par exemple.
Le fichier d'aide généré aura une extension .chm et peut être entièrement autonome, c'est-à-dire pas forcément rattaché à un programme.
Pour une prise en main du kit voir le tutoriel de thierry aim sur notre site: http://thierry_aim.developpez.com/htmlhelp/
Cliquer ici pour le téléchargement du kit sur le site de Microsoft
Maintenant nous allons voir comment établir le lien entre un projet développé avec le kit de Microsoft et un programme MFC .
A terme l'appui de la touche F1 sur une fenêtre particulière (FormView) invoquera l'aide correspondante dans le fichier d'aide.
Génération du fichier de liens entre les formes et l'aide :
Pour établir un lien entre le fichier d'aide et le programme il faut faire un fichier de correspondance qui peut être généré automatiquement par visual .
Sur les propriétés du projet : (menu projects /settings )
Onglet custom build :
Dans la partie gauche des fichiers du projet, sélectionner le fichier resource.h
Dans l'édit descriptions : on renseigne le libellé par exemple : Making HTML Help Include File...
Et dans l'édit Commands :
makehm ID_,IDH_,0x10000 IDM_,IDH_,0x10000 resource.h > > " hlp\$(TargetName).hm "
echo. > > " hlp\$(TargetName).hm "
makehm IDP_,IDH_,0x30000 resource.h > > " hlp\$(TargetName).hm "
makehm IDR_,IDH_,0x20000 resource.h > > " hlp\$(TargetName).hm "
makehm IDD_,IDH_,0x20000 resource.h > > " hlp\$(TargetName).hm "
makehm IDW_,IDH_,0x50000 resource.h > > " hlp\$(TargetName).hm "
MakeIDH " hlp\$(TargetName).hm "
|
makehm va faire le lien entre les différents type de ressources du projet en un identifiant unique commençant par IDH et dont la plage des différents types est reparti .
le fichier généré portera le nom du projet suivi de l'extension .hm.
À indiquer dans l'édit Outputs
la première compilation des ressources le fichier .hm va être généré .
Note : le programme MakeIDH doit être présent à la racine du projet.
Compilation automatique du projet d'aide à partir de visual 6: (falcutatif)
Le fichier .hpp doit être inclu dans le projet.
Sur les propriétés du projet : (menu projects /settings )
Onglet custom build :
Dans la partie gauche des fichiers du projet, sélectionner le fichier .hpp
Dans l'édit descriptions : on renseigne le libellé par exemple : Making HTML Help Include File...
Et dans l'édit Commands :
hhc.exe html\$(InputName).hhp
echo.
copy html\$(InputName).chm $(OutDir)\$(InputName).chm
|
Dans l'édit Outputs:
cliquer ensuite sur le bouton dependencies et rajouter
Dans l'onglet link :
Object/library modules, rajouter : htmlhelp.lib
Lien du fichier d'aide .chm avec le programme :
Dans la fonction InitInstance de la classe d'application on va modifier le lien de l'aide qui est par défaut sur une extension .HLP
CString strHelpFile = m_pszHelpFilePath;
strHelpFile.Replace (" .HLP " , " .chm " );
free ((void * )m_pszHelpFilePath);
m_pszHelpFilePath = _tcsdup (strHelpFile);
|
Le fichier .chm devra être au même emplacement que le programme.
Appel de l'aide par la touche F1 :
Dans la classe CMainFrame rajouter manuellement le message
ON COMMAND (IDHELP_CMDIFrameWnd :: OnHelp)
END_MESSAGE_MAP ()
|
dans le cas d'un projet SDI :
ON_COMMAND (ID_HELP, CFrameWnd:: OnHelp)
|
Au niveau de la classe CMainFrame rajouter avec l'aide classwizard la fonction virtuelle :WinHelp .
virtual void WinHelp (DWORD dwData, UINT nCmd = HELP_CONTEXT);
|
Et remplacer le contenu par :
void CMainFrame:: WinHelp (DWORD dwData, UINT nCmd)
{
CMyApp * pApp= static_cast < CMyApp * > (AfxGetApp ());
# if _MFC_VER > = 0x0700
:: HtmlHelp ((pApp- > m_bHelpModal?m_hWnd:NULL ), AfxGetApp ()- > m_pszHelpFilePath, HH_HELP_CONTEXT,nCmd= = HELP_CONTEXT?dwData:0 );
# else
HtmlHelp ((pApp- > m_bHelpModal?m_hWnd:NULL ), AfxGetApp ()- > m_pszHelpFilePath, HH_HELP_CONTEXT,nCmd= = HELP_CONTEXT?dwData:0 );
# endif
}
|
la variable est un booleen permettant de choisir si l'appel de l'aide est bloquante ou non .
pour finir dans le hhp on doit avoir les sections suivantes :
[MAP]
# include MyApp.hm
[TEXT POPUPS]
MyApp.hm
[MERGE FILES]
MyApp.chm
|
on peut rajouter ces sections avec l'aide de notepad.
c'est au niveau de la section alias dans le programme help workshop que l' on va définir les liens :
on va associer un numero d'id IDH à une page web.
en faisant double click sur la section alias on renseignera le nom de l'include:
sur l'onglet map avec l'aide du bouton header file on indiquera le chemin du fichier .hm.
dans l'onglet alias on établira directement le lien entre l'id IDH_ et la page web.
Note:
à la racine du projet on doit avoir les répertoires :
html et hlp.
|
| auteur : Farscape | Le détail de l'erreur avec visual .net :
Fin de fichier inattendue lors de la recherche d'une directive d'en-tête précompilé
Pour visual 6.0 :
unexpected end of file while looking for precompiled header directive
Explications :
Dans la plupart des cas Visual génère un projet avec l'option en-tête précompilé .
Les en-têtes précompilés représentent des instantanés de compilation pris à un certain emplacement du code source.
Il est pris juste après l'inclusion de la ligne #include "stdafx .h"
qui contient les fichiers d'en-têtes des MFC ou template .
Les en-têtes précompilés font donc gagner du temps à la compilation.
A partir du moment où cette option est réglée pour le projet tous les fichiers .CPP du projet doivent avoir en tout début du source la ligne :
#include "stdafx .h"
Sinon le compilateur généra le message C1010 ?
Note : il est possible de désactiver spécifiquement par fichier cette option ,c'est le cas par exemple si on veut mixer des fichiers .c et .cpp dans un même projet
Voir Comment intégrer des sources C dans un projet C++ ?
|
| auteur : nico-pyright(c) | En utilisant l'API OutputDebugString et un petit logiciel qui intercepte ces informations de débugage (disponible ici) : pour NT/2000/XP - pour Win9x
Une fois ce programme lancé, un simple OutputDebugString (" Informations à voir affichées " );
|
permet de voir la ligne dans la fenêtre.
|
| auteur : nico-pyright(c) | Lors de l'utilisation de grosses variables dans un programme, on se demande souvent comment sont allouées les différentes variables. ( voir portée des variables)
On peut résumer rapidement en disant que :
Une déclaration de type a une portée locale à la fonction (ou au bloc {} )et est allouée sur la pile (stack)
Une allocation dynamique de type int * monTableau = new int [20000 ]
|
a une portée définie par l'utilisation de new et de delete et est allouée sur le tas (heap)
Les variables globales sont définies dans le segment de données.
La taille par défaut du tas est de 1 Mo. Cette taille par défaut peut être augmentée en réglant une option du linker C'est bien souvent inutile, car le tas peut augmenter tout seul lorsque l'allocation est supérieure à la mémoire par défaut.
C'est le système d'exploitation qui gère cela tout seul (de la même facon, il préfèrera déléger à VirtualAlloc lorsque l'allocation dépasse un certain seuil).
Cette option est rarement utilisée, sauf pour des questions de performances.
La pile dispose elle aussi d'une taille par défaut d'1 Mo. Cependant, celle-ci est fixe et ne peut augmenter seule. Ainsi, lorsque l'on déclare beaucoup de grosses variables, il peut se produire une erreur de dépassement de mémoire : stack overflow.
On peut de même facilement augmenter la mémoire de la pile par défaut en réglant une option du linker.
Le linker utilise par défaut une valeur de 0x100000 (1 Mo) et 0x1000 (4Ko) pour la mémoire commit
donc pour réserver 2 Mo par exemple, il suffit de réserver cette mémoire dans le linker par :
Remarque : C'est en général une mauvaise idée d'avoir une grosse pile. Il est plus judicieux d'utiliser des allocations dynamiques pour les gros objets.
|
| auteur : Farscape | cette erreur peut apparaitre à l'exécution du programme en mode debug,
Il faudra régler la valeur de génération du manifest à oui dans les options d'édition des liens du projet.
Menu Project / Properties /Configuration Properties /Linker/ Manifest File mettre "Generate Manifest" à Yes.
Voir ce lien MSDN pour en savoir plus.
|
| auteur : Farscape |
Vous avez certainement remarqué qu'il est très pratique de visualiser directement le contenu de certains objets dans la fenêtre de Visual ou encore en passant la souris sur un objet pour inspecter le contenu d'une CString par exemple ?
Et bien cette fonctionnalité de visualiser les données membres importantes d'un objet qu'il soit MFC ou autre est personnalisable.
Ce paramétrage est à mettre en place dans un fichier nommé AUTOEXP.DAT
Il est situé pour Visual 6.0 à l'emplacement :
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin
Sous Visual 2005 :
C:\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger
Voici un aperçu de son contenu:
; from afxwin.h
CDC = hDC= < m_hDC> attrib= < m_hAttribDC>
CPaintDC = < ,t> hWnd= < m_hWnd>
CPoint = x= < x> y= < y>
CRect = top= < top> bottom= < bottom> left= < left> right= < right>
CSize = cx= < cx> cy= < cy>
CWnd = < ,t> hWnd= < m_hWnd>
CWinApp = < ,t> < m_pszAppName,s>
CWinThread = < ,t> h= < m_hThread> proc= < m_pfnThreadProc>
; from afx.h
CArchiveException = cause= < m_cause>
CFile = hFile= < m_hFile> name= < m_strFileName.m_pchData,s>
CFileException = cause= < m_cause> OS Error= m_lOsError
CMemFile = pos= < m_nPosition> size= < m_nFileSize>
CObject = < ,t>
CRuntimeClass = < m_lpszClassName,s>
CStdioFile = FILE* = < m_pStream> name= < m_strFilename.m_pchData,s>
CTimeSpan = time= < m_time>
CTime = time= < m_time>
|
On retrouve la liste des objets MFC avec les données membres importantes à visualiser.
Une description des formats d'affichages est disponible dans ce même fichier :
Letter Description Sample Display
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; d,i Signed decimal integer 0xF000F065 ,d - 268373915
; u Unsigned decimal integer 0x0065 ,u 101
; o Unsigned octal integer 0xF065 ,o 0170145
; x,X Hexadecimal integer 61541 ,X 0X0000F065
; l,h long or short prefix for 00406042 ,hx 0x0c22
; d, i, u, o, x, X
; f Signed floating- point 3 ./ 2 .,f 1 .500000
; e Signed scientific- notation 3 ./ 2 .,e 1 .500000e + 000
; g Shorter of e and f 3 ./ 2 .,g 1 .5
; c Single character 0x0065 ,c ' e '
; s Zero- terminated string pVar,s " Hello world "
; su Unicode string pVar,su " Hello world "
|
Pour rajouter vos propres classes il suffit d'éditer ce fichier avec notepad et de rajouter une section pour vos différents objets.
La syntaxe générale est la suivante :
L'objet =leLibelledonnéemembre<donnée membre>
Plusieurs variables membre peuvent être indiquées à la suite.
Les types simples entiers double etc sont correctement interprétés.
Pour une variable membre de type CString il faudra donner le chemin de la chaîne interne :
name=<m_strFilename.m_pchData,s> avec le type s voulant dire chaîne se terminant par un zéro.
|
| auteur : Farscape | Pour inscrire un nouveau type de fichier procéder comme suit:
avec le programme regedit (faire démarrer exécuter, saisir regedit) ouvrir la clef :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Languages\File Extensions
suivant les versions de compilateurs on aura à la place de 8.0 pour VC 2005
7.0 pour .net2002 et 7.1 pour .net 2003
Si on désire que l'extension de fichier .pc soit reconnue comme un .C on créera le répertoire .PC en dessous de la clef File Extensions
Ensuite dans la clef .c copier le contenu de la zone défaut dans le presse papiers
Coller la valeur dans la zone défaut de la clef ajoutée (ici .pc)
Pour intégrer IntelliSense modifier la clef suivante :
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\Languages\Language Services\C/C++\NCB Default C/C++ Extensions
il suffit de rajouter aux extensions existantes la nouvelle extension (ici .pc)
|
| auteur : nico-pyright(c) | Lorsqu'on migre petit à petit son projet en C++.Net ou simplement lorsqu'on veut faire cohabiter l'Api Win32 (ou les MFC) et le framework.Net, on peut rencontrer des problèmes de compilation du style :
error C2039: ' GetObjectA ' : is not a member of ' System::Resources::ResourceManager '
error C2653: ' MessageBoxA ' : is not a class or namespace name
|
Le problème vient du fait que lorsqu'on souhaite utiliser la fonction MessageBox par exemple, le compilateur ne sait pas s'il doit utiliser la fonction MessageBox définie dans Windows.h ou bien dans le namespace System::Windows::Forms.
Il faut donc à ce moment dire au compilateur quelle fonction on veut utiliser.
On enlève alors la définition du MessageBox comme ci-dessous
# pragma push_macro ( " MessageBox " )
# undef MessageBox
...
MessageBox:: Show (S" hello " );
...
# pragma pop_macro ( " MessageBox " )
|
Ainsi le compilateur saura qu'il faut utiliser le MessageBox de .Net
|
| auteur : nico-pyright(c) | - Soit en l'ajoutant dans les options du projet, pour VS2005 : propriétés du projet, configuration properties, linker, input, additional dependencies et indiquer ici le .lib à lier.
- Soit par pragma
# pragma comment ( lib , " malib . lib " )
|
|
| auteur : Farscape | Lorsque la bibliothèque de runtime (CRT) est utilisée en mode statique /MT (multi-thread statique)
(en opposition au mode dynamique /MD (dll)), il peut apparaitre ce type d'erreurs lorsqu'on utilise plusieurs bibliothèques :
nafxcwd.lib (afxmem.obj) : error LNK2005: " void * __cdecl operator new(unsigned int) " (??2 @YAPAXI@Z) already defined in LIBCMTD.lib (new .obj)
nafxcwd.lib (afxmem.obj) : error LNK2005: " void __cdecl operator delete(void *) " (??3 @YAXPAX@Z) already defined in LIBCMTD.lib (dbgdel.obj)
nafxcwd.lib (afxmem.obj) : error LNK2005: " void * __cdecl operator new[](unsigned int) " (??_U@YAPAXI@Z) already defined in libcpmtd.lib (newaop.obj)
nafxcwd.lib (afxmem.obj) : error LNK2005: " void __cdecl operator delete[](void *) " (??_V@YAXPAX@Z) already defined in LIBCMTD.lib (delete2.obj)
|
Comment régler ce problème ? , il faut changer l'ordre des liens des bibliothèques incriminées comme suggéré dans cette note MSDN.
Voici comment procéder :
Avec Visual 2005 dans les propriétés du projet, chapitre éditeur de liens.
Rubrique Entrée, zone : "bibliothèque spécifique ignorée", mettre : Nafxcwd.lib Libcmtd.lib (pour le mode debug).
Dans la zone : "dépendances supplémentaires" mettre en dernier à la suite des autres bibliothèques utilisées par le projet: Nafxcwd.lib Libcmtd.lib
|
| auteur : Farscape | Sous Windows Vista avec l'UAC lorsqu'une tâche nécessite un privilège administrateur il faut elever les droits de l'application
Comment gérer la situation ?
Soit on change les droits d'accès sur le programme par clic droit onglet compatibilité : exécuter en tant que administrateur, un peu pénible...
ou bien on rajoutera le fichier manifest suivant à notre application :
?xml version= " 1.0 " encoding= " UTF-8 " standalone= " yes " ?>
< assembly xmlns= " urn:schemas-microsoft-com:asm.v1 " manifestVersion= " 1.0 " >
< assemblyIdentity name= " monapplication "
version= " 1.0.0.0 "
processorArchitecture= " X86 "
type= " win32 " / >
< description> Mon Application< / description>
< ! - - Identify the app' s security requirements. -->
< trustInfo xmlns= " urn:schemas-microsoft-com:asm.v3 " >
< security>
< requestedPrivileges>
< requestedExecutionLevel level= " requireAdministrator " / >
< / requestedPrivileges>
< / security>
< / trustInfo>
< / assembly>
|
|
| auteur : Farscape | Au fil des ans et des différentes versions de Windows, nombre d'applications ont été conçues pour avoir un accès direct à des emplacements systèmes ou tout simplement à la base de registres.
Sous Vista ces emplacements sont maintenant verrouillés pour réduire la surface d'attaque du système.
Pour garder une compatibilité avec les anciens programmes Vista implémente un service de virtualisation de l'UAC qui redirige de manière transparente les accès aux parties protégées du système (fichier ,base de registres) vers un emplacement virtualisé et non protégé faisant croire ainsi à l'application qu'elle écrit à l'emplacement d'origine.
Exemple :
Un programme exécuté avec des droits utilisateurs s'installe dans le répertoire :
C:\Program Files\<application>\
L'accès sera automatiquement virtualisé à l'emplacement :
C:\Users\<votre_compte>\AppData\Local\VirtualStore\Program Files\<application>
Si le programme doit impérativement écrire à l'emplacement d'origine il faudra élever les droits de l'application en administrateur.
On procédera comme suit :
Soit on change les droits d'accès sur le programme par clic droit onglet compatibilité : exécuter en tant que administrateur, un peu pénible...
ou bien on rajoutera avec les versions de Visual antérieure à Visual 2008 le fichier manifest suivant à notre application : Comment rajouter le fichier manifeste du style XP au manifeste existant dans Visual 2005 ?
xml version= " 1.0 " encoding= " UTF-8 " standalone= " yes " ?>
< assembly xmlns= " urn:schemas-microsoft-com:asm.v1 " manifestVersion= " 1.0 " >
< assemblyIdentity name= " monapplication "
version= " 1.0.0.0 "
processorArchitecture= " X86 "
type= " win32 " / >
< description> Mon Application< / description>
< ! - - Identify the app' s security requirements. -->
< trustInfo xmlns= " urn:schemas-microsoft-com:asm.v3 " >
< security>
< requestedPrivileges>
< requestedExecutionLevel level= " requireAdministrator " / >
< / requestedPrivileges>
< / security>
< / trustInfo>
< / assembly>
|
à intégrer suivant la technique décrite dans la faq : Comment rajouter le fichier manifeste du style XP au manifeste existant dans Visual 2005 ?
au moment d'exécuter le programme Vista demandera l'acceptation de l'utilisateur pour l'élévation des droits sauf évidemment si vous avez désactivé l'UAC.
Pour conclure :
Il faut bien comprendre que ce mécanisme de virtualisation a été implémenté par Microsoft pour permettre une transition en « douceur » des applications.
Mais il ne faut pas trop compter sur la solution de la virtualisation, car rien ne garantit que ce mécanisme soit encore présent dans les futures versions de Windows?
|
lien : Comment rajouter le fichier manifeste du style XP au manifeste existant dans Visual 2005 ?
|
| auteur : Farscape | Visual 2008 permet la gestion du manifest UAC au niveau du projet.
Le réglage de cette option permet de spécifier le niveau d'exécution demandé pour l'application.
Trois options sont disponibles :
AsInvoker : l'application devra s'exécuter avec le jeton actuel de l'appelant sans demander une élévation de privilèges.
highestAvailable : l'application s'exécutera avec le privilège le plus haut que le compte utilisateur possède.
RequireAdministrator: l'application doit s'exécuter avec un jeton complet d'administration.
L'UAC demandera à l'utilisateur l'autorisation de donner l'accès au jeton complet si le compte administrateur fonctionne avec le jeton restreint.
|
| auteur : Farscape | Les classes MFC utilisent l'héritage simple. Dans le cas où l'on voudrait se passer de l'héritage multiple pour enrichir des classes existantes il est possible d'utiliser les classes templates.
Démonstration :
L'exemple ci-dessus montre l'implémentation d'une classe template pour la gestion des couleurs,
Celle-ci est associée à trois classes dialogues.
Technique d'implémentation :
On déclare la classe avec un paramètre qui est aussi utilisé pour spécifier le parent.
template < class GENERIC_DLGCOLOR >
class CTplDlgColor : public GENERIC_DLGCOLOR
{
public :
CTplDlgColor (UINT nID= 0 ,CWnd* pParent= NULL ) :GENERIC_DLGCOLOR (nID,pParent)
{
m_HbrClrCtlBk= NULL ;
m_ClrCtlText= RGB (0 , 0 , 0 ) ;
}
~ CTplDlgColor ()
{
if (m_HbrClrCtlBk) :: DeleteObject (m_HbrClrCtlBk);
}
virtual BOOL OnWndMsg (UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (message= = WM_CTLCOLOR)
{
return TRUE;
}
return GENERIC_DLGCOLOR:: OnWndMsg (message, wParam, lParam, pResult);
}
} ;
|
La déclaration pour les classes à enrichir :
class CTabInformation : public CTplDlgColor< CDialog>
{
public :
CTabInformation (CWnd* pParent = NULL );
} ;
|
Coté source :
CTabInformation:: CTabInformation (CWnd* pParent )
: CTplDlgColor< CDialog> (CTabInformation:: IDD, pParent)
{
m_pTab = NULL ;
}
void CTabInformation:: DoDataExchange (CDataExchange* pDX)
{
CTplDlgColor< CDialog> :: DoDataExchange (pDX);
}
|
Les avantages de la classe patron (template) utilisée de cette manière sur l'héritage multiple sont nombreux.
Les problèmes liés à des méthodes membres qui sont présentes plusieurs fois dans les ancêtres d'une classe peuvent être résolus simplement si ces méthodes sont virtuelles comme dans l'exemple ci-dessus avec la méthode OnWndMsg.
Utilisation native des méthodes sans cast sur la classe de base ici CWnd
Souplesse d'intégration dans une classe existante.
Etc..
Les Inconvénients :
Le fait de devoir mettre le code dans le .h, ce qui nuit à la lisibilité, même en séparant dans un deuxième fichier la partie implémentation, cela peut avoir un impact sur le temps de compilation si cette classe est souvent utilisée ou si le code est conséquent.
Alors les classes patrons solution idéale ?
Presque, j'en viens maintenant au problème qui est apparu avec Visual 2005,
Un bug du ClassView empêche pour des classes dialogues (CFormView, CDialog, CDialogBar) construites à partir de classe patron la reconnaissance de la classe.
Dans ce contexte la demande de génération d'une variable contrôle à partir des ressources échoue, l'option contrôle variable étant grisée.
Pour résumer si vous utilisez une classe patron sur une classe dialogue il faudra vous passer de l'assistant pour associer une variable à son contrôle.
J'ai signalé ce problème au support Microsoft, la réponse est qu'effectivement le problème est constaté mais ce n'est pas une priorité et ne sera pas résolu?
Donc en conclusion tout était parfait avec Visual 6.0 , avec Visual 2005 et 2008 beaucoup moins..
Si l'assistant est indispensable Il faudra donc recourir à l'héritage multiple et se passer des classes patrons.
|
| auteur : Farscape | Dans les propriétés du projet sur l'onglet link/system on trouve l'option /TSAWARE.
Cette option permet de spécifier que l'application est compatible Terminal Serveur et n'apporte pas de modification au chargement du programme.
Quelles sont les conséquences de cette option ?
Dans le cas d'une application non compatible (on parle d'application héritée ou legacy)
Terminal Serveur apporte des modifications pour faire fonctionner correctement l'application dans un environnement multi-utilisateur.
Ainsi il va créer un dossier Windows virtuel pour que chaque utilisateur puisse accéder à ses propres fichiers .ini ou à son paramétrage dans la base de registres dans la clef HKEY_CURRENT_USER
Donc par défaut Visual 2008 considère que l'application est compatible avec Terminal Serveur et que vous n'utilisez pas les .ini ou la clef HKEY_CURRENT_USER
Ce qui signifie que par exemple que l'api32 GetWindowsDirectory renvoie toujours C:\windows quelque soit l'utilisateur, j'en ai fait les frais il n'y pas longtemps?
Ce qui n'était pas le cas sous Visual 6.0?
|
| auteur : Farscape | Une application compatible Terminal serveur ne gère plus un emplacement virtualisé pour la gestion des fichiers ini.
Voir ce post de la faq pour plus de renseignements Comment rendre une application compatible terminal serveur ?
Dans ces conditions comment récupérer ce chemin virtualisé ?
On utilisera la fonction SHGetFolderPath avec l'option CSIDL_PROFILE.
L'exemple ci-dessous récupère le chemin du profil utilisateur et crée le répertoire Windows s'il n'existe pas.
TCHAR szPath[MAX_PATH];
if (SUCCEEDED (SHGetFolderPath (NULL ,
CSIDL_PROFILE | CSIDL_FLAG_CREATE,
NULL , 0 ,szPath)))
{
PathAppend (szPath, TEXT (" Windows " ));
if (! PathIsDirectory (szPath)) CreateDirectory (szPath,NULL );
}
|
|
lien : Comment rendre une application compatible terminal serveur ?
|
| auteur : Farscape | Le passage de Visual 2005 à Visual 2008 n'est pas sans surprises ?
Vous avez dû certainement vous rendre compte que pour de vieux projets issus de Visual6 ou autres Visual définissait par défaut la plateforme système à Windows Vista ?
Laisser ce choix par défaut n'est pas sans danger, en effet certaines API comme SystemParametersInfo ne fonctionneront plus sous windows XP, la fonction renverra NULL!.
Je me sers de cette API pour récupérer la fonte système par défaut, donc par chance je me suis rendu assez vite compte du problème avec le code suivant :
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof (NONCLIENTMETRICS);
VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICS), & ncm, 0 ));
SetFont (& (ncm.lfMessageFont));
|
à qui La faute ?
Eh bien la structure utilisée a changée de taille sous Vista, en laissant le paramétrage par défaut sur Vista la taille de la structure évaluée par sizeof correspond donc à la version de l'API sous Vista, et l'appel échouera sous Windows XP.
En cherchant un peu dans les sources de Visual 2008 on trouve une référence à l'ancienne structure que vous pouvez comparer à la nouvelle..
struct AFX_OLDNONCLIENTMETRICS
{
UINT cbSize;
int iBorderWidth;
int iScrollWidth;
int iScrollHeight;
int iCaptionWidth;
int iCaptionHeight;
LOGFONT lfCaptionFont;
int iSmCaptionWidth;
int iSmCaptionHeight;
LOGFONT lfSmCaptionFont;
int iMenuWidth;
int iMenuHeight;
LOGFONT lfMenuFont;
LOGFONT lfStatusFont;
LOGFONT lfMessageFont;
} ;
typedef struct tagNONCLIENTMETRICS {
UINT cbSize;
int iBorderWidth;
int iScrollWidth;
int iScrollHeight;
int iCaptionWidth;
int iCaptionHeight;
LOGFONT lfCaptionFont;
int iSmCaptionWidth;
int iSmCaptionHeight;
LOGFONT lfSmCaptionFont;
int iMenuWidth;
int iMenuHeight;
LOGFONT lfMenuFont;
LOGFONT lfStatusFont;
LOGFONT lfMessageFont;
int iPaddedBorderWidth;
} NONCLIENTMETRICS,
|
Comment résoudre ce problème ?
Dans les sources de Visual 2008, le problème est résolu pour cette API comme suit :
struct AFX_OLDNONCLIENTMETRICS
{
UINT cbSize;
int iBorderWidth;
int iScrollWidth;
int iScrollHeight;
int iCaptionWidth;
int iCaptionHeight;
LOGFONT lfCaptionFont;
int iSmCaptionWidth;
int iSmCaptionHeight;
LOGFONT lfSmCaptionFont;
int iMenuWidth;
int iMenuHeight;
LOGFONT lfMenuFont;
LOGFONT lfStatusFont;
LOGFONT lfMessageFont;
} ;
const UINT cbProperSize = (_AfxGetComCtlVersion () < MAKELONG (1 , 6 ))
? sizeof (AFX_OLDNONCLIENTMETRICS) : sizeof (NONCLIENTMETRICS);
NONCLIENTMETRICS NonClientMetrics;
NonClientMetrics.cbSize = cbProperSize;
:: SystemParametersInfo (SPI_GETNONCLIENTMETRICS, cbProperSize, & NonClientMetrics, 0 );
m_MenuFont.CreateFontIndirect (& NonClientMetrics.lfMenuFont);
|
Comme il est difficile de connaître les autres incompatibilités, il est préférable de définir un niveau de plateforme de Windows compatible au plus près de sa cible.
Dans mon cas avec un poste de production sous Windows XP je l'ai défini dans stdafx.h (au sommet)
# if _MSC_VER > 1200
# define WINVER 0x0500 / / windows 2000
# define _WIN32_WINNT 0x0501 / / xp
# endif
|
|
Consultez les autres F.A.Q.
|
|