Modifiche ATL e MFC: ATL 7.0 e MFC 7.0
Aggiornamento: novembre 2007
Nota È possibile che alcune funzionalità presentate in questo argomento non siano più presenti nella versione corrente di Visual C++.
Rispetto al momento del rilascio di Visual C++ 6.0, alle librerie ATL e MFC sono stati apportati numerosi miglioramenti. Alcune di queste modifiche possono creare interruzioni nel codice esistente.
Incompatibilità delle DLL
I file DLL ATL e MFC forniti con Visual C++ .NET 2002 sono stati rinominati rispettivamente ATL70.dll e MFC70.dll.
Le classi ATL e MFC di Visual C++ .NET non dispongono di un formato binario compatibile con quello delle stesse classi delle versioni precedenti. Il codice sorgente generato mediante mfc42.dll deve quindi essere rigenerato con Visual Studio .NET, così come tutti i file DLL o LIB utilizzati dall'applicazione.
Una libreria contenente una funzione esportata che accetta CString come parametro generata mediante Visual C++ 6.0, ad esempio, genererà un riferimento esterno non risolto durante il collegamento con un progetto Visual C++ .NET.
Classi modulo ATL
In ATL 3.0 veniva fornita la classe CComModule. In ATL 7.0 le funzionalità precedentemente fornite da CComModule vengono gestite da diverse nuove classi. Per ulteriori informazioni, vedere Classi modulo ATL.
Conversioni di stringhe
Nelle versioni di ATL fino alla 3.0 di Visual C++ 6.0 le conversioni di stringhe basate sulle macro di atlconv.h venivano sempre eseguite utilizzando la tabella codici ANSI del sistema (CP_ACP). A partire da ATL 7.0 di Visual C++ .NET le conversioni di stringhe vengono eseguite mediante la tabella codici ANSI predefinita del thread corrente, a meno che non venga definito _CONVERSION_DONT_USE_THREAD_LOCALE. In questo caso, viene utilizzata la tabella codici ANSI del sistema come nelle versioni precedenti.
Le classi per la conversione di stringhe, ad esempio CW2AEX, consentono di passare ai costruttori delle stringhe una tabella codici da utilizzare per la conversione. Se non viene specificata una tabella codici, le classi utilizzano la stessa tabella codici delle macro.
Per ulteriori informazioni, vedere Macro per la conversione di stringhe ATL e MFC.
Classe base astratta CException
CException è la classe base per tutte le eccezioni nella libreria MFC. Poiché CException è ora una classe base astratta, non è possibile creare direttamente oggetti CException, ma è necessario creare oggetti di classi derivate. In caso contrario, viene generato un errore. Per ulteriori informazioni, vedere CException.
Conversione da BSTR a CString
In Visual C++ 6.0 era possibile utilizzare il seguente codice:
BSTR bstr = SysAllocString(L"Hello");
CString str = bstr;
SysFreeString(bstr);
Nei nuovi progetti Visual C++ .NET questo codice genera il seguente errore nelle build ANSI:
error C2440: 'initializing' : cannot convert from 'BSTR' to
'ATL::CStringT<BaseType,StringTraits>'
Sono adesso disponibili versioni UNICODE e ANSI di CString, ovvero CStringW e CStringA. Per contrassegnare ogni overhead non necessario causato da conversioni implicite, i costruttori che accettano il tipo inverso, ad esempio CStringA che accetta un argomento UNICODE o CStringW che accetta un argomento ANSI, vengono definiti come espliciti mediante la seguente voce in stdafx.h:
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
Per risolvere l'errore, effettuare una delle seguenti operazioni:
Utilizzare CStringW per evitare la conversione:
BSTR bstr = SysAllocString(L"Hello"); CStringW str = bstr; SysFreeString(bstr);
Chiamare il costruttore in modo esplicito:
BSTR bstr = SysAllocString(L"Hello"); CString str = CString(bstr); SysFreeString(bstr);
Rimuovere la riga #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS da stdafx.h.
Modifiche a CTime
La CTime Class utilizza il tipo di dati sottostante __time64_t. In MFC 6.0 CTime utilizzava time_t, un tipo di dati a 32 bit. Questa modifica è stata apportata per includere il supporto per le ore successive alle 3.14.07 del 19 gennaio 2038.
Modifiche a CComEnumImpl::Skip
Nelle versioni precedenti ad ATL 7.0 il metodo CComEnumImpl::Skip non restituiva il codice di errore corretto per il valore di input 0 e gestiva in modo incoerente i valori di input di grandi dimensioni. In ATL 7.0 questi problemi sono stati risolti.
Asserzioni CWnd::DestroyWindow
Quando in CWnd::DestroyWindow veniva visualizzata una descrizione comandi, si verificava un errore di asserzione. In MFC 7.0 le seguenti variabili membro sono quindi state spostate da AFX_THREAD_STATE ad AFX_MODULE_THREAD_STATE:
CToolTipCtrl* m_pToolTip
CWnd* m_pLastHit
int m_nLastHit
TOOLINFO m_lastInfo
int m_nLastStatus
CControlBar* m_pLastStatus
Errore di simbolo esterno non risolto LNK2001
Durante la chiamata a una funzione in una libreria statica o in una DLL che accetta un tipo wchar_t (BSTR e LPWSTR si risolvono in wchar_t*) può essere generato un errore di simbolo esterno non risolto LNK2001.
L'errore è causato dall'opzione /Zc:wchar_t del compilatore, che nei nuovi progetti MFC viene attivata per impostazione predefinita. In base a tale opzione il compilatore considera wchar_t come un tipo nativo. Nelle versioni precedenti a Visual C++ .NET wchar_t veniva considerato come un tipo unsigned short.
Se il progetto principale e la libreria non utilizzano la stessa impostazione di /Zc:wchar_t, si verificherà un errore di corrispondenza tra le firme delle funzioni. Per evitare il problema, rigenerare la libreria con l'opzione /Zc:wchar_t del compilatore oppure disattivare l'opzione nel progetto principale mediante l'impostazione Considera wchar_t come tipo incorporato nella pagina delle proprietà Linguaggio della finestra di dialogo Pagine delle proprietà.
Espressioni booleane di tipo bool anziché BOOL
Si prenda in considerazione la seguente classe:
class CMyClass : public CObject
{
BOOL bFlag;
void Serialize (CArchive& ar))
{
if (ar.IsStoring())
ar << (bFlag != FALSE); // breaking change
else
ar >> bFlag;
}
};
Nelle versioni precedenti a Visual C++ .NET l'espressione bFlag != FALSE restituiva il valore BOOL e venivano scritti quattro byte. In Visual C++ .NET viene invece restituito il valore bool e viene scritto un solo byte. È pertanto possibile che programmi compilati con versioni diverse del compilatore producano file di dati incompatibili gli uni con gli altri.
Per evitare il problema, eseguire il cast dell'espressione su BOOL:
ar << (BOOL)(bFlag != FALSE);
Rimozione di CColorPropPage e CFontPropPage
Nelle versioni precedenti di MFC un controllo ActiveX visualizzava le pagine delle proprietà relative al colore o al tipo di carattere specificando rispettivamente il GUID CLSID_CColorPropPage o CLSID_CFontPropPage. Questi GUID facevano riferimento alle classi CColorPropPage e CFontPropPage, non più implementate. Nella versione corrente è necessario utilizzare i GUID CLSID_StockColorPage e CLSID_StockFontPage, implementati da msstkprp.dll, ed è pertanto necessario ridistribuire questa DLL con l'applicazione.
Modifiche a ON_MESSAGE
Il parametro di funzione della macro ON_MESSAGE deve corrispondere al tipo afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM).
Modifiche ai modelli OLE DB
Per ulteriori informazioni sulle modifiche ai modelli OLE DB, vedere l'articolo Q321743 della Knowledge Base "INFO: Porting Issues with Visual Studio .NET OLE DB Provider Template Classes" disponibile nel CD della MSDN Library o all'indirizzo https://support.microsoft.com/?ln=IT.
Classi e modelli consumer OLE DB
In generale, la classe della funzione di accesso deve implementare i membri aggiuntivi. Si tratta di un'operazione necessaria solo se si implementa manualmente la classe della funzione di accesso. Se la classe della funzione di accesso deriva da CAccessor, questa operazione non è necessaria.
Comportamento precedente |
Nuovo comportamento |
---|---|
CRowset è una classe. |
CRowset è un modello di classe e accetta un parametro, TAccessor, che è una classe della funzione di accesso. |
CBulkRowset è una classe. |
CBulkRowset è un modello di classe. |
La classe base di CArrayRowset è un parametro di modello (il valore predefinito è CRowset). |
CArrayRowset deriva sempre da CBulkRowset. |
CDynamicAccessor::GetColumnInfo accetta tre parametri. |
CDynamicAccessor::GetColumnInfo dispone di un nuovo form che accetta un parametro aggiuntivo, ppStringsBuffer. L'utilizzo di questo parametro elimina una perdita di memoria. Il metodo precedente è obsoleto. |
Rowset, secondo parametro del modello CAccessorRowset, è una classe di rowset. |
TRowset, secondo parametro del modello CAccessorRowset, è un modello di classe di rowset. |
Rowset, secondo parametro del modello CTable, è una classe di rowset. |
TRowset, secondo parametro del modello CTable, è un modello di classe di rowset. |
Rowset, secondo parametro del modello CCommand, è una classe di rowset. |
TRowset, secondo parametro del modello CCommand, è un modello di classe di rowset. |
Macro DEFINE_COMMAND |
La macro DEFINE_COMMAND è obsoleta. Utilizzare DEFINE_COMMAND_EX. |
Classi e modelli provider OLE DB
Poiché l'implementazione interna di numerosi metodi e interfacce è stata modificata da Visual C++ 6.0, possono verificarsi problemi di compatibilità a seconda che l'applicazione esegua o meno l'override di questi metodi.
Comportamento precedente |
Nuovo comportamento |
---|---|
L'implementazione di rowset/funzioni di accesso utilizza le classi CSimpleMap/CSimpleArray. Le classi di insiemi fornite dall'utente devono essere compatibili con CSimpleMap/CSimpleArray. |
L'implementazione di rowset/funzioni di accesso utilizza le classi CAtlMap/CAtlArray. Le classi di insiemi fornite dall'utente devono essere compatibili con CAtlMap/CAtlArray. Inoltre, il codice che chiama i metodi di queste classi di insiemi deve essere riesaminato in quanto sono presenti notevoli differenze tra le classi CAtl* e CSimple* (parametri, valori restituiti e così via) che possono causare errori di runtime. |
ICommandImpl deriva da ICommand. |
ICommandImpl è un modello che deriva dall'argomento CommandBase del modello (il valore predefinito è ICommand). |
ICommandTextImpl deriva da ICommandImpl<ICommandImpl<T>. |
ICommandTextImpl deriva da ICommandImpl<ICommandImpl<T, ICommandText>. Si noti che ICommandImpl deriva da ICommandText, non dal valore predefinito ICommand. |