TN033: Versión de la DLL de MFC

Esta nota describe cómo puede utilizar el MFCxx.DLL y MFCxxD.DLL (donde x es el número de versión MFC) compartir bibliotecas de vínculos dinámicos con las aplicaciones MFC y las DLL de extensión. Para obtener más información acerca de los archivos DLL estándar, consulte Utilizar MFC como parte de un archivo DLL.

Esta nota técnica abarca tres aspectos de la DLL. Las dos últimas son para los usuarios más avanzados:

Si estás interesado en la creación de un archivo DLL mediante MFC que se puede utilizar con aplicaciones no MFC (esto se denomina un archivo DLL estándar), consulte 11 de nota técnica.

Visión general de MFCxx.DLL apoyo: terminología y archivos

Archivo DLL estándar: utilizar un archivo DLL estándar para crear una DLL independiente utilizando algunas de las clases MFC. Interfaces a través de la frontera de App/DLL son interfaces de "C" y la aplicación cliente no tiene que ser una aplicación MFC.

Se trata de la versión de soporte DLL compatible con MFC 1.0. Se describe en 11 de nota técnica y la muestra de conceptos avanzados de MFC DLLTRACE.

&Notanbsp;  Visual C++ versión 4.0, el término USRDLL es obsoleto y ha sido sustituido por un archivo DLL estándar vinculado estáticamente a MFC. También puede crear un archivo DLL estándar que vincula dinámicamente a MFC.

MFC 3.0 (o superior) compatible con archivos DLL estándar con la nueva funcionalidad incluyendo las clases OLE y base de datos.

AFXDLL: esto se conoce también como la versión de las bibliotecas MFC compartida. Este es el nuevo soporte DLL en MFC 2.0. La propia biblioteca MFC es un número de archivos DLL (descrito a continuación) y una aplicación cliente o DLL vincula dinámicamente los archivos DLL que requiere. Son interfaces entre el límite de aplicación/DLL C + / interfaces de clase MFC. La aplicación cliente debe ser una aplicación MFC. Esto soporta todas las funcionalidades de MFC 3.0 (excption: UNICODE no es compatible con las clases de base de datos).

&Notanbsp;  Como de la versión 4.0 de Visual C++, este tipo de archivo DLL se conoce como una "extensión DLL".

Esta nota usará MFCxx.DLL para referirse a todo el conjunto DLL de MFC, que incluye:

&Notanbsp;  El MFCSxx [U] [D].LIB librerías son usadas en junto con la MFC comparte archivos DLL. Estas bibliotecas contienen código que debe ser estáticamente enlazada a la aplicación o DLL.

Un enlaces de aplicación a las bibliotecas de importación correspondiente:

Un "DLL de extensión de MFC" es una DLL que se basa en MFCxx.DLL (o el otro MFC comparte archivos DLL). Aquí se inicia la arquitectura de componentes MFC. Si derivar una clase de utilidad de una clase MFC o construir otro toolkit como MFC, puede colocarlo en una DLL. Que DLL utiliza MFCxx.DLL, igual que la aplicación cliente final. Esto permite hoja reutilizable clases, clases base reutilizables y clases reutilizables ver/documento.

&Notanbsp;  No es necesario vincular con las bibliotecas de MFCOxx [U] D, D MFCDxx [U] o MFCNxx [U] D depurar a menos que la aplicación utiliza la MFC/OLE, base de datos o redes clases respectivamente.

Pros y contras

¿Por qué debería utilizar la versión compartida de MFC?

¿Por qué usted no debe utilizar la versión compartida de MFC:

Cómo escribir un archivo DLL de extensión MFC

Un archivo DLL de extensión de MFC es un archivo DLL que contiene clases y funciones escritas para embellecer la funcionalidad de las clases MFC. El apoyo de depuración OLE y base de datos de archivos DLL (MFCOxxD.DLL y MFCDxxD.DLL) son ejemplos de las DLL de extensión MFC que utilizan MFCxxD.DLL. Un archivo DLL de extensión de MFC utiliza las DLL de MFC compartida de la misma manera que una aplicación utiliza, con algunas consideraciones adicionales:

Estas consideraciones se describen con más detalle a continuación. Además, debe consultar a la muestra de conceptos avanzados de MFC DLLHUSK puesto que ilustra

La aplicación cliente y cualquier DLL de extensión deben utilizar la misma versión de MFCxx.DLL. Debe seguir la Convención de la DLL de MFC y proporcionar tanto una depuración y minoristas (/ lanzar) versión de la DLL de extensión. Esto permite que los programas de cliente para crear versiones de depuración y venta de sus aplicaciones y vincularlos con la depuración adecuada o la versión comercial de todas las DLL.

