Cómo: Migrar a /clr

Actualización: noviembre 2007

Este tema trata sobre los problemas que surgen al compilar código nativo con /clr (vea /clr (Compilación de Common Language Runtime) para obtener más información). /clr permite a los módulos de Visual C++ invocar y ser invocados desde ensamblados .NET, conservando a su vez la compatibilidad con los módulos no administrados. Vea Ensamblados mixtos (nativos y administrados) y Interoperabilidad nativa y de .NET para obtener más información sobre las ventajas de compilar con /clr.

Problemas conocidos al compilar proyectos de biblioteca con /clr

Visual C++ 2005 contiene algunos problemas conocidos al generar proyectos de biblioteca con /clr:

  • Al compilar un proyecto de control ActiveX de MFC con /clr en el entorno de desarrollo, el sistema de generación intentará registrar el archivo .dll con regasm y no con regsvr32. Deberá registrar manualmente el control con regsvr32.

  • Al crear un proyecto ATL y habilitar a continuación /clr, los archivos .c generarán un error, porque éstos no se pueden compilar con /clr. Sin embargo, si cambia la configuración de archivo para compilar el archivo con /TP, se generarán errores de vinculador. La solución consiste en compilar los archivos .c de modo nativo (sin /clr).

  • El código puede consultar tipos en tiempo de ejecución con CRuntimeClass::FromName. Sin embargo, si un tipo está en un archivo .dll en MSIL (compilado con /clr), la llamada a CRuntimeClass::FromName puede sufrir un error si se realiza antes de que los constructores estáticos se ejecuten en el archivo .dll administrado (no apreciará este problema si la llamada a FromName se produce una vez ejecutado el código en el archivo .dll administrado). Para solucionar este problema, puede forzar la creación del constructor estático administrado definiendo una función en el archivo .dll administrado, exportándola e invocándola desde la aplicación MFC nativa. Por ejemplo:

    // Extention DLL Header file:
    __declspec( dllexport ) void EnsureManagedInitialization () {
       // managed code that won't be optimized away
       System::GC::KeepAlive(System::Int32::MaxValue);
    }
    

Compilar con Visual C++ 2005

Antes de utilizar /clr en cualquier módulo del proyecto, compile y vincule primero el proyecto nativo con Visual C++ 2005.

Los pasos siguientes, seguidos en orden, constituyen la forma más fácil de realizar una compilación con /clr. Es importante compilar y ejecutar el proyecto después de cada uno de estos pasos.

Versiones anteriores a Visual C++ 2003

Si se actualiza a Visual C++ 2005 desde una versión anterior a Visual C++ 2003, puede que aparezcan errores de compilador relacionados con el cumplimento de estándares de C++ mejorado de Visual C++ 2003. Vea Cambios importantes en el compilador de Visual C++ para obtener más información.

Actualizar desde Visual C++ 2003

Los proyectos generados anteriormente con Visual C++ 2003 también se deberían generar primero sin /clr, ya que Visual C++ 2005 ha aumentado la compatibilidad con ANSI/ISO y ha realizado algunos cambios importantes. Vea Cambios importantes en el compilador de Visual C++ para obtener más información. El cambio que probable requiera más atención son Security Enhancements in the CRT. Es muy probable que el código que utiliza el CRT genere advertencias de que está en desuso. Estas advertencias se pueden suprimir, pero es preferible migrar a las nuevas Security-Enhanced Versions of CRT Functions, ya que proporcionan mayor seguridad y pueden revelar problemas de seguridad del código.

Actualizar desde Extensiones administradas para C++

Los proyectos generados con Visual C++ .NET o Visual C++ 2003 que usaban Extensiones administradas para C++ necesitarán al menos un cambio de configuración, ya que estas extensiones ahora ya no se usan. Como resultado, el código escrito con Extensiones administradas para C++ no se compilará bajo /clr. En su lugar, se ha de utilizar /clr:oldSyntax.

Convertir código de C en código de C++

Aunque Visual C++ 2005 generará los archivos de C, es necesario convertirlos a C++ para una compilación /clr. El nombre de archivo real no tiene que cambiarse, puede utilizar /Tp (vea /Tc, /Tp, /TC, /TP (Especificar el tipo de archivo de código fuente).) Tenga en cuenta que, aunque se requieren archivos de código fuente de C++ para /clr, no es necesario refactorizar el código para utilizar paradigmas orientados a objetos.

Es muy probable que el código de C requiera cambios cuando se compile como un archivo de C++. Las reglas de seguridad de tipos de C++ son estrictas, por lo que las conversiones de tipos se deben realizar de forma explícita con conversiones de tipos. Por ejemplo, malloc devuelve un puntero nulo, pero se puede asignar a un puntero de cualquier tipo de C con una conversión de tipos:

int* a = malloc(sizeof(int));   // C code
int* b = (int*)malloc(sizeof(int));   // C++ equivalent

