Obtener acceso a DLL en Excel
Hace referencia a: Excel 2013 | Office 2013 | Visual Studio
Puede obtener acceso a una función DLL o comando en Microsoft Excel de varias formas:
A través del módulo de código Microsoft Visual Basic para aplicaciones (VBA) en el que la función o el comando está disponible mediante una instrucción Declare.
A través de una hoja de macros XLM con las funciones CALL o REGISTER.
Directamente desde la hoja de cálculo o de un elemento personalizado de la interfaz de usuario (IU).
Esta documentaci�n no trata las funciones XLM. Se recomienda que use uno de los dos enfoques.
Para acceder directamente desde la hoja de c�lculo o desde un elemento personalizado de la interfaz de usuario, la funci�n o el comando se debe registrar primero con Excel. Para obtener informaci�n sobre el registro de comandos y funciones, consulte Acceso al c�digo XLL en Excel (en ingl�s).
Llamar a funciones y comandos DLL desde VBA
Puede acceder a funciones y comandos DLL de VBA con la instrucci�n Declare. Esta instrucci�n tiene una sintaxis para los comandos y otra para las funciones.
Sintaxis 1: comandos
[Public | Private] Declare Sub name Lib "libname" [Alias "aliasname"] [([arglist])]
Sintaxis 2: funciones
[Public | Private] Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]
Las palabras clave opcionales Public y Private especifican el �mbito de la funci�n importada: todo el proyecto de Visual Basic o el m�dulo de Visual Basic, respectivamente. El nombre es el nombre que quiere usar en el c�digo VBA. Si esto difiere del nombre del DLL, debe usar el especificador de Alias "aliasname" y proporcionar el nombre de la función como exportada por el DLL. Si quiere acceder a una funci�n DLL por referencia para un n�mero ordinal DLL, debe proporcionar un nombre de alias, que es el ordinal con el prefijo #.
Los comandos deben devolver void. Las funciones deben devolver tipos que VBA pueda reconocer ByVal. Esto significa que algunos tipos se devuelven m�s f�cilmente modificando los argumentos locales: cadenas, matrices, tipos definidos por el usuario y objetos.
Nota:
VBA no puede comprobar que la lista de argumentos y el retorno que se indica en el módulo de Visual Basic son los mismos según la codificación de DLL. Debe comprobar usted mismo con cuidado, ya que un error podr�a provocar el bloqueo de Excel.
Cuando la referencia o el puntero no pasan los argumentos de la funci�n o del comando, deben ir precedidos por la palabra clave ByVal en la declaraci�n arglist. Cuando una funci�n de C o C++ toma argumentos de puntero o una funci�n de C++ toma argumentos de referencia, deben pasar ByRef. La palabra clave ByRef se puede omitir de las listas de argumentos porque es el valor predeterminado en VBA.
Tipos de argumento en C/C++ y VBA
Debe tener en cuenta lo siguiente cuando se comparan las declaraciones de tipos de argumentos en C o C++ y VBA.
Se pasa un String de VBA como un puntero a una estructura BSTR de cadena de bytes al pasar ByVal, y como un puntero a un puntero al pasar ByRef.
Variant de VBA que contiene una cadena se pasa como puntero a una estructura BSTR de cadena de caracteres anchos Unicode al pasar ByVal, y como un puntero a un puntero al pasar ByRef.
Integer de VBA es un tipo de 16 bits equivalente a un signed short en C/C++.
Long de VBA es un tipo de 32 bits equivalente a un signed int en C/C++.
Tanto VBA como C/C++ permiten la definición de tipos de datos definidos por el usuario, con las instrucciones Type y struct respectivamente.
Tanto VBA como C/C++ admiten el tipo de datos Variant, definidos para C/C++ en los archivos de encabezado de Windows OLE/COM como VARIANT.
Las matrices VBA son OLE SafeArrays, definidas para C/C++ en los archivos de encabezado de Windows OLE/COM como SAFEARRAY.
El tipo de datos Currency de VBA se pasa como estructura de tipo CY, definido en el archivo wtypes.h del archivo de encabezado Windows, cuando pasa ByVal, y como un puntero para este cuando pasa ByRef.
En VBA, los elementos de los tipos de datos definidos por el usuario se empaquetan en límites de 4 bytes mientras que, en Visual Studio, de forma predeterminada, se empaquetan en límites de 8 bytes. Por lo tanto, debe incluir la definición de la estructura de C/C++ en un bloque #pragma pack(4) … #pragma pack()
para evitar que los elementos estén alineados de forma incorrecta.
El siguiente es un ejemplo de definiciones de tipo de usuario equivalente.
Type VB_User_Type
i As Integer
d As Double
s As String
End Type
#pragma pack(4)
struct C_user_type
{
short iVal;
double dVal;
BSTR bstr; // VBA String type is a byte string
}
#pragma pack() // restore default
VBA admite una amplia gama de valores, en algunos casos, m�s de los que admite Excel. El doble de VBA es compatible con IEEE y admite n�meros por debajo de lo normal redondeados hacia abajo a cero en la hoja de c�lculo. El tipo Date de VBA puede representar fechas anteriores al uno de enero de 0100 con fechas serializadas negativas. Excel solo permite fechas serializadas mayores o iguales a cero. El tipo Currency de VBA, un entero escalado de 64 bits, puede alcanzar una precisi�n no admitida por los dobles de 8 bytes y, por lo tanto, no coinciden en la hoja de c�lculo.
Excel solo pasa las variantes de los siguientes tipos a una función definida por el usuario de VBA.
Tipo de datos VBA | Marcas de bits de tipo Variant de C/C++ | Descripción |
---|---|---|
Doble |
VT_R8 |
|
Booleano |
VT_BOOL |
|
Fecha |
VT_DATE |
|
String |
VT_BSTR |
Cadena de bytes Bstr OLE |
Range |
VT_DISPATCH |
Referencias de celda y de rango |
Variante que contiene una matriz |
VT_ARRAYVT_VARIANT |
Matrices literales |
Ccy |
VT_CY |
Entero de 64 bits que se escala para permitir cuatro posiciones decimales de precisión. |
Variante que contiene un error |
VT_ERROR |
|
VT_EMPTY |
Celdas vacías o argumentos omitidos |
Puede comprobar el tipo de una variante pasada en VBA con VarType, excepto que la funci�n devuelve el tipo de los valores del rango cuando se llama con referencias. Para determinar si una Variant es un objeto de referencia Range, puede usar la funci�n IsObject.
Puede crear Variants que contenga matrices de variantes en VBA desde Range asignando la propiedad Value a Variant. Las celdas del rango de origen que tengan formato de moneda est�ndar para la configuraci�n regional en vigor en el momento, se convierten en elementos de matriz de tipo Currency. Las celdas con formato como fechas se convierten en elementos de la matriz de tipo Date. Las celdas que contienen cadenas se convierten en variantes BSTR de caracteres anchos. Las celdas que contienen errores se convierten en Variants de tipo VT_ERROR. Las celdas que contienen BooleanTrue o False se convierten en Variants de tipo VT_BOOL.
Nota:
[!NOTA] Variant almacena True como -1 y False como 0. Los n�meros sin formato como fechas o cantidades de moneda se convierten en variantes de tipo VT_R8.
Variante y argumentos de cadena
Excel funciona internamente con cadenas de caracteres anchos Unicode. Cuando se declara una funci�n definida por el usuario VBA como que toma un argumento String, Excel convierte la cadena proporcionada en una cadena de bytes de forma espec�fica de la configuraci�n regional. Si quiere que la funci�n se pase a una cadena Unicode, la funci�n definida por el usuario VBA debe aceptar Variant en lugar de un argumento String. Luego, la funci�n DLL la cadena de car�cter ancho BSTR Variant VBA.
Para devolver las cadenas Unicode a VBA desde un DLL, debe modificar un argumento de cadena Variant local. Para que esto funcione, debe declarar la función DLL como tomar un puntero a Variant y en el código de C/C++, y declarar el argumento en el código VBA como ByRef varg As Variant
. Debe liberar la memoria de cadena antigua y el nuevo valor de cadena creado con las funciones de cadena OLE Bstr solo en DLL.
Para devolver una cadena de bytes a VBA desde un DLL, debe modificar un argumento BSTR de cadena de bytes local. Para que funcione, debe declarar la funci�n DLL que toma un puntero para un puntero en BSTR y en el c�digo de C/C++, y declarar el argumento en el c�digo VBA como ByRef varg As String.
Solo debe gestionar las cadenas que se pasan de estas formas desde VBA con las funciones de cadena OLE BSTR para evitar problemas relacionados con la memoria. Por ejemplo, debe llamar a SysFreeString para liberar la memoria antes de sobrescribir la cadena pasada, y SysAllocStringByteLen o SysAllocStringLen para asignar espacio para una nueva cadena.
Puede crear errores de hoja de c�lculo de Excel como Variants en VBA con la funci�n CVerr con argumentos, como se muestra en la siguiente tabla. Los errores de la hoja de c�lculo tambi�n se pueden devolver a VBA desde un DLL con Variants de tipo VT_ERRORy con los siguientes valores en el campo ulVal.
Error | Valor Variant ulVal | Argumento CVerr |
---|---|---|
#NULL! |
2148141008 |
2000 |
#DIV/0! |
2148141015 |
2007 |
#VALUE! |
2148141023 |
2015 |
#REF! |
2148141031 |
2023 |
#NAME? |
2148141037 |
2029 |
#NUM! |
2148141044 |
2036 |
#N/A |
2148141050 |
2042 |
Tenga en cuenta que el valor ulVal variante dado equivale al valor de argumento CVerr más x800A0000 hexadecimal.
Llamar a funciones DLL directamente desde la hoja de cálculo
No puede acceder a funciones DLL de Win32 desde la hoja de c�lculo sin, por ejemplo, usar VBA o XLM como interfaces, o sin dejar que Excel conozca la funci�n, sus argumentos y el tipo devuelto por adelantado. Este proceso se denomina registro.
Las formas en que se puede acceder a las funciones de un DLL en la hoja de cálculo son las siguientes:
Declarar la función de VBA como descrita anteriormente y acceder a ella a través de una función definida por el usuario VBA.
Llamar a la función DLL con CALL en una hoja de macros XLM y acceder a ella a través de una función definida por el usuario XLM.
Usar un comando XLM o VBA para llamar a la función REGISTER de XML, que proporciona la información que Excel necesita para reconocer la función cuando se introduce en una celda de la hoja de cálculo.
Convertir el DLL en un XLL y registrar la función con la función xlfRegister de la API de C cuando se activa XLL.
El cuarto enfoque es independiente: el c�digo que registra las funciones y el c�digo de funci�n se incluyen en el mismo proyecto de c�digo. Realizar cambios en el complemento no implica realizar cambios a una hoja de XLM o en un módulo de código VBA. Para hacerlo de manera administrada manteniéndose dentro de las capacidades de la API de C, debe convertir el DLL en un XLL y cargar el complemento resultante con Administrador de complementos. Esto permite que Excel llame a una función que expone el DLL cuando se carga o activa el complemento, desde el que puede registrar todas las funciones que contiene el XLL y realizar cualquier otra inicialización del DLL.
Llamar a los comandos DLL directamente desde Excel
No se puede acceder directamente a los comandos del DLL de Win32 desde los menús y los cuadros de diálogo de Excel sin que haya una interfaz, como VBA, o sin los comandos que se registran con antelación.
Las formas en las que acceder a los comandos de un DLL son las siguientes:
Declarar el comando de VBA, como se describió anteriormente, y acceder a él a través de una macro de VBA.
Llamar al comando DLL con CALL en una hoja de macros XLM y acceder a él a través de una macro XLM.
Usar un comando XLM o VBA para llamar a la función REGISTER de XML, que proporciona la información que Excel necesita para reconocer el comando cuando se introduce en un cuadro de diálogo que se espera el nombre de un comando de macros.
Convertir el DLL en un XLL y registrar el comando mediante la función xlfRegister de la API de C.
Como se ha explicado anteriormente, en el contexto de las funciones DLL, el cuarto enfoque es el m�s independiente ya que mantiene el c�digo de registro cerca del c�digo de comando. Para ello, debe convertir el DLL en un XLL y cargar el complemento resultante con el Administrador de complementos. Registrar los comandos de esta manera también le permite adjuntar el comando a un elemento de la interfaz de usuario, como un menú personalizado, o configurar una captura de eventos que llame al comando en una pulsación de tecla determinada u otro evento.
Excel asume que todos los comandos XLL registrados con Excel tienen el siguiente formato.
int WINAPI my_xll_cmd(void)
{
// Function code...
return 1;
}
Nota:
[!NOTA] Excel omite el valor devuelto a menos que se le llame desde una hoja de macros XLM, en cuyo caso el valor devuelto se convierte a TRUE o FALSE. Por lo tanto, debe devolver 1 si el comando se ejecuta correctamente y 0 si tiene errores o el usuario lo cancela.
Memoria de DLL e instancias de varios DLL
Cuando una aplicaci�n carga un DLL, el c�digo ejecutable del DLL se carga en el mont�n global para que se pueda ejecutar, y se asigna espacio en el mont�n global para las estructuras de datos. Windows usa la asignaci�n de memoria para que estas �reas de memoria aparezcan como si estuvieran en el proceso de la aplicaci�n, para que esta pueda acceder a ella.
Si una segunda aplicaci�n carga el DLL, Windows no crea otra copia del c�digo ejecutable de DLL, ya que la memoria es de solo lectura. Windows asigna la memoria de c�digo ejecutable de DLL a los procesos de ambas aplicaciones. Sin embargo, asigna un segundo espacio para una copia privada de las estructuras de datos del DLL y asigna esta copia solo al segundo proceso. Esto garantiza que ninguna aplicaci�n interfiere con los datos del DLL de la otra.
Esto significa que los desarrolladores de DLL no tienen que preocuparse de las variables globales y est�ticas ni de las estructuras de datos a las que acceden varias aplicaciones, o m�s de una instancia de la misma aplicaci�n. Cada instancia de cada aplicaci�n obtiene su propia copia de los datos del DLL.
Los desarrolladores de DLL no tienen que preocuparse por la misma instancia de una aplicaci�n que llama al DLL varias veces desde distintos subprocesos, ya que esto puede provocar la contenci�n de los datos de esa instancia. Para obtener más información, consulte Administración de memoria en Excel.