&Notanbsp;  Debido a problema de mutilación y exportación de nombre de C++, la lista de exportación de un archivo DLL de extensión puede ser diferente entre las versiones de depuración y venta por menor de la misma DLL y archivos DLL para diferentes plataformas. La minorista MFCxx.DLL ha aproximadamente 2000 exportado puntos de entrada; la depuración MFCxxD.DLL ha unos 3000 exportado puntos de entrada.

Nota rápida sobre la gestión de memoria

La sección titulada "Gestión de memoria," cerca del final de esta nota técnica, describe la implementación de la MFCxx.DLL con la versión compartida de MFC. Aquí se describe la información que necesita saber para aplicar sólo una DLL de extensión.

MFCxx.DLL y todas las DLL de extensión cargadas en espacio de direcciones de la aplicación de un cliente utilizará el mismo asignador de memoria, carga de recursos y otros Estados "globales" de MFC como si estuvieran en la misma aplicación. Esto es significativo porque el archivo DLL MFC bibliotecas y archivos DLL estándar que se vinculan estáticamente a MFC hacer exactamente lo contrario y tiene cada DLL asignación fuera de su propio bloque de memoria.

Si un archivo DLL de extensión asigna memoria, esa memoria libremente puede combinar con cualquier otro objeto asignados a la aplicación. También, si se bloquea una aplicación que utiliza las bibliotecas compartidas de MFC, la protección del sistema operativo mantendrá la integridad de cualquier otra aplicación MFC compartir el archivo DLL.

Asimismo otros Estados MFC "globales", como el actual archivo ejecutable para cargar los recursos, también son compartidos entre la aplicación cliente y todas las DLL de extensión MFC como MFCxx.DLL propio.

Creación de un archivo DLL de extensión

Puede utilizar el Asistente para aplicaciones para crear un proyecto DLL de extensión MFC, y generará automáticamente el compilador apropiado y opciones del vinculador. Fue también generar una función DllMain que puede modificar.

Si convierte un proyecto existente a un archivo DLL de extensión MFC, comenzar con las normas estándar para la creación de una aplicación utilizando la versión compartida de MFC y, a continuación, haga lo siguiente:

Cambiar los archivos de encabezado

El objetivo de una extensión DLL suele exportar cierta funcionalidad común a una o más aplicaciones que pueden utilizar esa funcionalidad. Esto reduce a exportar clases y funciones globales que están disponibles para las aplicaciones de cliente.

Para ello debe asegurarse de que cada una de las funciones miembro se marca como importar o exportar según corresponda. Esto requiere declaraciones especiales: dllexport y __declspec (dllimport). Cuando las clases son utilizadas por las aplicaciones cliente, desea que declararse como __declspec (dllimport). Cuando se construye la extensión del archivo DLL, debe declararse como dllexport. Además, las funciones deben ser efectivamente exportadas, por lo que los programas cliente de unirse a ellos en tiempo de carga.

Utilice AFX_EXT_CLASS para exportar toda la clase, en la definición de clase. Esta macro se define por el marco como dllexport cuando _AFXDLL y _AFXEXT está definido, pero define como __declspec (dllimport) cuando _AFXEXT no está definido. _AFXEXT como se describió anteriormente, sólo se define al crear el archivo DLL de extensión. Por ejemplo:

clase AFX_EXT_CLASS CExampleExport: CObject pública
{... clase definición...}

No exportar la clase entera

A veces puede que desee exportar a sólo los miembros necesarios de su clase. Por ejemplo, si va a exportar un CDialog-derivado de la clase, tal vez sólo necesite exportar el constructor y la llamada DoModal . Puede exportar a estos miembros utilizando el archivo DLL.Archivo DEF, pero usted también puede utilizar AFX_EXT_CLASS en mucho la misma manera a los miembros individuales que necesita exportar.

Por ejemplo:

 clase CExampleDialog: CDialog público
{
público:
   AFX_EXT_CLASS CExampleDialog();
   AFX_EXT_CLASS int DoModal();
   / / resto de definición de clase
   .
   .
   .
}

Al hacer esto, se puede ejecutar en un problema adicional debido a que ya no va a exportar a todos los miembros de la clase. El problema es en la forma en trabajo de macros MFC. Varias de las macros de auxiliar de MFC efectivamente declaran o definen a miembros de datos. Por lo tanto, estos miembros de datos también tendrá que ser exportada desde el archivo DLL.

Por ejemplo, la macro DECLARE_DYNAMIC se define como sigue al generar un archivo DLL de extensión:

# define DECLARE_DY&NAMIC(class_name) \
protegido: \
 nbsp; _GetBaseClass() de CRuntimeClass * PASCAL estático; \
   público: \
   clase CRuntimeClass AFX_DATA estática ## class_name; \
   virtual CRuntimeClass * GetRuntimeClass() const; \