Los punteros a función también presentan una seguridad de tipos estricta en C++, por lo que el siguiente código de C requiere alguna modificación. En C++, es mejor crear un typedef que define el tipo de puntero a función y, a continuación, utilizar dicho tipo para convertir los punteros a función:

NewFunc1 = GetProcAddress( hLib, "Func1" );   // C code
typedef int(*MYPROC)(int);   // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );

C++ también requiere que se creen prototipos de las funciones o se definan totalmente para que se pueda hacer referencia a ellas o se puedan invocar.

Se debe cambiar el nombre de los identificadores utilizados en el código de C que resulten ser palabras clave en C++ (como virtual, new, delete, bool, true, false, etc.). Esto generalmente se puede hacer con operaciones simples de búsqueda y sustitución.

Finalmente, mientras que las llamadas COM de estilo C requieren el uso explícito de v-table y del puntero this, C++ no lo requiere:

COMObj1->lpVtbl->Method(COMObj, args);  // C code
COMObj2->Method(args);  // C++ equivalent

Redefinir la configuración del proyecto

Después de generar y ejecutar el proyecto en Visual C++ 2005, deberá crear nuevas configuraciones de proyecto para /clr en lugar de modificar las configuraciones predeterminadas. /clr es incompatible con algunas opciones de compilador, y la creación de configuraciones independientes permite generar el proyecto como nativo o administrado. Si se selecciona /clr en el cuadro de diálogo de páginas de propiedades, los parámetros de configuración del proyecto que no sean compatibles con /clr se desactivarán (y las opciones desactivadas no se restauran automáticamente si /clr se deshabilita posteriormente).

Crear nuevas configuraciones de proyecto

Puede utilizar la opción Copiar configuración de en el Nueva configuración del proyecto (Cuadro de diálogo) para crear una configuración de proyecto basada en los parámetros del proyecto existentes. Haga esto una vez para la configuración de depuración y una vez para la configuración de lanzamiento. Los cambios subsiguientes sólo se podrán aplicar a las configuraciones específicas de /clr, dejando las configuraciones de proyecto originales intactas.

Los proyectos que usen reglas de generación personalizadas puede que requieran más atención.

Este paso tiene implicaciones diferentes para proyectos que utilizan archivos make. En este caso se puede configurar un destino-versión independiente, o se puede crear una compilación específica de la versión de /clr a partir de una copia del original.

Cambiar la configuración del proyecto

/clr se puede seleccionar en el entorno de desarrollo siguiendo las instrucciones de /clr (Compilación de Common Language Runtime). Como se mencionó previamente, este paso deshabilitará automáticamente los parámetros de configuración del proyecto que entren en conflicto.

Nota:

Si se actualiza un proyecto de biblioteca administrada o de servicio Web desde Visual C++ 2003 a Visual C++ 2005, la opción del compilador /Zl se agregará a la página de propiedades Línea de comandos. Esto produce el error LNK2001. Quite /Zl de la página de propiedades Línea de comandos para resolverlo. Para obtener más información, vea /Zl (Omitir nombres de biblioteca predeterminada) y Cómo: Abrir páginas de propiedades del proyecto. O bien, agregue .lib y msvcmrt.lib a la propiedad Dependencias adicionales del vinculador.

Para los proyectos generados con archivos make, las opciones del compilador incompatibles se deben deshabilitar manualmente una vez agregado /clr. Vea /Restricciones de /clr para obtener información sobre las opciones del compilador que no son compatibles con /clr.

Encabezados precompilados

/clr admite los encabezados precompilados. No obstante, si sólo compila algunos de los archivos CPP con /clr (compilando el resto como archivos nativos) se deberán realizar algunos cambios ya que los encabezados precompilados generados con /clr no son compatibles con los generados sin /clr. Esta incompatibilidad se debe al hecho de que /clr genera y requiere metadatos. Por lo tanto, los módulos compilados con /clr no pueden usar encabezados precompilados que no incluyan metadatos, los módulos no compilados con /clr no pueden usar archivos de encabezados precompilados que contengan metadatos.

La manera más fácil de compilar un proyecto en el que algunos módulos se compilan con /clr es deshabilitar completamente los encabezados precompilados. (En cuadro de diálogo Páginas de propiedades del proyecto, abra el nodo C/C++ y seleccione Encabezados precompilados. A continuación, cambie la propiedad Crear o utilizar encabezado precompilado a "No utilizar encabezados precompilados").

Sin embargo, particularmente para los proyectos grandes, los encabezados precompilados proporcionan una velocidad de compilación mucho mejor, de modo que no es deseable deshabilitar esta característica. En este caso, es mejor configurar los archivos /clr y no /clr para utilizar encabezados precompilados independientes. Esto se puede realizar en un solo paso mediante la selección múltiple de módulos que se van a compilar con /clr utilizando el Explorador de soluciones, haciendo clic con el botón secundario en el grupo y seleccionando Propiedades. A continuación, cambie las propiedades Crear o utilizar encabezado precompilado a través del archivo y Archivo de encabezado precompilado para utilizar un nombre de archivo de encabezado y un archivo PCH diferentes respectivamente.

