Share via


Cambios en ATL y MFC: ATL 7.0 y MFC 7.0

Actualización: noviembre 2007

Nota   Algunas de las funciones mencionadas en este tema pueden no estar ya incorporadas en la versión actual de Visual C++.

Se han incorporado numerosas mejoras en las bibliotecas ATL y MFC desde Visual C++ 6.0. Algunos de estos cambios pueden interrumpir el código existente.

Incompatibilidades de DLL

Los archivos DLL de ATL y MFC que se distribuyen formando parte de Visual C++ .NET 2002 se han renombrado como ATL70.dll y MFC70.dll, respectivamente.

Las clases de ATL y MFC de Visual C++ .NET no tienen compatibilidad binaria con las mismas clases que en versiones anteriores y, por lo tanto, cualquier código fuente generado con mfc42.dll debe volver a generarse con Visual Studio .NET. Cualquier archivo DLL o LIB utilizado por las aplicaciones del programador también debe volver a generase con Visual Studio .NET.

Por ejemplo, una biblioteca que contiene una función exportada, que toma a CString como un parámetro que se ha generado con Visual C++ 6.0, da como resultado una referencia externa sin resolver durante la vinculación con un proyecto de Visual C++ .NET.

Clases de módulo ATL

ATL 3.0 suministraba la clase CComModule. En ATL 7.0, la funcionalidad que antes proporcionaba CComModule la controlan ahora varias clases nuevas. Vea Clases de módulo ATL para obtener más información.

Conversiones de cadenas

En las versiones de ATL hasta ATL 3.0, incluida, las conversiones de cadenas en Visual C++ 6.0 por medio de las macros de atlconv.h siempre se llevaban a cabo utilizando la página de códigos ANSI del sistema (CP_ACP). A partir de ATL 7.0 en Visual C++ .NET, las conversiones de cadenas se realizan utilizando la página de códigos ANSI predeterminada del subproceso actual, salvo que esté definida _CONVERSION_DONT_USE_THREAD_LOCALE, en cuyo caso se utiliza, igual que antes, la página de códigos ANSI del sistema.

Debe tenerse en cuenta que las clases de conversión de cadenas, como CW2AEX, permiten pasar a sus constructores una página de códigos que se utilizan para la conversión. Si no se especifica una página de códigos, las clases utilizan la misma que las macros.

Para obtener información más detallada, vea ATL and MFC String Conversion Macros.

CException es ahora una clase base abstracta

CException es la clase base para todas las excepciones de la biblioteca MFC (Microsoft Foundation Class). Puesto que CException es ahora una clase base abstracta, no es posible crear objetos CException directamente; deberá crear objetos de clases derivadas. Si crea un objeto directamente, recibirá un error. Para obtener más información, vea CException.

Convertir de BSTR a CString

En Visual C++ 6.0, el código siguiente era aceptable:

BSTR bstr = SysAllocString(L"Hello");
CString str = bstr;
SysFreeString(bstr);

En los proyectos nuevos de Visual C++ .NET, esto causa el siguiente error en las generaciones ANSI:

error C2440: 'initializing' : cannot convert from 'BSTR' to 
'ATL::CStringT<BaseType,StringTraits>'

Ahora existen versiones UNICODE y ANSI de CString (CStringW y CStringA). Para señalizar cualquier sobrecarga innecesaria causada por las conversiones implícitas, los constructores que aceptan el tipo inverso (por ejemplo, CStringA con un argumento UNICODE o CStringW con un argumento ANSI) ahora se etiquetan como explícitos mediante la siguiente entrada en stdafx.h:

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS

Para solucionar este error, realice una de las acciones siguientes:

  • Use CStringW para evitar la conversión:

    BSTR bstr = SysAllocString(L"Hello");
    CStringW str = bstr;
    SysFreeString(bstr);
    
  • Llame al constructor de manera explícita :

    BSTR bstr = SysAllocString(L"Hello");
    CString str = CString(bstr);
    SysFreeString(bstr);
    
  • Elimine la línea #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS de stdafx.h.

Cambios en CTime

CTime Class utiliza el tipo de datos __time64_t subyacente. En MFC 6.0, CTime utilizaba el tipo de datos time_t, que entonces era de tipo de 32 bits. La razón para este cambio es admitir instantes posteriores a las 3:14:07 del 19 de enero de 2038.

Cambios en CComEnumImpl::Skip

El método CComEnumImpl::Skip de las versiones anteriores a la ATL 7.0 no devolvía el código de error correcto para un valor de entrada 0; además, trataba los valores de entrada elevados de una forma no coherente. Estos comportamientos se han corregido en ATL 7.0.

Aserciones CWnd::DestroyWindow

Cuando se mostraba una información sobre herramientas en CWnd::DestroyWindow, se producía un error de aserción. Como consecuencia, en MFC 7.0, se han movido las siguientes variables miembro de AFX_THREAD_STATE a AFX_MODULE_THREAD_STATE:

  • CToolTipCtrl* m_pToolTip

  • CWnd* m_pLastHit

  • int m_nLastHit

  • TOOLINFO m_lastInfo

  • int m_nLastStatus

  • CControlBar* m_pLastStatus

Error de símbolo externo sin resolver LNK2001

Cuando se llama a una función en una biblioteca estática o en un archivo DLL estático que toma un tipo wchar_t (a tener en cuenta que BSTR y LPWSTR se resuelven en wchar_t*), puede obtenerse un error de símbolo externo sin resolver LNK2001.

Este error está causado por la opción de compilación /Zc:wchar_t, que de forma predeterminada está activada en los proyectos nuevos de MFC. Con esta opción, el compilador trata a wchar_t como un tipo nativo. Antes de Visual C++ .NET, a wchar_t se le trataba como un unsigned short.