La línea que comienza "static AFX_DATA" es declarar un objeto estático dentro de su clase. Exportar esta clase correctamente y acceder a la información de tiempo de ejecución desde un cliente.EXE, necesita exportar este objeto estático. Porque el objeto estático es declarado con el modificador AFX_DATA, sólo necesita definir AFX_DATA para ser dllexport al generar el archivo DLL y definir como __declspec (dllimport) cuando su cliente ejecutable de construcción.

Como se señaló anteriormente, AFX_EXT_CLASS ya está definido de esta manera. Tan sólo necesita redefinir AFX_DATA a ser el mismo que AFX_EXT_CLASS alrededor de la definición de clase.

Por ejemplo:

nbsp;  # undef AFX_DATA
   # define AFX_EXT_CLASS AFX_DATA
   clase CExampleView: CView pública
   {
     DECLARE_DY&NAMIC()
     / /... definición de clase...
   };
   # undef AFX_DATA
   # define AFX_DATA

MFC siempre utiliza el símbolo AFX_DATA de elementos de datos que define dentro de sus macros, por lo que esta técnica funcionará para todos los escenarios. Por ejemplo trabajará para DECLARE_MESSAGE_MAP.

&Notanbsp;  Si va a exportar la clase entera en lugar de miembros seleccionados de la clase, se exportan automáticamente miembros de datos estáticos.

Puede utilizar la misma técnica para exportar automáticamente el operador de extracción de CArchive para las clases que utilizan las macros DECLARE_SERIAL y IMPLEMENT_SERIAL . El operador de archivo de exportación por la sucesión de las declaraciones de clase (situado en el.Archivo H) con el siguiente código:

# undef AFX_API
# define AFX_API AFX_EXT_CLASS

lt; las declaraciones de clase aquí >

# undef AFX_API
# define AFX_API

Limitaciones de _AFXEXT

Puede utilizar el símbolo del preprocesador deAFXEXT _ para su extensión DLL como no tienes varias capas de archivos DLL de extensión. Si tiene extensión DLL que llame o derivar clases en su propia extensión DLL, que luego se derivan las clases MFC, deberá utilizar su propio símbolo de preprocesador para evitar la ambigüedad.

El problema es que en Win32, debe declarar explícitamente los datos como dllexport si es para exportar desde un archivo DLL y __declspec (dllimport) si ha de ser importada desde un archivo DLL. Cuando se define _AFXEXT, los encabezados MFC Asegúrese que AFX_EXT_CLASS está definida correctamente.

Si tiene varias capas, un símbolo como AFX_EXT_CLASS no es suficiente, desde un archivo DLL de extensión puede ser exportar nuevas clases así como importación de otras clases de otra extensión DLL. A fin de abordar este problema, utilice un símbolo del preprocesador especial que indica que está generando el archivo DLL frente a utilizar la DLL. Por ejemplo, imagine dos extensión DLL, A.DLL y B.DLL. Cada uno de ellos exporta algunas clases de A.H y B.H, respectivamente. B.dll utiliza las clases de A.DLL. Los archivos de encabezado sería algo como esto:

/ / A.H
# ifdef A_IMPL
   # define CLASS_DECL_A dllexport
# else
   # define CLASS_DECL_A __declspec (dllimport)
# endif

clase CLASS_DECL_A CExampleA: CObject pública
{... clase definición...};

/ / B.H
# ifdef B_IMPL
   # define CLASS_DECL_B dllexport
# else
   # define CLASS_DECL_B __declspec (dllimport)
# endif

clase CLASS_DECL_B CExampleB: CExampleA pública
{... clase definición..}

Cuando se construye A.DLL, está construido con /D A_IMPL y cuando B.DLL se construye, está construida con /D B_IMPL. Mediante el uso de símbolos separados para cada DLL, se exporta CExampleB y CExampleA se importa al edificio B.DLL. CExampleA se exporta al edificio A.DLL y importa cuando se usa B.DLL (o algún otro cliente).

Este tipo de capas no se puede hacer cuando se utilizan los símbolos del preprocesador incorporados, AFX_EXT_CLASS y _AFXEXT . La técnica descrita anteriormente resuelve este problema de una manera no a diferencia que el mecanismo MFC utiliza al crear su extensión OLE, la base de datos y la red de archivos DLL.

No exportar la clase entera

Nuevamente tendrá que tener un cuidado especial cuando no está exportando una clase entera. Se debe garantizar que los elementos de datos necesarios creados por las macros MFC se exportan correctamente. Esto puede hacerse por inmersos AFX_DATA macro de su clase específica. Esto debe hacerse cualquier momento que no va a exportar toda la clase.

