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 True ou Falseboolianos 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 retornar cadeias de caracteres Unicode ao VBA de uma DLL, você deve modificar um argumento de cadeia de caracteres Variant em vigor. Para que isso funcione, você deve declarar a função DLL como levando um ponteiro para a Variant e no código C/C++ e declarar o argumento no código VBA como ByRef varg As Variant. A memória de cadeia de caracteres antiga deve ser lançada e o novo valor de cadeia de caracteres criado usando as funções de cadeia de caracteres OLE Bstr somente 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.

Confira também