¿Qué archivo tiene la extensión "DLL"? ¿Qué programa usas para abrirlo?
En funciones relativamente independientes, cooperan entre sí para completar el trabajo de todo el sistema de software. Puede haber algunos módulos cuyas funciones sean más generales y aún se utilizarán al construir otros sistemas de software. Al construir un sistema de software, si el código fuente de todos los módulos se compila estáticamente en el archivo EXE completo de la aplicación, surgirán algunos problemas: una desventaja es que aumenta el tamaño de la aplicación, lo que ocupa más espacio en el disco y el programa se ejecuta. También consumirá una gran cantidad de espacio de memoria, lo que provocará un desperdicio de recursos del sistema. Otra desventaja es que al escribir un programa EXE grande, todos los códigos fuente deben ajustarse y compilarse cada vez que se modifica y reconstruye, lo que aumenta la complejidad de; el proceso de compilación, que tampoco es propicio para pruebas unitarias por etapas.
La plataforma del sistema Windows proporciona un entorno de programación y ejecución completamente diferente y más efectivo. Puede crear módulos de programa independientes como archivos DLL (Biblioteca dinámica enlazable) más pequeños y controlarlos y probarlos individualmente. En tiempo de ejecución, el sistema cargará estos módulos DLL en el espacio de la memoria solo si el programa EXE realmente quiere llamarlos. Este enfoque no sólo reduce el tamaño del archivo EXE y los requisitos de espacio de memoria, sino que también permite que múltiples aplicaciones utilicen estos módulos DLL al mismo tiempo. El propio Windows implementa algunas funciones importantes del sistema en forma de módulos DLL.
En términos generales, una DLL es un archivo de disco. Los archivos del sistema con .dll, .DRV, .FON, .SYS y muchas extensiones .EXE pueden ser DLL. Consiste en datos globales, funciones de servicio y recursos. El sistema lo carga en el espacio virtual del proceso de llamada en tiempo de ejecución y se convierte en parte del proceso de llamada. Si no hay conflictos con otras DLL, el archivo generalmente se asigna a la misma dirección en el espacio virtual del proceso. El módulo DLL contiene varias funciones exportadas para brindar servicios al mundo exterior. Una DLL puede tener su propio segmento de datos, pero no tiene su propia pila. Utiliza el mismo modo de pila que la aplicación que la llama; una DLL tiene solo una instancia en la memoria; la DLL implementa la encapsulación de código; está relacionado con el lenguaje de programación específico. No tiene nada que ver con el compilador.
En un entorno Win32, cada proceso copia sus propias variables globales de lectura/escritura. Si desea compartir memoria con otros procesos, debe utilizar un archivo asignado en memoria o declarar un segmento de datos compartido. La memoria de pila requerida por los módulos DLL se asigna desde la pila del proceso en ejecución. Windows compara las llamadas a funciones de proceso con las funciones exportadas del archivo DLL cuando carga un módulo DLL. La operación del sistema operativo Windows en la DLL es solo asignar la DLL al espacio de direcciones virtuales del proceso que la necesita. Cualquier objeto (incluidas las variables) creado por código dentro de una función DLL es propiedad del hilo o proceso que lo llama.
Método de llamada
1. Método de llamada estática: el sistema de compilación completa la carga de la DLL y la codificación de la descarga de la DLL cuando finaliza el programa de aplicación (si otros programas usan la DLL). , luego Windows disminuye el registro de la aplicación de la DLL en 1 y no lo libera hasta que todos los programas relacionados hayan terminado de usar la DLL. Es simple y práctico, pero no lo suficientemente flexible y solo puede cumplir con los requisitos generales. llamadas: el archivo .LIB generado al generar la biblioteca de enlaces dinámicos debe agregarse al proyecto de la aplicación. Cuando desee utilizar las funciones en la DLL, solo necesita explicar que las llamadas implícitas no requieren llamar a LoadLibrary () y FreeLibrary. () Al crear un archivo DLL, el vinculador genera automáticamente un archivo de importación LIB correspondiente. Este archivo contiene el nombre simbólico y el número de identificación opcional de cada función exportada de DLL, pero no contiene el código real del archivo LIB como DLL. El archivo de reemplazo se compila en el proyecto de la aplicación.
Cuando el programador compila y genera la aplicación mediante enlaces estáticos, las funciones de llamada en la aplicación coinciden con los símbolos exportados en el archivo LIB. en el archivo EXE generado.
El archivo LIB también contiene el nombre del archivo DL L correspondiente (pero no el nombre de la ruta completa), que el vinculador almacena dentro del archivo EXE.
Cuando una aplicación necesita cargar un archivo DLL durante la ejecución, Windows descubre y carga la DLL en función de esta información y luego vincula dinámicamente la función DLL a través del nombre del símbolo o el número de identificación. Todos los archivos DLL llamados por la aplicación se cargarán en la memoria cuando se cargue el archivo EXE de la aplicación. El programa ejecutable se vincula a un archivo de biblioteca de entrada (archivo .LIB) que contiene información sobre las funciones exportadas de la DLL. El sistema operativo carga la DLL cuando carga el programa ejecutable. El programa ejecutable llama directamente a la función de salida de la DLL a través del nombre de la función, y el método de llamada es el mismo que el de otras funciones dentro del programa.
2. Método de llamada dinámica: el programador utiliza funciones API para cargar y descargar la DLL para lograr el propósito de llamar a la DLL. Es más complicado de usar, pero puede usar la memoria de manera más efectiva. la mejor opción al compilar aplicaciones a gran escala.
Llamada explícita: se refiere al uso de LoadLibrary o AfxLoadLibrary proporcionado por MFC para llamar explícitamente a la biblioteca de enlaces dinámicos que ha creado en la aplicación. El nombre de archivo de la biblioteca de enlaces dinámicos son los dos parámetros anteriores. función y luego use GetProcAddress() para obtener la función que desea introducir. De ahora en adelante, puede llamar a esta función importada como una función personalizada en esta aplicación. Antes de que se cierre la aplicación, se debe liberar la biblioteca de vínculos dinámicos utilizando FreeLibrary o AfxFreeLibrary proporcionado por MFC. Llame a la función Win32 LoadLibary directamente y especifique la ruta a la DLL como parámetro. LoadLibary devuelve el parámetro HINSTANCE que utiliza la aplicación al llamar a la función GetProcAddress. La función GetProcAddress convierte un nombre simbólico o número de identificación en una dirección dentro de la DLL. El programador puede decidir cuándo se carga o no un archivo DLL; el enlace explícito determina qué archivo DLL se carga en tiempo de ejecución. Los programas que usan DLL deben cargarse (LoadLibrary) antes de su uso para cargar la DLL para obtener un identificador del módulo DLL y luego llamar a la función GetProcAddress para obtener el puntero de la función de salida. La DLL debe descargarse (FreeLibrary) antes de salir.
Windows seguirá el siguiente orden de búsqueda para localizar la DLL:
El directorio que contiene el archivo EXE
El directorio de trabajo actual del proceso
Directorio del sistema de Windows
Directorio de Windows
Una serie de directorios enumerados en la variable de entorno Ruta
DLL en MFC
No -MFC DLL: se refiere a una DLL escrita directamente en lenguaje C sin la estructura de biblioteca de clases de MFC. Sus funciones de salida generalmente usan la interfaz C estándar y pueden ser invocadas por aplicaciones que no sean MFC o escritas en MFC.
DLL normal: al igual que las DLL de extensión que se describen a continuación, se escribe utilizando la biblioteca de clases MFC. La característica obvia es que hay una clase que hereda CWinApp en el archivo fuente. Se puede subdividir en conexiones estáticas a MFC y conexiones dinámicas a MFC.
Las bibliotecas de vínculos dinámicos vinculadas estáticamente a MFC solo son compatibles con las ediciones Professional y Enterprise de VC. Las funciones de salida de este tipo de aplicación DLL pueden ser utilizadas por cualquier programa Win32, incluidas las aplicaciones que utilizan MFC. La función de entrada tiene la siguiente forma:
extern "C" EXPORT YourExportedFunction();
Sin la modificación externa "C", la función de salida solo se puede llamar desde código C++.
Las aplicaciones DLL se derivan de CWinApp pero no tienen un bucle de mensajes.
Las funciones de salida en una aplicación DLL de reglas que está vinculada dinámicamente a MFC pueden ser utilizadas por cualquier programa Win32, incluidas las aplicaciones que usan MFC. Sin embargo, todas las funciones exportadas desde la DLL deben comenzar con la siguiente declaración:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
Esta declaración se utiliza para cambiar correctamente el estado del módulo MFC.
Las aplicaciones escritas en todos los lenguajes que admiten la tecnología DLL pueden llamar a la DLL normal. En este tipo de biblioteca de enlaces dinámicos, debe tener una clase heredada de CWinApp. La función DLLMain la proporciona MFC y no es necesario que usted la escriba explícitamente.
DLL de extensión: se utiliza para reutilizar clases heredadas de MFC. En otras palabras, este tipo de biblioteca de enlaces dinámicos se puede utilizar para generar una clase heredada de MFC. Las funciones que exporta solo pueden ser utilizadas por aplicaciones que usan MFC y están vinculadas dinámicamente a MFC. Puede heredar de MFC las clases que desee y que sean más adecuadas para su propio uso y proporcionarlas a su aplicación. También puede proporcionar a su aplicación punteros de objetos a MFC o clases derivadas de MFC. La DLL de extensión se crea utilizando la versión vinculada dinámicamente de MFC y solo la llaman aplicaciones escritas con la biblioteca de clases MFC. Las DLL de extensión se diferencian de las DLL normales en que no tienen objetos de clases heredadas de CWinApp, por lo que debe agregar código de inicialización y código de terminación a su función DLLMain.
Comparado con la regla DLL, existen las siguientes diferencias:
1. No tiene objetos derivados de CWinApp.
2. Función DLLMain;
3. Cuando DLLMain llama a la función AfxInitExtensionModule, debe verificar el valor de retorno de la función. Si devuelve 0, DLLMmain también devuelve 0. desea generar un objeto o recurso de tipo CRuntimeClass, debe proporcionar una función de inicialización para crear un objeto CDynLinkLibrary. Además, es necesario generar la función de inicialización;
5. Las aplicaciones MFC que usan DLL extendida deben tener una clase derivada de CWinApp, y la función de inicialización de la DLL extendida generalmente se llama en InitInstance.
Función de entrada de DLL
1. Cada DLL debe tener un punto de entrada y DLLMain es una función de entrada predeterminada. DLLMain es responsable de la inicialización y finalización. Siempre que un nuevo proceso o un nuevo subproceso del proceso acceda a la DLL, o cada proceso o subproceso que acceda a la DLL ya no use la DLL o finalice, se llamará a DLLMain. Sin embargo, el uso de TerminateProcess o TerminateThread para finalizar el proceso o subproceso no llamará a DLLMain.
Prototipo de función de DLLMain:
BOOL APIENTRY DLLMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID
lpReserved)
{
switch(ul_reason_for_call)
{
caso DLL_PROCESS_ATTACH:
.......
caso DLL_THREAD_ATTACH:
.......
caso DLL_THREAD_DETACH:
.......
caso DLL_PROCESS_DETACH: p> p>
.......
devuelve VERDADERO;
}
}
Parámetros:
hMoudle: Es un identificador que apunta a sí mismo y que se pasa cuando se llama a la biblioteca dinámica (en realidad, es un selector que apunta al segmento _DGROUP);
ul_reason_for_call: Es un descripción dinámica Bandera que indica el motivo por el cual se llamó a la biblioteca. Cuando un proceso o subproceso carga o descarga una biblioteca de vínculos dinámicos, el sistema operativo llama a la función de entrada y explica el motivo por el cual se llama a la biblioteca de vínculos dinámicos. Todos sus valores posibles son:
DLL_PROCESS_ATTACH: Se llama al proceso;
DLL_THREAD_ATTACH: Se llama al hilo;
DLL_PROCESS_DETACH: Se detiene el proceso;
DLL_THREAD_DETACH: El hilo está detenido;
lpReserved: es un parámetro reservado por el sistema;
2 _DLLMainCRTStartup
En orden para usar "C" para ejecutar Para la versión DLL (multiproceso) de la biblioteca (CRT, biblioteca en tiempo de ejecución C), una aplicación DLL debe especificar _DLLMainCRTStartup como función de entrada y la función de inicialización de la DLL debe ser DLLMain.
_DLLMainCRTStartup completa las siguientes tareas: asigna espacio e inicialización para datos de tiempo de ejecución "C" (C Runtime Data) cuando un proceso o subproceso se agrupa (adjunta) a una DLL y construye un objeto global "C++". O cuando el hilo termine usando la DLL (Separar), limpie los datos de tiempo de ejecución de C y destruya el objeto global "C++". También llama a las funciones DLLMain y RawDLLMain.
RawDLLMain es necesario cuando una aplicación DLL se vincula dinámicamente a una DLL de MFC, pero está estáticamente vinculada a una aplicación DLL. Explique por qué cuando se habla de gestión estatal.
Acerca de las convenciones de llamada
Hay dos convenciones para las funciones de salida de la biblioteca dinámica: convenciones de llamada y convenciones de modificación de nombres.
1) Convención de llamada: determina el orden en el que los parámetros de la función se insertan y sacan de la pila cuando se transfieren, si la persona que llama o la persona que llama saca los parámetros de la pila y las modificaciones utilizadas. por el compilador para identificar los nombres de las funciones.
Hay muchas convenciones de llamada a funciones, aquí hay una breve introducción:
1. La convención de llamada __stdcall es equivalente a la convención de llamada PASCAL que se usa a menudo en bibliotecas dinámicas de 16 bits. En VC++5.0 de 32 bits, la convención de llamada PASCAL ya no es compatible (de hecho, se ha definido como __stdcall. Además de __pascal, __fortran y __syscall tampoco son compatibles), reemplazada por la convención de llamada __stdcall.
Los dos son esencialmente iguales, es decir, los parámetros de la función se pasan a través de la pila de derecha a izquierda, y la función llamada borra los parámetros transferidos de la pila de memoria antes de regresar, pero la diferencia es la parte modificada de la función. nombre (sobre la parte modificada del nombre de la función) se explicará en detalle más adelante).
_stdcall es el método de llamada predeterminado de los programas Pascal. Generalmente se usa en la API de Win32. La función empuja la pila de derecha a izquierda y la limpia cuando sale. Después de que VC compila la función, agregará un prefijo de guión bajo delante del nombre de la función y "@" y el número de bytes de los parámetros después del nombre de la función.
2. La convención de llamadas de C (es decir, explicada con la palabra clave __cdecl) inserta los parámetros en la pila en orden de derecha a izquierda, y la persona que llama los saca de la pila. La persona que llama mantiene la pila de memoria para pasar parámetros (debido a esto, las funciones que implementan argumentos variables solo pueden usar esta convención de llamada). Además, también existen diferencias en las convenciones de modificación del nombre de la función.
_cdecl es el método de llamada predeterminado para programas C y C++. Cada función que la llama contiene código para borrar la pila, por lo que el tamaño del archivo ejecutable resultante será mayor que el de llamar a la función _stdcall. Las funciones se colocan en la pila de derecha a izquierda. Después de que VC compila la función, agregará un prefijo de guión bajo delante del nombre de la función. Es la convención de llamadas predeterminada de MFC.
3. La convención de llamada __fastcall es "humana". Como su nombre indica, su característica principal es rápida, porque transfiere parámetros a través de registros (de hecho, utiliza ECX y EDX para transferir los dos primeros dobles). palabras (DWORD) o parámetros más pequeños, los parámetros restantes aún se insertan en la pila de derecha a izquierda y la función llamada borra la pila de memoria de los parámetros transferidos antes de regresar). los dos anteriores diferentes.
El método _fastcall utiliza registros para pasar parámetros. Después de que VC compila la función, agregará el prefijo "@" delante del nombre de la función y agregará "@" y el número de bytes del parámetro. después del nombre de la función.
4. Esta llamada solo se aplica a funciones miembro de "C++". Este puntero se almacena en el registro CX y los parámetros se presionan de derecha a izquierda. thiscall no es una palabra clave y, por lo tanto, el programador no puede especificarla.
5. Cuando la llamada desnuda adopta la convención de llamada del 1 al 4, si es necesario, el compilador generará código para guardar los registros ESI, EDI, EBX y EBP al ingresar a la función y generará la recuperación del código. al salir de la función.
La llamada desnuda no genera dicho código. La llamada desnuda no es un modificador de tipo, por lo que debe usarse junto con _declspec ***.
Las palabras clave __stdcall, __cdecl y __fastcall se pueden agregar directamente antes de la función que se generará, o se pueden seleccionar en el elemento Configuración...\C/C++\Code Generation del entorno de compilación. Cuando la palabra clave agregada antes de la función de salida es diferente de la selección en el entorno de compilación, la palabra clave agregada directamente antes de la función de salida es efectiva. Sus parámetros de línea de comando correspondientes son /Gz, /Gd y /Gr respectivamente. El estado predeterminado es /Gd, que es __cdecl.
Para imitar completamente la convención de llamada PASCAL, primero debe usar la convención de llamada __stdcall. En cuanto a la convención de modificación del nombre de la función, puede imitarla mediante otros métodos. Otra cosa que vale la pena mencionar es la macro WINAPI, que es compatible con Windows.h y puede traducir funciones salientes a la convención de llamada adecuada. En WIN32, se define como __stdcall. Utilice la macro WINAPI para crear sus propias API.
2) Convención de modificación de nombre
1. Nombre de decoración (Nombre de decoración)
La función "C" o "C++" se pasa internamente (compilación y vinculación). ) Reconocimiento de nombre modificado. El nombre decorado es una cadena generada por el compilador al compilar una definición o prototipo de función. En algunos casos, es necesario utilizar nombres modificados de funciones, como especificar la salida de funciones, constructores y destructores sobrecargados de "C++" en el archivo de definición del módulo, o llamar a funciones "C" o "C++" en código ensamblador. esperar.
El nombre modificado está determinado por el nombre de la función, el nombre de la clase, la convención de llamada, el tipo de retorno, los parámetros, etc.
2. Las convenciones de modificación de nombres varían según las convenciones de llamada y los tipos de compilación (C o C++). Las convenciones de modificación de nombres de funciones varían según los diferentes tipos de compilación y convenciones de llamada, que se explican a continuación.
a. Reglas de convención de modificación de nombres de funciones en tiempo de compilación de C:
La convención de llamada __stdcall agrega un prefijo de guión bajo antes del nombre de la función de salida, seguido de un símbolo "@" y el número de sus parámetros Número de bytes en el formato _nombrefunción@número.
La convención de llamada __cdecl solo antepone al nombre de la función de salida un guión bajo en el formato _nombredefunción.
La convención de llamada __fastcall agrega un símbolo "@" antes del nombre de la función de salida, seguido de un símbolo "@" y el número de bytes de sus parámetros en el formato @nombredefunción@número.
Ninguno de ellos cambia el caso de los caracteres en el nombre de la función de salida, que es diferente de la convención de llamada PASCAL. La convención PASCAL genera nombres de funciones sin ninguna modificación y en letras mayúsculas.
b. Reglas de convención de modificación de nombres de funciones en tiempo de compilación de C++:
Convención de llamada a __stdcall:
1. nombre, seguido del nombre de la función;
2 El nombre de la función va seguido de "@@YG" para identificar el comienzo de la lista de parámetros, seguido de la lista de parámetros;
3. La lista de parámetros está representada por un código:
X——void,
D——char,
E——unsigned char, p>
F——corto,
H——int,
I——int sin signo,
J——largo,
K——unsigned long,
M——float,
N——double,
_N——bool,
....
PA—— - representa un puntero y el siguiente código indica el tipo de puntero. Si aparecen punteros del mismo tipo continuamente, se reemplazan por "0" y un. "0" representa una repetición;
4. El primer elemento en la tabla de parámetros es el tipo de valor de retorno de la función, seguido del tipo de datos del parámetro y el puntero está marcado antes del tipo de datos. se refiere a;
5. Después de la lista de parámetros, "@Z" marca el final del nombre completo. Si la función no tiene parámetros, termina con la marca "Z".
El formato es "?nombrefunción@@YG*****@Z" o "?nombrefunción@@YG*XZ",
Por ejemplo
int Test1 (char *var1, unsigned long)-----"?Test1@@YGHPADK@Z"
void Test2() -----"?Test2@@YGXXZ" p >
Convención de llamada __cdecl:
Las reglas son las mismas que la convención de llamada _stdcall anterior, excepto que el identificador de inicio de la tabla de parámetros cambia de "@@YG" arriba a "@@YA ".
Convención de llamada __fastcall:
Las reglas son las mismas que la convención de llamada _stdcall anterior, excepto que el identificador de inicio de la tabla de parámetros cambia de "@@YG" arriba a "@ @YI".
La declaración de funciones predeterminada de VC++ es "__cedcl", que solo puede ser llamada por C/C++.
Acerca de las funciones DLL
Hay dos tipos de funciones definidas en la biblioteca de enlaces dinámicos: función de exportación y función interna. Otros módulos pueden llamar a las funciones exportadas y las funciones internas se utilizan dentro del programa DLL en el que están definidas.
Hay varias formas de exportar funciones:
1. Método tradicional
Especifique la función o variable que se importará en la sección EXPORTAR del archivo de definición del módulo. .
El formato de sintaxis es el siguiente:
nombredeentrada[=nombreinterno] [@ordinal[NONAME]] [DATOS] [PRIVADO]
Dónde:
nombredeentrada es la función de salida O el nombre de los datos a los que se hace referencia;
nombre interno es el mismo que nombre de entrada;
@ordinal representa el número de secuencia (índice) en la tabla de salida;
NONAME solo se usa al presionar. El número de secuencia se usa al generar (el nombre de entrada no se usa);
DATA indica que la salida es un elemento de datos. Los programas que usan DLL para generar datos deben declarar. el elemento de datos como _declspec(DLLimport).
Entre los elementos anteriores, solo el elemento del nombre de la entrada es obligatorio y los demás se pueden omitir.
Para funciones "C", nombre de entrada puede ser equivalente al nombre de la función, pero para funciones "C++" (funciones miembro, funciones no miembros), nombre de entrada es un nombre modificado. Puede obtener los nombres decorados de las funciones que se generarán desde el archivo de imagen .map, o usar DUMPBIN /SYMBOLS para obtenerlos y luego escribirlos en el módulo de salida del archivo .def. DUMPBIN es una herramienta proporcionada por VC.
Si desea generar una clase "C++", escriba los datos que se generarán y los nombres modificados de los miembros en el archivo de definición del módulo .def.
2. Salida en la línea de comando
Especifique el parámetro de línea de comando /EXPORT para que el vinculador LINK genere las funciones relevantes.
3. Utilice el modificador _declspec(DLLexport) proporcionado por MFC
Agregue el modificador _declspec(DLLexport) antes de la declaración de la función, clase y datos que se generarán para indicar la salida. . __declspec(DLLexport) puede eliminar el prefijo de guión bajo del nombre de la función de salida según la convención de llamadas de C y la compilación de C. El "C" externo permite utilizar el estilo de compilación C en C++. Para definir una función "C" en "C++", debe agregar la palabra clave externa "C". Utilice "C" externa para indicar que la función utiliza compilación de C. Las funciones "C" exportadas se pueden llamar desde el código "C".
Por ejemplo, en un archivo C++, existe la siguiente función:
extern "C"
El nombre de la función de salida es: Prueba
MFC proporciona algunas macros para este propósito.
AFX_CLASS_IMPORT: __declspec(DLLexport)
AFX_API_IMPORT: __declspec(DLLexport)
AFX_DATA_IMPORT: __declspec(DLLexport)
AFX_CLASS_EXPORT: __declspec( DLLexport)
AFX_API_EXPORT: __declspec(DLLexport)
AFX_DATA_EXPORT: __declspec(DLLexport)
AFX_EXT_CLASS: #ifdef _AFXEXT
AFX_CLASS_EXPORT p>
#else
AFX_CLASS_IMPORT
AFX_EXT_API: #ifdef _AFXEXT
AFX_API_EXPORT
#else
AFX_API_IMPORT
AFX_EXT_DATA: #ifdef _AFXEXT
AFX_DATA_EXPORT
#else
AFX_DATA_IMPORT
Al igual que la macro AFX_EXT_CLASS, si se usa en la implementación de una aplicación DLL, representa la salida (porque _AFX_EXT está definido, generalmente especificando la opción /D_AFX_EXT en el parámetro de identificación del compilador; si se usa en una aplicación que usa una DLL, representa la entrada (_AFX_EXT no está definida);
Para exportar la clase completa, use _declspec(_DLLexpot) para la clase; para exportar las funciones miembro de la clase, use _declspec(_DLLexport) para la función. Por ejemplo:
clase AFX_EXT_CLASS CTextDoc: CDocumento público
{
…
}
extern "C " AFX_EXT_API void WINAPI InitMYDLL();
Entre estos métodos, es mejor usar el tercer método, que es conveniente y fácil de usar; el segundo es el primer método. Si se genera de acuerdo con el número de secuencia, la eficiencia de la llamada será mayor; el último Este es el segundo tipo.
Archivo de definición de módulo (.DEF)
El archivo de definición de módulo (.DEF) es un archivo de texto compuesto por una o más declaraciones de módulo que se utilizan para describir las propiedades de cada DLL. file Se deben incluir al menos las siguientes declaraciones de definición de módulo:
La primera declaración debe ser una declaración LIBRARY, indicando el nombre de la DLL
La declaración EXPORTS enumera los nombres de la DLL; funciones exportadas; las funciones que se exportarán. El nombre modificado aparece en EXPORTACIONES. Este nombre debe ser exactamente el mismo que el nombre de la función definida, para que obtenga un nombre de función sin ninguna modificación.
Puede utilizar la declaración DESCRIPCIÓN para describir el propósito de la DLL (esta oración es opcional
";"Comentar una línea (opcional); La relación entre un programa DLL y el programa que llama a su función de salida
1. La relación entre la DLL, el proceso y el hilo
El módulo DLL se asigna al virtual. espacio de direcciones del proceso que lo llama.
La memoria utilizada por la DLL se asigna desde el espacio de direcciones virtuales del proceso de llamada y solo los subprocesos de ese proceso pueden acceder a ella.
El identificador de la DLL puede ser utilizado por el proceso de llamada; el identificador del proceso de llamada puede ser utilizado por la DLL.
La DLL utiliza la pila del proceso de llamada.
2. Acerca del segmento de datos compartidos
El proceso de llamada puede acceder a las variables globales definidas por DLL; Cada proceso que utiliza la misma DLL tiene su propia instancia de las variables globales de la DLL. Si varios subprocesos acceden a la misma variable al mismo tiempo, debe usar un mecanismo de sincronización para una variable DLL; si desea que cada subproceso que usa la DLL tenga su propio valor, debe usar Thread Local Storage (TLS).
El propósito de configurar los atributos del segmento de datos también se puede lograr agregando instrucciones de precompilación al programa, o en la configuración del proyecto del entorno de desarrollo. A estas variables se les deben asignar valores iniciales; de lo contrario, el compilador los interpretará. los valores iniciales como no asignados. Las variables se colocan en un segmento llamado datos no inicializados.