Por ejemplo:

/ / A.H
# ifdef A_IMPL
 nbsp; # define CLASS_DECL_A _declspec(dllexport)
# else
   # define CLASS_DECL_A _declspec(dllimport)
   # endif

# undef AFX_DATA
# define CLASS_DECL_A AFX_DATA

clase CExampleA: CObject pública
{
   DECLARE_DY&NAMIC()
   Int CLASS_DECL_A SomeFunction();
   definición de //Class.
   .
   .
};

# undef AFX_DATA
# define AFX_DATA

DllMain

El siguiente es el código exacto que debe colocar en el archivo fuente principal para la DLL de extensión. Debe venir después de que la norma incluye. Tenga en cuenta que cuando utiliza AppWizard para crear archivos de arranque para un archivo DLL de extensión, proporciona una función DllMain para usted.

# include "afxdllx.h"

extensionDLL AFX_EXTE&NSION_MODULE estático;

extern "C" int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
 nbsp; Si (dwReason == DLL_PROCESS_ATTACH)
   {
      / / Inicialización única de DLL de extensión if (!() AfxInitExtensionModule
             extensionDLL, hInstance))
         devuelven 0;

/ / TODO: realizar otras tareas de inicialización aquí
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      / / Archivo DLL de extensión terminación por proceso
      AfxTermExtensionModule(extensionDLL);

/ / TODO: realizar otras tareas de limpieza aquí
   }
   devolver 1;   / / Aceptar
}

La llamada a AfxInitExtensionModule captura las módulos runtime-clases (estructurasCRuntimeClass ) así como sus fábricas de objetos (objetosCOleObjectFactory ) para su uso posterior, cuando se crea el objeto CDynLinkLibrary . La llamada a AfxTermExtensionModule (opcional) permite MFC Liberador de espacio en el archivo DLL de extensión cuando cada proceso (lo que ocurre cuando el proceso se cierra, o cuando el archivo DLL se descarga como resultado de una llamada de FreeLibrary ) se separa de la DLL de extensión. Desde la mayoría extensión DLL no se cargan dinámicamente (por lo general, están vinculados a través de sus bibliotecas de importación), la llamada a AfxTermExtensionModule no suele ser necesaria.

Si la aplicació&n se carga y libera dinámicamente archivos DLL de extensión, asegúrese de llamar a AfxTermExtensionModule como above.nbsp se muestra; También asegúrese de utilizar AfxLoadLibrary y AfxFreeLibrary (en lugar de funciones Win32 LoadLibrary y FreeLibrary) si la aplicación utiliza varios subprocesos. Uso de AfxLoadLibrary y AfxFreeLibrary garantiza que el código de inicio y apagado que se ejecuta cuando se carga y descarga el archivo DLL de extensión no corromper el estado global de MFC.

El archivo de encabezado AFXDLLX.H contiene definiciones especiales para estructuras utilizadas en extensión DLL, tales como la definición de AFX_EXTENSION_MODULE y CDynLinkLibrary.

El global extensionDLL deben declararse como se muestra. A diferencia de la versión de 16 bits de MFC, puede asignar memoria y llamar a las funciones MFC durante este tiempo, ya que el MFCxx.DLL se haya inicializado por el momento que se llama a la función DllMain.

Compartir recursos y clases

Simples archivos DLL de extensión MFC sólo necesitan exportar unas pocas funciones de bajo ancho de banda para la aplicación de cliente y nada más. Más archivos DLL intensivo de interfaz de usuario desee exportar clases de C++ y recursos para la aplicación de cliente.

Exportación de recursos se realiza a través de una lista de recursos. En cada aplicación es una lista vinculada de objetos CDynLinkLibrary . Cuando se busca un recurso, la mayoría de las implementaciones estándar de MFC que carga recursos mirar primeros en el módulo de recursos actual (AfxGetResourceHandle) y si no se encuentra la lista de objetos CDynLinkLibrary intentar cargar el recurso solicitado a pie.

Creación dinámica de objetos de C++ recibe un nombre de clase de C++ es similar. El mecanismo de deserialización del objeto MFC debe tener todos los objetos CRuntimeClass registrados por lo que puede reconstruir creando dinámicamente objetos C++ del tipo necesario basado en lo que fue almacenado anteriormente.

Si desea que la aplicación cliente para utilizar las clases de la DLL de extensión que son DECLARE_SERIAL, será necesario exportar sus clases sean visibles para la aplicación de cliente. Esto también se hace recorrer la lista de CDynLinkLibrary.

En el caso de la muestra de conceptos avanzados de MFC DLLHUSK, la lista de aspecto

