Modifications ATL et MFC : ATL 7.0 et MFC 7.0
Mise à jour : novembre 2007
Remarque Il se peut que certaines fonctionnalités mentionnées dans cette rubrique ne soient pas encore opérationnelles dans la version actuelle de Visual C++.
Depuis Visual C++ 6.0, les bibliothèques ATL et MFC ont fait l'objet de nombreuses améliorations. Certaines de ces modifications peuvent interrompre le code existant.
Incompatibilités des DLL
Les fichiers DLL ATL et MFC fournis avec Visual C++ .NET 2002 ont été respectivement renommés ATL70.dll et MFC70.dll.
Les classes ATL et MFC de Visual C++ .NET n'étant pas compatibles au format binaire avec les mêmes classes des versions précédentes, il est nécessaire de régénérer avec Visual Studio .NET tout code source généré à l'aide de mfc42.dll. Tous les fichiers DLL ou LIB utilisés par votre application doivent également être régénérés avec Visual Studio .NET.
Ainsi, une bibliothèque contenant une fonction exportée prenant CString comme paramètre et qui a été générée avec Visual C++ 6.0 donnera lieu à un externe non résolu pendant la liaison avec un projet Visual C++ .NET.
Classes du module ATL
ATL 3.0 a fourni la classe CComModule. Dans ATL 7,0, la fonctionnalité précédemment fournie par CComModule est gérée par plusieurs nouvelles classes. Pour plus d'informations, consultez Classes du module ATL.
Conversions de chaînes
Dans les versions d'ATL, version ATL 3.0 incluse, dans Visual C++ 6.0, les conversions de chaînes employant les macros dans atlconv.h étaient toujours effectuées en utilisant la page de codes ANSI du système (CP_ACP). À partir d'ATL 7.0, dans Visual C++ .NET, les conversions de chaînes sont effectuées à l'aide de la page de codes ANSI par défaut du thread actuel, sauf si _CONVERSION_DONT_USE_THREAD_LOCALE est défini, auquel cas c'est la page de codes ANSI du système qui est utilisée comme avant.
Notez que les classes de conversion de chaînes, telles que CW2AEX, vous permettent de passer une page de codes qui sera utilisée pour la conversion vers leurs constructeurs. Si aucune page de codes n'est spécifiée, les classes utilisent alors la même page de code que les macros.
Pour plus d'informations, consultez Macros de conversion de chaînes ATL et MFC.
CException est maintenant une classe de base abstraite
CException est la classe de base de toutes les exceptions dans la bibliothèque MFC (Microsoft Foundation Class). CException étant maintenant une classe de base abstraite, vous ne pouvez pas créer d'objets CException directement ; vous devez créer des objets de classes dérivées. Si vous créez un objet directement, une erreur apparaît. Pour plus d'informations, consultez CException.
Conversion de BSTR en CString
Dans Visual C++ 6.0, le code suivant était accepté :
BSTR bstr = SysAllocString(L"Hello");
CString str = bstr;
SysFreeString(bstr);
Avec les nouveaux projets sous Visual C++ .NET, l'erreur suivante se produit dans les versions ANSI :
error C2440: 'initializing' : cannot convert from 'BSTR' to
'ATL::CStringT<BaseType,StringTraits>'
Il existe à présent des versions UNICODE et ANSI de CString (CStringW et CStringA). Pour signaler toute charge inutile induite par les conversions implicites, les constructeurs prenant le type inverse (CStringA prenant un argument UNICODE ou CStringW prenant un argument ANSI, par exemple) sont maintenant identifiés comme étant explicites à l'aide de l'entrée suivante dans le fichier stdafx.h :
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
Pour contourner cette erreur, effectuez l'une des opérations suivantes :
Utilisez CStringW pour éviter la conversion :
BSTR bstr = SysAllocString(L"Hello"); CStringW str = bstr; SysFreeString(bstr);
Appelez le constructeur de façon explicite :
BSTR bstr = SysAllocString(L"Hello"); CString str = CString(bstr); SysFreeString(bstr);
Supprimez la ligne #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS de stdafx.h.
Modifications apportées à CTime
La CTime Class utilise le type de données sous-jacent __time64_t. Dans MFC 6.0, CTime utilisait le type de données time_t qui est ensuite devenu un type 32 bits. Cette modification a été apportée pour assurer la prise en charge des heures au-delà de 3:14:07, le 19 janvier 2038.
Modifications de CComEnumImpl::Skip
La méthode CComEnumImpl::Skip dans les versions antérieures à ATL 7.0 ne retourne pas le code d'erreur correct si la valeur entrée est 0. Elle traite également les grandes valeurs d'entrée de façon incohérente. Ces problèmes ont été résolus dans ATL 7.0.
Assertions CWnd::DestroyWindow
Une erreur d'assertion se produit si une info-bulle était affichée dans CWnd::DestroyWindow. Par conséquent, sous MFC 7.0, les variables membres suivantes ont été déplacées de AFX_THREAD_STATE vers **AFX_MODULE_THREAD_STATE **:
CToolTipCtrl* m_pToolTip
CWnd* m_pLastHit
int m_nLastHit
TOOLINFO m_lastInfo
int m_nLastStatus
CControlBar* m_pLastStatus
LNK2001 : erreur de symboles externes non résolue
En appelant une fonction dans une bibliothèque ou une DLL statique prenant un type wchar_t (notez que BSTR et LPWSTR résolvent le type en wchar_t*), vous pouvez obtenir une erreur LNK2001 de symboles externes non résolue.
Cette erreur est provoquée par l'option du compilateur /Zc:wchar_t, qui est activée par défaut dans les nouveaux projets MFC. Cette option force le compilateur à traiter wchar_t comme un type natif. Avant Visual C++ .NET, wchar_t était traité comme un type unsigned short.
Si le projet principal et la bibliothèque n'utilisent pas le même paramètre pour /Zc:wchar_t, cela provoque une incohérence des signatures de fonction. Pour éviter ce problème, régénérez la bibliothèque à l'aide de l'option du compilateur /Zc:wchar_t ou désactivez-la dans le projet principal à l'aide du paramètre Traitement de wchar_t en tant que type intégré dans la page de propriétés Langue de la boîte de dialogue Pages de propriétés.
Les expressions booléennes sont maintenant de type bool et non BOOL
Prenons la classe suivante :
class CMyClass : public CObject
{
BOOL bFlag;
void Serialize (CArchive& ar))
{
if (ar.IsStoring())
ar << (bFlag != FALSE); // breaking change
else
ar >> bFlag;
}
};
Avant Visual C++ .NET, l'expression bFlag != FALSE était évaluée comme BOOL et quatre octets étaient écrits ; dans Visual C++ .NET, elle est évaluée comme bool et un octet est écrit. Cela signifie que les programmes compilés avec des versions différentes du compilateur peuvent produire des fichiers de données mutuellement incompatibles.
Pour éviter ce problème, effectuez un cast de l'expression en **BOOL **:
ar << (BOOL)(bFlag != FALSE);
CColorPropPage et CFontPropPage ont été supprimés
Dans les versions précédentes de MFC, un contrôle ActiveX affichait des pages de propriétés pour les propriétés de couleur ou de police en spécifiant respectivement l'identificateur global unique (GUID, Global Unique ID) CLSID_CColorPropPage ou CLSID_CFontPropPage. Ces GUID pointaient vers les classes CColorPropPage et CFontPropPage qui ne sont plus implémentées. Utilisez plutôt les GUID CLSID_StockColorPage et CLSID_StockFontPage. Ceux-ci étant implémentés par msstkprp.dll, vous devez redistribuer cette DLL avec votre application.
Modifications apportées à ON_MESSAGE
Le paramètre de fonction contenu dans la macro ON_MESSAGE doit correspondre au type afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM).
Modifications apportées aux modèles OLE DB
Pour plus d'informations sur les modifications apportées aux modèles OLE DB, consultez l'article de la Base de connaissances « INFO: Porting Issues with Visual Studio .NET OLE DB Provider Template Classes » (Q321743). Vous trouverez les articles de la Base de connaissances sur le CD-ROM de MSDN Library ou à l'adresse https://www.microsoft.com/france/support/.
Classes et modèles du consommateur OLE DB
En règle générale, la classe d'accesseur doit implémenter des membres supplémentaires. Cela est uniquement nécessaire si vous implémentez votre propre classe d'accesseur manuellement. Si votre classe d'accesseur est dérivée de CAccessor, il n'est pas nécessaire de le faire.
Ancien comportement |
Nouveau comportement |
---|---|
CRowset est une classe. |
CRowset est un modèle de classe qui prend un paramètre, TAccessor, une classe d'accesseur. |
CBulkRowset est une classe. |
CBulkRowset est un modèle de classe. |
La classe de base de CArrayRowset était un paramètre de modèle (sa valeur par défaut était CRowset). |
CArrayRowset est toujours dérivé de CBulkRowset. |
CDynamicAccessor::GetColumnInfo prenait trois paramètres. |
CDynamicAccessor::GetColumnInfo présente une nouvelle forme qui prend un paramètre supplémentaire, ppStringsBuffer. L'utilisation de ce paramètre élimine une fuite de mémoire. L'ancienne méthode est désapprouvée. |
Rowset, deuxième paramètre du modèle CAccessorRowset, est une classe rowset. |
TRowset, deuxième paramètre du modèle CAccessorRowset, est un modèle de classe rowset. |
Rowset, deuxième paramètre du modèle CTable, est une classe rowset. |
TRowset, deuxième paramètre du modèle CTable, est un modèle de classe rowset. |
Rowset, deuxième paramètre du modèle CCommand, est une classe rowset. |
TRowset, deuxième paramètre du modèle CCommand, est un modèle de classe rowset. |
Macro DEFINE_COMMAND |
La macro DEFINE_COMMAND est désapprouvée. Utilisez plutôt DEFINE_COMMAND_EX. |
Classes et modèles du fournisseur OLE DB :
L'implémentation interne de nombreuses interfaces et méthodes a changé depuis Visual C++ 6.0. Cette modification pourrait entraîner des problèmes de compatibilité selon que votre application substitue ces méthodes.
Ancien comportement |
Nouveau comportement |
---|---|
L'implémentation de jeu de lignes/accesseur utilisait les classes CSimpleMap/CSimpleArray. Les classes de collection fournies par l'utilisateur devaient être compatibles avec CSimpleMap/CSimpleArray. |
L'implémentation de jeu de lignes/accesseur utilise les classes CAtlMap/CAtlArray. Les classes de collection fournies par l'utilisateur devaient être compatibles avec CAtlMap/CAtlArray. En outre, un code qui appelle des méthodes de ces classes de collection doit être révisé en raison de différences significatives entre les classes CAtl* et CSimple* (paramètres, valeurs de retour, etc.) pouvant provoquer des erreurs d'exécution. |
ICommandImpl est dérivée de ICommand. |
ICommandImpl est un modèle qui est dérivé de l'argument CommandBase du modèle (la valeur par défaut est ICommand). |
ICommandTextImpl dérivé de ICommandImpl<ICommandImpl<T>. |
ICommandTextImpl est dérivé de ICommandImpl<ICommandImpl<T, ICommandText>. Notez qu'ici ICommandImpl est dérivé de ICommandText (et non de la valeur par défaut ICommand). |