Corregir errores

Compilar con /clr puede producir errores de compilador, vinculador o tiempo de ejecución. En esta sección se describen los problemas más comunes.

Combinación de metadatos

Versiones distintas de los tipos de datos pueden hacer que el vinculador produzca un error porque los metadatos generados para los dos tipos no coinciden. (Esto ocurre normalmente cuando los miembros de un tipo se definen condicionalmente, pero las condiciones no son las mismas para todos los archivos CPP que usan dicho tipo). En este caso el vinculador produce un error, informando sólo del nombre de símbolo y del nombre del segundo archivo OBJ en el que se definió el tipo. A menudo resulta útil invertir el orden en que se envían los archivos OBJ al vinculador para encontrar la ubicación de la otra versión del tipo de datos.

Interbloqueo del bloqueo del cargador

En Visual C++ .NET y Visual C++ 2003, la inicialización bajo /clr era susceptible al interbloqueo no determinista. Este problema se conoce como el "interbloqueo del bloqueo del cargador". En Visual C++ 2005, este interbloqueo es más fácil de evitar, se detecta y se notifica en tiempo de ejecución y ya no es no determinista. Encontrar el problema del bloqueo del cargador todavía es posible, pero ahora es mucho más fácil de evitar y corregir. Vea Inicialización de ensamblados mixtos para obtener información detallada, orientación y soluciones.

Exportaciones de datos

La exportación de datos DLL es propensa a sufrir errores, y no se recomienda. Esto se debe a que no se garantiza que se inicialice la sección de datos de un archivo DLL hasta que se haya ejecutado alguna parte administrada del archivo DLL. Haga referencia a los metadatos con The #using Directive.

Visibilidad de tipos

Los tipos nativos ahora son privados de forma predeterminada. En Visual C++ .NET 2002 y Visual C++ 2003, los tipos nativos eran públicos de forma predeterminada. Esto puede producir un tipo nativo que no sea visible fuera del archivo DLL. Resuelva este error agregando public a estos tipos. Vea Type and Member Visibility para obtener más información.

Problemas de punto flotante y alineación

__controlfp no se admite en Common Language Runtime (vea _control87, _controlfp, __control87_2 para obtener más información). El CLR tampoco respetará align (C++).

Inicialización COM

Common Language Runtime inicializa COM automáticamente cuando se inicializa un módulo (cuando se inicializa COM automáticamente, se hace para MTA). Como resultado, la inicialización explícita de COM produce códigos devueltos que indican que COM ya se ha inicializado. El intento de inicializar COM explícitamente con un modelo de subprocesamiento cuando CLR ya ha inicializado COM en otro modelo de subprocesamiento puede hacer que la aplicación no funcione correctamente.

La inicialización COM y el código de error asociado deben permitir el caso en el que COM ya se haya inicializado, o las llamadas a CoInitialize y CoUninitialize generalmente se pueden quitar simplemente. Common Language Runtime inicia COM de forma predeterminada como MTA; utilice /CLRTHREADATTRIBUTE (Establecer el atributo de subproceso de CLR) para modificar esto.

Problemas de rendimiento

Puede que disminuya el rendimiento si los métodos de C++ nativos generados para MSIL se llaman indirectamente (llamadas a funciones virtuales o uso de punteros a función). Para obtener más información sobre esto, vea Doble thunk (C++).

Al trasladar de nativo a MSIL, observará un aumento en el tamaño de su espacio de trabajo. Esto se debe a que Common Language Runtime proporciona muchas características para garantizar que los programas se ejecutan correctamente. Si la aplicación /clr no se está ejecutando correctamente, puede habilitar C4793 (desactivado de forma predeterminada), vea Advertencia del compilador (niveles 1 y 3) C4793 para obtener más información.

El programa se bloquea o se cierra

En algunos casos, el CLR puede que se cierre antes de que el código administrado termine de ejecutarse. El uso de std::set_terminate y SIGTERM puede producir esto. Para obtener más información, vea signal Constants y set_terminate (<exception>).

Utilizar las nuevas características de Visual C++

Después de que la aplicación, se compile, vincule y ejecute, puede empezar a utilizar las características .NET en cualquier módulo compilado con /clr. Para obtener más información, vea Language Features for Targeting the CLR.

Si utilizó Extensiones administradas para C++, puede convertir el código para usar la nueva sintaxis. Para obtener un resumen de las diferencias sintácticas, vea la Extensiones administradas para la lista de comprobación de actualizaciones de sintaxis de C++. Para obtener detalles sobre cómo convertir Extensiones administradas para C++, vea Manual de migraciones C++/CLI.

Para obtener información sobre la programación .NET en Visual C++ vea:

Vea también

Conceptos

Ensamblados mixtos (nativos y administrados)