cabeza - >   DLLHUSK.EXE - o - DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL TESTDLL1.DLL
               |                      |
           MFCO42D.DLL                |
               |                      |
           MFCD42D.DLL                |
               |                      |
            MFC42D.DLL MFC42.DLL

El MFCxx.DLL es usualmente pasada en la lista de clase y recursos. MFCxx.DLL incluye todos los recursos estándar de MFC, incluyendo cadenas de mensaje para todos los identificadores de comandos estándar. Colocándolo a la cola de la lista permite archivos DLL y la aplicación de cliente que no tiene un su propia copia de los recursos estándar de MFC, pero que confían en los recursos compartidos en el MFCxx.DLL en su lugar.

Combinar los recursos y los nombres de clase de todas las DLL en el espacio de nombre de la aplicación cliente tiene la desventaja que tienes que tener cuidado qué IDs o nombres que usted elija. Por supuesto puede desactivar esta función por no exportar sus recursos o un objeto CDynLinkLibrary a la aplicación cliente. El ejemplo DLLHUSK administra el espacio de nombre de recurso compartido mediante el uso de varios archivos de encabezado. Ver 35 de nota técnica para más consejos sobre el uso de recurso compartido de archivos.

Inicializar el archivo DLL

Como se mencionó anteriormente, generalmente deseará crear un objeto CDynLinkLibrary para exportar sus recursos y clases a la aplicación cliente. Necesitará proporcionar un punto de entrada exportado para inicializar el archivo DLL. Mínimamente esta es una rutina de vacío que no toma ningún argumento y devuelve nada, pero puede ser cualquier cosa que te gusta.

Cada aplicación de cliente que quiere utilizar la DLL debe llamar a esta rutina de inicialización, si utiliza este enfoque. También puede asignar este objeto CDynLinkLibrary en su función DllMain justo después de llamar a AfxInitExtensionModule.

La rutina de inicialización debe crear un objeto CDynLinkLibrary en montículo de la aplicación actual, wired hasta la información de archivo DLL de extensión. Esto puede hacerse con la siguiente:

extern "C" de extern void WI&NAPI InitXxxDLL()
{
 nbsp; Nueva CDynLinkLibrary(extensionDLL);
}

El nombre de rutinario, InitXxxDLL en este ejemplo, puede ser cualquier cosa que desee. No necesita ser extern “C” , pero haciendo lo hace más fácil mantener la lista de exportación.

&Notanbsp;  Si utiliza la extensión DLL desde un archivo DLL estándar, debe exportar esta función de inicialización. Esta función debe ser llamada desde el archivo DLL estándar antes de utilizar cualquier extensión DLL clases o recursos.

Exportar entradas

La forma simple de exportar sus clases es utilizar __declspec (dllimport) y dllexport en cada clase y función global que desea exportar. Esto facilita mucho, pero es menos eficiente que la denominación de cada punto de entrada (descrito a continuación) ya tiene menos control sobre qué funciones se exportan y no se pueden exportar las funciones por ordinal. Este es el método que TESTDLL1 y TESTDLL2 utilizan para exportar sus entradas.

Son un método más eficiente (y el método utilizado por MFCxx.DLL) exportar cada entrada a mano nombrando a cada entrada en el.Archivo DEF. Ya estamos exportando las exportaciones selectivas desde nuestro archivo DLL (es decir, no todo), tenemos que decidir qué interfaces particulares queremos exportar. Esto es difícil ya que se deben especificar los nombres arruinando al vinculador en forma de entradas en el.Archivo DEF. No exportar cualquier clases de C++ a menos que realmente necesita tener un enlace simbólico para TI.

Si ha intentado exportar C++ clases con una.Definición de archivo antes, puede que desee desarrollar una herramienta para generar esta lista automáticamente. Esto puede hacerse mediante un proceso de enlace de dos etapas. Vincular el archivo DLL con no las exportaciones, y permite el vinculador generar un.Archivo de mapa. La.Archivo de mapa puede utilizarse para generar una lista de funciones que debe exportarse, por lo que con algunos munging, puede utilizarse para generar las entradas de exportación para su.Archivo DEF. La lista de exportación para MFCxx.DLL, OLE y archivos DLL de extensión de base de datos, varios miles en número, se generó con ese proceso (aunque no es completamente automático y requiere algunos mano ajuste cada vez en un tiempo).

CWinApp vs CDynLinkLibrary

Un archivo DLL de extensión de MFC no tienen un CWinApp-derivados objeto propio; en su lugar debe trabajar con el CWinApp-objeto de la aplicación cliente derivado. Esto significa que la aplicación cliente posee la bomba principal de mensajes, el bucle de inactividad, etc.