Si el proyecto y la biblioteca principales no utilizan la misma configuración para /Zc:wchar_t, se producirá una falta de coincidencia de las firmas de función. Para evitar este problema, vuelva a generar la biblioteca con la opción de compilador /Zc:wchar_t o desactive dicha opción en el proyecto principal, mediante la configuración Tratar wchar_t como tipo integrado de la página de propiedades Lenguaje en el cuadro de diálogo Páginas de propiedades.

Las expresiones booleanas son ahora de tipo bool, no BOOL

Considere la siguiente clase:

class CMyClass : public CObject
{
   BOOL bFlag;

   void Serialize (CArchive& ar))
   {
      if (ar.IsStoring())
         ar << (bFlag != FALSE); // breaking change
      else
         ar >> bFlag;
   }
};

Antes de Visual C++ .NET, la expresión bFlag != FALSE se evaluaba como un tipo BOOL y se escribían cuatro bytes; en Visual C++ .NET, se evalúa como un tipo bool y sólo se escribe un byte. Esto significa que los programas compilados con diferentes versiones del compilador pueden producir archivos de datos incompatibles entre sí.

Para evitar este problema, convierta la expresión a BOOL:

ar << (BOOL)(bFlag != FALSE);

CColorPropPage y CFontPropPage se han eliminado

En versiones anteriores de MFC, un control ActiveX mostraba páginas de propiedades para el color o la fuente mediante el GUID CLSID_CColorPropPage o CLSID_CFontPropPage, respectivamente. Estos GUID apuntaban a las clases CColorPropPage y CFontPropPage, las cuales ya no se implementan. En su lugar, utilice los GUID CLSID_StockColorPage y CLSID_StockFontPage. Éstos se implementan en msstkprp.dll, por lo que deberá distribuir esa DLL con la aplicación.

Cambios en ON_MESSAGE

El parámetro de función en la macro ON_MESSAGE debe coincidir con el tipo afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM).

Cambios en las plantillas OLE DB

Encontrará más información sobre cambios en las plantillas OLE DB en el artículo de Knowledge Base "INFO: Porting Issues with Visual Studio .NET OLE DB Provider Template Classes" (Q321743). Encontrará artículos de Knowledge Base en el CD-ROM de MSDN Library o en la dirección https://support.microsoft.com/support.

Plantillas y clases de consumidor OLE DB:

Como nota general, la clase descriptora de acceso debe implementar los miembros adicionales. Esto sólo es necesario si el usuario implementa su propia clase descriptora de acceso manualmente. Si la clase descriptora de acceso se deriva de CAccessor, no necesita hacerlo.

Comportamiento anterior

Nuevo comportamiento

CRowset es una clase.

CRowset es una plantilla de clase que recibe un parámetro, TAccessor, una clase descriptora de acceso.

CBulkRowset es una clase.

CBulkRowset es una plantilla de clase.

La clase base para CArrayRowset era un parámetro de plantilla (el valor predeterminado era CRowset).

CArrayRowset siempre se deriva de CBulkRowset.

CDynamicAccessor::GetColumnInfo tomaba tres parámetros.

CDynamicAccessor::GetColumnInfo presenta una nueva forma que recibe un parámetro adicional, ppStringsBuffer. El uso de este parámetro elimina una pérdida de memoria. El método antiguo queda desaconsejado.

Rowset, el segundo parámetro de la plantilla CAccessorRowset, es una clase de conjunto de filas.

TRowset, el segundo parámetro de la plantilla CAccessorRowset, es una plantilla de clase de conjunto de filas.

Rowset, el segundo parámetro de la plantilla CTable, es una clase de conjunto de filas.

TRowset, el segundo parámetro de la plantilla CTable, es una plantilla de clase de conjunto de filas.

Rowset, el segundo parámetro de la plantilla CCommand, es una clase de conjunto de filas.

TRowset, el segundo parámetro de la plantilla CCommand, es una plantilla de clase de conjunto de filas.

DEFINE_COMMAND es una macro.

DEFINE_COMMAND es una macro en desuso. Utilice DEFINE_COMMAND_EX en su lugar.

Plantillas y clases de proveedor OLE DB:

La implementación interna de muchas interfaces y métodos ha cambiado desde Visual C++ 6.0. Esto puede producir problemas de compatibilidad en el caso de que la aplicación reemplace estos métodos.

Comportamiento anterior

Nuevo comportamiento

La implementación de conjunto de filas/descriptor de acceso utilizaba clases CSimpleMap/CSimpleArray. Las clases de colecciones suministradas por el usuario debían ser compatibles con CSimpleMap/CSimpleArray.

La implementación de conjunto de filas/descriptor de acceso utiliza clases CAtlMap/CAtlArray. Las clases de colecciones suministradas por el usuario tienen que ser compatibles con CAtlMap/CAtlArray. Además, el código que llama a métodos de estas clases de colecciones debería revisarse, ya que existen diferencias importantes entre las clases CAtl* y las CSimple* (parámetros, valores devueltos, etc.) que pueden producir errores en tiempo de ejecución.

ICommandImpl se derivaba de ICommand.

ICommandImpl es una plantilla que se deriva del argumento CommandBase de la plantilla (el valor predeterminado es ICommand).

ICommandTextImpl se deriva de ICommandImpl<ICommandImpl<T>.

ICommandTextImpl se deriva de ICommandImpl<ICommandImpl<T, ICommandText>. Observe que aquí ICommandImpl se deriva de ICommandText (no del valor predeterminado ICommand).

Vea también

Referencia

Cambios en ATL y MFC