Acessar DLLs no Excel
Aplica-se a: Excel 2013 | Office 2013 | Visual Studio
Você pode acessar um comando ou função DLL no Microsoft Excel de diversas maneiras:
Por meio de um módulo de código Microsoft VBA (Visual Basic for Applications) na qual a função ou comando foi disponibilizada usando uma instrução Declare.
Por meio de uma folha de macro XLM usando as funções CALL ou REGISTER.
Diretamente da planilha ou de um item personalizado na IU (interface do usuário).
Esta documenta��o n�o aborda as fun��es XLM. � recomend�vel que voc� use uma das duas outras abordagens.
Para ser acessada diretamente da planilha ou de um item personalizado na IU, primeiro a fun��o ou o comando dever�o ser registrados no Excel. Para saber mais sobre o registro de comandos e de fun��es, consulte Accessing XLL Code in Excel.
Chamar funções e comandos DLL do VBA
Voc� pode acessar fun��es e comandos DLL no VBA usando a instru��o Declare. Essa instru��o tem uma sintaxe para os comandos e outra para as fun��es.
Sintaxe 1 – comandos
[Public | Private] Declare Sub name Lib "libname" [Alias "aliasname"] [([arglist])]
Sintaxe 2 – funções
[Public | Private] Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type]
As palavras-chave Public e Private especificam o escopo da fun��o importada: o projeto inteiro do Visual Basic ou apenas o m�dulo do Visual Basic, respectivamente. O nome � o que voc� deseja usar no c�digo VBA. Se ele for diferente do nome na DLL, será necessário usar o especificador "nomedoalias" do Alias e nomear a função como exportada pela DLL. Se voc� quiser acessar uma fun��o de DLL por refer�ncia a um n�mero ordinal de DLL, dever� fornecer um nome de alias, que � o ordinal com o prefixo #.
Os comandos devem retornar void. As fun��es devem retornar tipos que o VBA possa reconhecer ByVal. Isso significa que alguns tipos s�o retornados com mais facilidade pela modifica��o dos argumentos existentes: cadeias de caracteres, matrizes, tipos definidos pelo usu�rio e objetos.
Observação
O VBA não pode verificar se a lista de argumentos e os estados retornados no módulo do Visual Basic são iguais aos codificados na DLL. Verifique isso com muito cuidado, pois um erro pode causar uma falha no Excel.
Quando os argumentos da fun��o ou do comando n�o forem passados por refer�ncia ou por ponteiro, dever�o ser precedidos pela palavra-chave ByVal na declara��o arglist. Quando uma fun��o C/C++ obtiver argumentos do ponteiro, ou quando uma fun��o C++ obtiver argumentos de refer�ncia, dever�o ser passados ByRef. A palavra-chave ByRef pode ser omitida das listas de argumentos porque � o padr�o no VBA.
Tipos de argumento no C/C++ e no VBA
Você deve observar o seguinte ao comparar as declarações dos tipos de argumentos no C/C++ e VBA.
Uma String do VBA é passada como um ponteiro para uma estrutura BSTR de cadeia de caracteres de bytes quando houver passado por ByVal e como um ponteiro para um ponteiro quando passada por ByRef.
Uma Variant do VBA que contém uma cadeia de caracteres é passada como um ponteiro para uma estrutura BSTR de cadeia de caracteres largos Unicode quando passada por ByVal e como um ponteiro para um ponteiro quando passada por ByRef.
O Integer do VBA é um tipo de 16 bits equivalente a um curto assinado no C/C++.
O Long do VBA é um tipo de 32 bits equivalente a um curto assinado no C/C++.
O VBA e o C++ permitem a definição de tipos de dados definidos pelo usuário, usando respectivamente as instruções Type e struct.
O VBA e o C++ oferecem suporte ao tipo de dados Variant, definido para o C++ nos arquivos de cabeçalho Windows OLE/COM, como VARIANT.
As matrizes do VBA são SafeArrays OLE, definidas para o C++ nos arquivos de cabeçalho Windows OLE/COM, como SAFEARRAY.
O tipo de dados Currency do VBA é passado como uma estrutura de tipo CY, definido no arquivo de cabeçalho de Windows wtypes.h, quando passado por ByVal e como um ponteiro para isso quando passado por ByRef.
No VBA, os elementos de dados nos tipos de dados definidos pelo usuário são compactados nos limites de 4 bytes, enquanto no Visual Studio, por padrão, eles são compactados nos limites de 8 bytes. Dessa forma, você deve inserir a definição de estrutura do C/C++ em um bloco #pragma pack(4) … #pragma pack()
para evitar erros de alinhamento de elementos.
A seguir, um exemplo de definições de tipo de usuário equivalentes.
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
O VBA d� suporte a uma s�rie de valores maior em alguns casos ao que o Excel consegue dar suporte. O double do VBA � compat�vel com IEEE, dando suporte a n�meros subnormais atualmente arredondados para baixo para zero na planilha. O tipo Date do VBA pode representar datas desde 1-Jan-0100 usando datas serializadas negativas. O Excel s� permite datas serializadas maiores ou iguais a zero. O tipo Currency do VBA � um inteiro de 64 bits dimensionado � pode obter precis�o sem suporte em doubles de 8 bytes e, portanto, n�o tem correspond�ncia na planilha.
O Excel somente passa Variants dos seguintes tipos para uma função definida pelo usuário do VBA.
Tipo de dados do VBA | Sinalizadores de bit do tipo Variant do C/C++ | Descrição |
---|---|---|
Duplo |
VT_R8 |
|
Boolean |
VT_BOOL |
|
Data |
VT_DATE |
|
Cadeia de caracteres |
VT_BSTR |
Cadeia de caracteres de byte Bstr OLE |
Intervalo |
VT_DISPATCH |
Referências de intervalos e células |
Variant com uma matriz |
VT_ARRAYVT_VARIANT |
Matrizes literais |
Ccy |
VT_CY |
Número inteiro de 64 bits dimensionado para permitir 4 casas decimais de precisão. |
Variant com erro |
VT_ERROR |
|
VT_EMPTY |
Argumentos omitidos ou células vazias |
Voc� pode verificar o tipo de uma Variant passado no VBA usando o VarType, exceto que a fun��o retorna o tipo dos valores do intervalo quando chamado com refer�ncias. Para determinar se uma Variant � um objeto de refer�ncia Range, voc� poder� usar a fun��o IsObject.
Voc� pode criar Variants com matrizes de variantes no VBA de um Range ao atribuir sua propriedade Value a uma Variant. Todas as c�lulas no intervalo de origem formatadas como a moeda padr�o para as configura��es regionais em vigor no momento ser�o convertidas em elementos da matriz do tipo Currency. Todas as c�lulas formatadas como datas ser�o convertidas em elementos de matriz do tipo Date. As c�lulas com cadeias de caracteres ser�o convertidas em Variants BSTR de caractere longo. As c�lulas com erros ser�o convertidas em Variants do tipo VT_ERROR. As células que contêm Valor BooleanoVerdadeiro ou Falso são convertidas em Variantes do tipo VT_BOOL.
Observação
[!OBSERVA��O] A Variant armazena True como �1 e False como 0. Os n�meros n�o s�o formatados como datas ou valores monet�rios s�o convertidos em Variants do tipo VT_R8.
Argumentos de variant ou de cadeia de caracteres
O Excel funciona internamente com cadeias de caracteres Unicode de caractere longo. Quando uma fun��o definida pelo usu�rio do VBA � declarada como obtendo um argumento de String, o Excel converte a cadeia de caracteres fornecida em uma cadeia de caracteres de byte de uma forma espec�fica da localidade. Se voc� quiser que uma cadeia de caracteres Unicode seja passada para sua fun��o, sua fun��o definida pelo usu�rio do VBA dever� aceitar um argumento de Variant em vez de um de String. Sua fun��o DLL poder� ent�o aceitar a cadeia de caracteres de caractere longo BSTR Variant do VBA.
Para devolver cadeias Unicode ao VBA a partir de uma DLL, deve modificar um argumento de cadeia variante . Para que isto funcione, tem de declarar a função DLL como tendo um ponteiro para a Variante e no código C/C++ e declarar o argumento no código VBA como ByRef varg As Variant
. A memória de cadeia antiga deve ser libertada e o novo valor de cadeia criado com as funções de cadeia OLE Bstr apenas na DLL.
Para retornar uma cadeia de caracteres de byte para o VBA de uma DLL, voc� dever� modificar um argumento BSTR de cadeia de caracteres de byte existente. Para que isso funcione, voc� dever� declarar a fun��o DLL como obtendo um ponteiro para um ponteiro para o BSTR e em seu c�digo C/C++ e declarar o argumento no c�digo VBA como " ByRef varg As String".
Voc� s� deve manipular as cadeias de caracteres passadas dessas maneiras do VBA usando as fun��es de cadeia de caracteres BSTR OLE para evitar problemas relacionados � mem�ria. Por exemplo, ser� necess�rio chamar SysFreeString para liberar a mem�ria antes de substituir o que foi passado na cadeia de caracteres e SysAllocStringByteLen ou SysAllocStringLen para alocar espa�o para uma nova cadeia de caracteres.
Voc� pode criar erros de planilha do Excel como Variants no VBA usando a fun��o CVerr com argumentos como os mostrados na tabela a seguir. Os erros de planilha tamb�m pode ser retornados para o VBA de uma DLL usando Variants do tipo VT_ERROR e com os valores a seguir no campo ulVal.
Erro | Valor da 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 |
Observe que o valor fornecido de Variant ulVal é equivalente ao valor do argumento CVerr mais o hexadecimal x800A0000.
Como chamar funções DLL diretamente da planilha
Voc� n�o pode acessar fun��es DLL Win32 da planilha sem, por exemplo, usar o VBA ou o XLM como interfaces ou sem permitir que o Excel conhe�a a fun��o, seus argumentos e seu tipo de retorno com anteced�ncia. O processo de fazer isso se chama registro.
Veja a seguir as maneiras para acessar as funções de uma DLL na planilha:
Declare a função em VBA, como descrito anteriormente, e acesse-a por meio de uma função VBA definida pelo usuário.
Chame a função DLL usando CALL em uma planilha de macro XLM e acesse-a por uma função XLM definida pelo usuário.
Use um comando XLM ou VBA para chamar a função XLM REGISTER, que fornece as informações que o Excel precisa para reconhecer a função quando ela é inserida em uma célula da planilha.
Transforme a DLL em um XLL e registre a função usando a função API de C xlfRegister quando o XLL estiver ativado.
A quarta abordagem � autocontida: o c�digo que registra as fun��es e o c�digo da fun��o est�o contidos no mesmo projeto de c�digo. Fazer alterações no suplemento não envolve fazer alterações em uma planilha XLM ou em um módulo de código VBA. Para fazer isso de uma maneira bem gerenciada mantendo-se no limite dos recursos da API do C, você deverá transformar sua DLL em um XLL e carregar o suplemento resultante usando o Gerenciador de Suplementos. Isso permite que o Excel chame uma função exposta por sua DLL quando o suplemento é carregado ou ativado, a partir do qual você poderá registrar todas as funções contidas em seu XLL e realizar a inicialização de qualquer outra DLL.
Chamando comandos de DLL diretamente do Excel
Os comandos Win32 DLL não são acessíveis diretamente nos menus e caixas de diálogo do Excel sem a existência de uma interface, como o VBA, ou sem os comandos serem registrados com antecedência.
Estas são as maneiras para acessar os comandos de uma DLL:
Declare o comando no VBA como descrito anteriormente e acesse-o por meio de uma macro do VBA.
Chame o comando da DLL usando CALL em uma folha de macros XLM e acesse-o por meio de uma macro XLM.
Use um comando XLM ou VBA para chamar a função de XLM REGISTER, que fornece as informações que o Excel precisa para reconhecer o comando quando ele é inserido na caixa de diálogo que espera o nome de um comando de macro.
Transforme a DLL em XLL e registre o comando usando a função API de C xlfRegister.
Como discutido anteriormente no contexto de fun��es de DLL, a quarta abordagem � a mais autocontida, mantendo o c�digo de registro pr�ximo ao c�digo do comando. Para fazer isso, você deve transformar sua DLL em um XLL e carregar o suplemento resultante usando o Gerenciador de Suplementos. O registro de comandos dessa maneira também permite que você anexe o comando a um elemento da interface do usuário, como um menu personalizado ou configure uma interceptação de evento que chame o comando em um determinado pressionamento de tecla ou outro evento.
Todos os comandos do XLL registrados com o Excel são considerados pelo Excel da forma a seguir.
int WINAPI my_xll_cmd(void)
{
// Function code...
return 1;
}
Observação
[!OBSERVA��O] O Excel ignorar� o valor de retorno, a menos que ele seja chamado de uma folha de macros XLM; nesse caso, o valor de retorno ser� convertido em TRUE ou em FALSE. Dessa forma, voc� dever� retornar 1 se o seu comando tiver sido executado com �xito e 0 caso ele tenha falhado ou tenha sido cancelado pelo usu�rio.
Memória de DLL e várias instâncias de DLL
Quando um aplicativo carrega uma DLL, o c�digo execut�vel da DLL � carregado na pilha global de forma que possa ser executado, e � alocado um espa�o na pilha global para suas estruturas de dados. O Windows usa o mapeamento de mem�ria para fazer com que essas �reas da mem�ria apare�am como se estivessem no processo do aplicativo, de forma que o aplicativo possa acess�-las.
Se um segundo aplicativo carregar a DLL, o Windows n�o far� outra c�pia do c�digo execut�vel da DLL, j� que a mem�ria � somente leitura. O Windows mapeia a mem�ria do c�digo execut�vel da DLL para os processos de ambos os aplicativos. No entanto, ele aloca um segundo espa�o para uma c�pia privada das estruturas de dados da DLL e mapeia essa c�pia apenas para o segundo processo. Isso garante que os aplicativos n�o interfiram nos dados de DLL um do outro.
Isso significa que os desenvolvedores n�o precisa se preocupar com a possibilidade de as vari�veis est�ticas e globais e as estruturas de dados serem acessados por mais de um aplicativo, ou por mais de uma inst�ncia do mesmo aplicativo. Todas as inst�ncias de todos os aplicativos obt�m sua pr�pria c�pia dos dados da DLL.
Os desenvolvedores de DLL n�o precisam se preocupar com o fato de a mesma inst�ncia do aplicativo chamar sua DLL v�rias vezes de threads diferentes, porque isso pode resultar em conten��o dos dados da inst�ncia. Saiba mais em Gerenciamento de Memória no Excel.