Si el archivo DLL de extensión de MFC necesita mantener datos adicionales para cada aplicación, puede derivar una nueva clase de CDynLinkLibrary y crear en la InitXxxDLL rutina describir por encima. Cuando se ejecuta, el archivo DLL puede comprobar la lista de la aplicación actual de objetos CDynLinkLibrary encontrar uno para ese archivo DLL de extensión particular.

Uso de recursos en su implementación de DLL

Como se mencionó anteriormente, la carga de recursos predeterminado guiará la lista de objetos CDynLinkLibrary buscando el primer EXE o DLL que tiene el recurso solicitado. Todas las APIs de MFC, así como todo el código interno utiliza AfxFindResourceHandle para caminar la lista de recursos para encontrar cualquier recurso, no importa donde pueden residir.

Si desea cargar sólo los recursos de un lugar específico, utilice las API AfxGetResourceHandle y AfxSetResourceHandle para guardar el identificador antiguo y establecer el nuevo identificador. Asegúrese de restaurar el identificador de recurso antiguo antes de volver a la aplicación cliente. La muestra TESTDLL2 utiliza este método para cargar explícitamente un menú.

Recorrer la lista tiene las desventajas que es ligeramente más lento y requiere gestión de rangos de ID de recurso. Tiene la ventaja de que una aplicación cliente que vincula a varios archivos DLL de extensión puede utilizar cualquier recurso siempre DLL sin tener que especificar el identificador de instancia DLL. AfxFindResourceHandle es una API que se utiliza para recorrer la lista de recursos para buscar una coincidencia determinada. Toma el nombre y el tipo de un recurso y devuelve el identificador de recursos donde fue descubierto (o NULL).

Escribir una aplicación que utiliza la versión de la DLL

Requisitos de la aplicación

Una aplicación que utiliza la versión compartida de MFC debe seguir unas reglas simples:

Edificio con el entorno de desarrollo

Si está utilizando el makefile interno con la mayoría de las opciones predeterminadas estándar, puede cambiar fácilmente el proyecto para construir la versión de la DLL.

El paso siguiente asume que tiene una aplicación MFC funcione correctamente vinculada con NAFXCWD.LIB (para depuración) y NAFXCW.LIB (para la venta minorista) y desea convertirlo a utilizar la versión de la biblioteca MFC compartida. Está ejecutando el entorno de Visual C++ y tener un archivo de proyecto interno.

  1. Seleccione configuración en el menú Generar. En la página General de ajustes del proyecto, establezca Microsoft Foundation Classes para utilizar MFC en una DLL compartida (MFCxx(d).dll).

Edificio con NMAKE

Si está utilizando la función de makefile externa de Visual C++, o utilizan directamente NMAKE, tendrá que editar el fichero makefile en apoyo del compilador y las opciones del vinculador

Banderas de compilador requiere:

/ /MD D_AFXDLL

/ D_AFXDLL

Los encabezados estándar de MFC necesitan este símbolo a definirse:

/MD

La aplicación debe utilizar la versión de la DLL de la biblioteca de tiempo de ejecución de c

Todos los otros indicadores de compilador siguen los valores predeterminados de MFC (por ejemplo, _DEBUG para depuración).

Editar la lista de vinculador de bibliotecas. Cambio NAFXCWD.LIB para MFCxxD.LIB y NAFXCW de cambio.LIB para MFCxx.LIB. Añadir MFCOxx[U]D.LIB, MFCDxx[U]D.LIB y MFCNxx[U]D.LIB según corresponda (requerido para uso del MFC/OLE, base de datos o clases de redes). Reemplazar LIBC.LIB con MSVCRT.LIB. Como con cualquier otra biblioteca MFC es importante que MFCxxD.LIB se coloca antes de que las bibliotecas de tiempo de ejecución de c.

Opcionalmente agregar /D_AFXDLL a ambos su minorista y depurar las opciones del compilador de recursos (uno que compila realmente los recursos con /R). Esto hace que el ejecutable final menor al compartir los recursos que están presentes en las DLL de MFC.

Una reconstrucción completa es necesaria después de estos cambios.

Construcción de las muestras

La mayoría de los programas de ejemplo MFC puede construirse desde Visual C++ o un MAKEFILE NMAKE compatible compartido desde la línea de comandos.

Para convertir cualquiera de estos ejemplos para utilizar MFCxx.DLL, puede cargar el.MAK de archivos en Visual C++ y defina las opciones de proyecto como se describió anteriormente. Si está utilizando la versión NMAKE, puede especificar "AFXDLL = 1" en el NMAKE línea de comandos y que se basará la muestra utilizando las bibliotecas compartidas de MFC.

La muestra de conceptos avanzados de MFC DLLHUSK está construido con la versión de la DLL de MFC. Esta muestra no sólo cómo generar una aplicación vinculada con MFCxx.DLL, pero también muestra otras características de la opción de empaque de DLL de MFC, como se describe más adelante en esta nota técnica archivos DLL de extensión de MFC.

Notas de embalaje

La versión de la DLL (MFCxx [U].DLL) son libremente redistribuible. La versión de depuración de los archivos DLL no son libremente redistribuible y debe utilizarse sólo durante el desarrollo de la aplicación.

La depuración de archivos DLL se proporcionan con información de depuración. Al utilizar al depurador de Visual C++, puede rastrear la ejecución de la aplicación, así como la DLL. Las DLL de lanzamiento (MFCxx [U].DLL) no contiene información de depuración.

Si desea Personaliza o reconstruir los archivos DLL, entonces debe llamarles algo distinto el archivo "MFCxx" la MFC SRC MFCDLL.MAK describe las opciones de compilación y contiene la lógica para cambiar el nombre del archivo DLL. Esta regla también se aplica a la MFC/OLE, la base de datos y la red archivos DLL que se construyen por MFCOLE.MAK, MFCDB.MAK y MFCNET.MAK, respectivamente. Cambiar el nombre de los archivos es necesario, ya que estos archivos DLL son potencialmente compartidos por muchas de las aplicaciones MFC. Tener la versión personalizada de las DLL de MFC reemplazar aquellos instalados en el sistema puede romper otra aplicación MFC con las DLL de MFC compartida.

No se recomienda la reconstrucción de los archivos DLL de MFC.

¿Cómo se implementa la MFCxx.DLL

La siguiente sección describe cómo se implementa la DLL de MFC (MFCxx.DLL y MFCxxD.DLL). Comprender que los detalles aquí también no son importante si todo lo que queremos hacer es utilizar la DLL de MFC con su aplicación. Los detalles aquí no son esenciales para la comprensión de cómo escribir un archivo DLL de extensión MFC, pero entender esta aplicación puede ayudarle a escribir su propia DLL.

Panorámica de la implementación

La DLL de MFC realmente es un caso especial de un archivo DLL de extensión de MFC, como se describió anteriormente. Tiene un número muy grande de las exportaciones de un gran número de clases. Hay algunas cosas adicionales que hacemos en la DLL de MFC que hacen aún más especial que una DLL de extensión regular.

Win32 hace la mayor parte de los trabajos

La versión de 16 bits de MFC necesarias una serie de técnicas especiales, incluidos los datos por app en el segmento de pila, segmentos especiales creados por algunos ensamblador 80 x 86, contextos de excepción por proceso y otras técnicas. Win32 directamente admite por proceso de datos en un archivo DLL, que es lo que desea la mayoría del tiempo. En su mayor parte MFCxx.DLL es solo NAFXCW.LIB empaquetado en un archivo DLL. Si miramos el código fuente MFC, encontrará muy pocos # ifdef _AFXDLL, ya que hay muy pocos casos especiales que necesitan ser hechas. Los casos especiales que están allí son específicamente tratar de Win32 en Windows 3.1 (conocido como Win32s). Win32s no apoyo por proceso DLL datos directamente hasta la DLL de MFC debe utilizar el almacenamiento local de subprocesos (TLS) API Win32 para obtener datos locales de proceso.

Impacto sobre las fuentes de biblioteca, archivos adicionales

El impacto de la versión _AFXDLL sobre las fuentes normales de biblioteca de clases MFC y encabezados es relativamente menor. Existe un versión especial del archivo (AFXV_DLL.H) así como un archivo de encabezado adicional (AFXDLL_.H) incluido por la AFXWIN principal.Encabezado de H. El AFXDLL_.H cabecera incluye la clase CDynLinkLibrary y otros detalles de la implementación de aplicaciones de _AFXDLL y archivos DLL de extensión de MFC. El AFXDLLX.Encabezado de h se proporciona para generar archivos DLL de extensión de MFC (vea los detalles más arriba).

Las fuentes regulares a la biblioteca MFC MFC SRC tienen algún código condicional adicional bajo el # ifdef _AFXDLL . Un archivo de fuente adicional (DLLINIT.CPP) contiene el código de inicialización de DLL adicional y otro pegamento para la versión compartida de MFC.

A fin de construir la versión compartida de MFC, se proporcionan los archivos adicionales. (Consulte a continuación para obtener más información sobre cómo crear el archivo DLL).

Generando el archivo DLL de MFC

Reconstrucción de la DLL de MFC es intencionalmente difícil, así que creo que dos veces (o tres veces) antes de hacerlo. Si usted entiende los problemas potenciales de embalaje y restricciones de redistribución que se describe a continuación y usted todavía realmente necesitan reconstruir la DLL de MFC, puede.

El MFCDLL.Archivo MAK construirá la DLL de depuración con CodeView info:

NMAKE /f mfcdll.mak DEBUG = 1 LIBNAME = MYMFC

El MFCDLL.Archivo MAK construirá la DLL versión sin información CodeView:

NMAKE /f mfcdll.mak DEBUG = 0 LIBNAME = MYMFC

(Asimismo, utilizar MFCOLE.MAK, MFCDB.MAK y MFCNET.MAK a construir el MFCOxxD.DLL, MFCDxxD.DLL y MFCNxxD.DLL--la DLL que contienen las MFC/OLE, base de datos y las clases de red)

Esto creará una versión privada de la DLL de MFC en el directorio SRC de MFC con los nombres estándar de MFCxx.DLL y MFCxxD.DLL. Necesita copiar a un lugar apropiado en su ruta de acceso para utilizar los nuevos archivos DLL. El MFCDLL.MAK makefile también reconstruir las bibliotecas de importación (MFCxx.LIB y MFCxxD.LIB) y colocarlos en el directorio estándar de MFC LIB. Esto reemplazará las bibliotecas MFCxx.LIB y MFCxxD.LIB preelaboradas, así que tenga cuidado.

Si desea distribuir una versión modificada de la biblioteca DLL de MFC, asegúrese de cambiar el nombre del archivo DLL en el MFCDLL.MAK makefile y los dos.Archivos de definición. Consulte el archivo Make MFCDLL.MAK para obtener más información.

Puede modificar la biblioteca y redistribuir un minorista (/ lanzar) de tu biblioteca modificada sólo si cambiarle el nombre a algo distinto de MFCxx.DLL. No puede redistribuir la versión de depuración de cualquiera la depuración construido DLL predefinida o personalizada.

Estas restricciones de redistribución son principalmente evitar una proliferación de estándar y potencialmente virus que contenga archivos DLL. lo ideal no es necesario reconstruir las DLL y si redistribuye su aplicación con el MFCxx.DLL preelaborados suministrada con el producto de Visual C++, evitará un montón de problemas para usted y sus usuarios.

Administración de memoria

Una aplicación mediante MFCxx.DLL utiliza un asignador de memoria común proporcionada por MSVCRTxx.DLL, la DLL de c runtime compartida. La aplicación, cualquier DLL de extensión, así como los archivos DLL de MFC, utilice este asignador de memoria compartida. Mediante el uso de una DLL compartida para la asignación de memoria, los archivos DLL de MFC puede asignar la memoria que más tarde es liberado por la aplicación o viceversa. Debido a la aplicación y el archivo DLL deben utilizar el asignador de mismo, no debe reemplazar el C++ global nuevo operador o eliminar operador. Las mismas reglas se aplican al resto de las rutinas de asignación de memoria de tiempo de ejecución de C (como malloc, realloc, libre, etc..).

Números ordinales y clase dllexport y nomenclatura de DLL

No usamos el class dllexport la funcionalidad del compilador C++. En su lugar, una lista de las exportaciones está incluida en las fuentes de biblioteca de clase (MFCxx.DEF y MFCxxD.DEF). Se exportan sólo estos seleccione conjunto de puntos de entrada (funciones y datos). Otros símbolos, tales como funciones de implementación privada de MFC o clases, no se exportan todas las exportaciones se realizan por ordinal sin un nombre de cadena en el cuadro Nombre de residentes o no residentes .

Mediante class dllexport puede ser una alternativa viable para la construcción de pequeñas archivos DLL, pero en el caso de un gran archivo DLL como MFC, el valor por defecto exportar mecanismo tiene eficacia y capacidad de límites .

¿Qué es este todos los medios que podemos empaquetar una gran cantidad de funcionalidades en la versión MFCxx.DLL que sólo alrededor de 800 KBytes sin comprometer mucho ejecución o velocidad de carga. MFCxx.DLL habría sido 100 K más grande esta técnica no ha sido utilizado.Esto también permite añadir puntos de entrada adicionales al final de la.Archivo de definición para permitir versiones simples sin comprometer la eficacia de velocidad y el tamaño de exportación por ordinal. Las revisiones de la versión principal de la biblioteca de clases MFC cambiará el nombre de la biblioteca. Es decir, MFC30.DLL es la DLL redistribuible que contiene la versión 3.0 de la biblioteca de clases MFC. Una actualización de esta DLL, digamos, en un hipotético 3.1 de MFC, la DLL se llamaría MFC31.DLL en su lugar. Una vez más, si se modifica el código fuente MFC para producir una versión personalizada de la DLL de MFC, utilice un nombre diferente (y preferiblemente uno sin "MFC") en el nombre.

&Notas técnicas por número |nbsp; Notas técnicas por categoría

Index