ID do artigo: 106553 - Última revisão: quinta-feira, 15 de julho de 2004 - Revisão: 2.1

Como gravar DLLs C e chamada-los a partir do Visual Basic

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sumário

Este artigo descreve como usar DLLs com o Visual Basic. Ele aborda os seguintes problemas:

A seção

  • 1.0 o que é uma DLL?
  • 1.1 Por que usar uma DLL?
  • 1.2 Anatomia de uma DLL.
  • 1.3 Problemas de gerenciamento de memória DLL.
  • 1.4 Criando uma DLL usando o Visual C++.
  • DLL de 1.5 exemplo C.

Seção B

  • DLLs de chamada 2.0 a partir do Visual Basic.
  • Parâmetros de DLL 2.1.
  • Solucionando problemas de 2.2.
  • Programa de chamada do 2.3 exemplo Visual Basic.

Mais Informações

UMA SEÇÃO

1.0 o que é uma DLL?

DLLs (bibliotecas de vínculo dinâmico) são um aspecto importante do Windows. Uma DLL contém funções que o programa executável pode chamar durante a execução. Em outras palavras, uma DLL é uma biblioteca de funções que seu programa pode vincular com dinamicamente.

Um link pode ser estático ou dinâmico. Vínculos estáticos não são alterados. Todas as informações endereço necessárias por seu programa para acessar a função de biblioteca é fixo quando o arquivo executável é criado e permanece inalterado durante a execução.

Vínculos dinâmicos são criados conforme necessário. Quando seu programa necessita de uma função que não está no arquivo executável, o Windows carrega a biblioteca de vínculo dinâmico (DLL), disponibilizar todas as suas funções para seu aplicativo. Nesse momento, o Windows resolve o endereço de cada função e links-lo dinamicamente para seu aplicativo.

Todos os controles personalizados usados no Visual Basic são DLLs. A única diferença é que eles exigem tratamento especial em termos de mensagens recebidas a partir do Visual Basic.

1.1 Por que usar DLLs?

Aqui estão quatro motivos por que você deseje usar uma DLL:

  • Acesso a funções de tempo de execução C:

    A biblioteca de tempo de execução C tem muitas funções úteis que não estaria disponíveis para programadores de Visual Basic não eram para DLLs. Por exemplo, a função _dos_getdiskfree permite que você calcular a quantidade total de espaço em disco e o espaço livre disponível em uma unidade.
  • Funções de acesso a API (Application Programming Interface) do Windows que requer retorno de chamada rotinas:

    Algumas funções de API do Windows exigem uma função de retorno de chamada. Uma função de retorno de chamada é uma função que Windows chamará ao executar a API chamada. Um exemplo desse tipo de função é EnumTaskWindows, que fornecerá a alça de todas as janelas que pertencem a uma determinada tarefa.
  • Velocidade:

    C é uma linguagem totalmente compilada que funciona em um nível está bastante próximo código de máquina nativo. Isso significa que a execução de programas que são bem escrita em C será rápida.
  • Carregar na utilização:

    Código e dados de uma DLL são carregados somente quando necessário. Uma DLL pode ser organizada de modo que somente os componentes necessários são carregados em oposição a DLL inteira. Isso reduz a quantidade de memória necessária e o tempo gasto para carregar.

1.2 Anatomia de uma DLL

Cada DLL deve conter uma função LibMain e deve conter um procedimento de sair do Windows (WEP) juntamente com as funções exportadas que podem ser chamados por um programa executável.

  • LibMain:

    Uma DLL deve conter a função LibMain. A função LibMain é chamada pelo sistema para inicializar a DLL. LibMain é chamado somente uma vez--quando o primeiro programa que requer a DLL é carregado. Estes são os parâmetros passados para LibMain:
    -HANDLE: Identificador para a instância da DLL.
    -WORD: Segmento de dados da biblioteca.
    -WORD: Tamanho de pilha.
    -LPSTR: parâmetros de linha de comando.
  • WEP:

    O WEP (Procedure de sair do Windows) executa a limpeza para uma DLL antes que a biblioteca seja descarregada. Embora uma função do WEP era necessária para cada DLL em versões anteriores do sistema operacional Windows, para a versão 3.1 é opcional. Um WEP deve ser incluído na definição de módulo arquivo (.def) no Visual C, por exemplo:
    EXPORTAÇÕES
    WEP
  • Exportadas funções:

    Essas são as funções que você deseja chamar da sua DLL. Eles são indicados por _export. _export é usado para compatibilidade com versões anteriores. Todas as funções que deseja chamar também devem constar no arquivo (.def) de sua DLL.

Problemas de gerenciamento de memória DLL 1.3

Use o modelo de memória grande.

C armazena todas as variáveis definidas como estática ou global (definido fora de uma função) na pilha do programa espaço e C armazena todas as outras variáveis na pilha.

No modelo de pequeno e médio, todos os ponteiros são próximo por padrão. Isso significa que os dados são acessados por deslocamentos de 16 bits para o registrador de segmento (DS) de dados ou o registrador de segmento (II) de pilha. Infelizmente, o compilador não tem como saber se o deslocamento é de serviço de diretório ou o II. Na maioria dos programas esse não seria um problema porque o DS e SS aponte para o mesmo segmento. Uma DLL, no entanto, é um caso especial.

Uma DLL tem seu próprio segmento de dados, mas compartilha sua pilha com o programa de chamada. Isso significa que o DS e o SS não apontam para o mesmo local. A solução mais fácil para esse problema é criar a DLL no modelo de memória grande onde todas as variáveis são referenciadas por um valor de 32 bits.

Por que alocar memória dinamicamente?

Alocar memória dinamicamente é uma técnica amigável do Windows. Declaração de matrizes grandes de dados ocupa espaço na pilha do programa, que é limitada a 64 K, ou segmento de dados do programa, que desperdiça espaço em disco e memória do Windows. É melhor para Windows pedir a memória quando você precisa dele e liberá-lo quando tiver terminado.

Alocando memória

No Windows, você pode alocar dinamicamente dois tipos de memória, local e global. Memória local está limitada a 64 K e no caso de uma DLL, local de memória é compartilhada com o programa que chamou a DLL. Memória global é toda a memória disponível para o Windows após ele foi carregado.

Local de memória é alocada e gerenciados usando o LocalAlloc, LocalLock LocalUnlock e LocalFree funções--como no exemplo:
   char* pszBuffer;
   ....
   pszBuffer = (char *) LocalAlloc (LPTR, 20);
   ...
   LocalFree (pszBuffer);
				
é mais rápido alocar a memória local que alocar memória global. Mas alocações do heap local são limitadas a 64 K, que deve ser compartilhado entre todos os programas que estão chamando a DLL. É melhor usar a memória local quando pequeno, curtos lived blocos de memória são necessários.

Global de memória é alocada e gerenciados usando o GlobalAlloc, GlobalLock GlobalUnlock e GlobalFree funções--como no exemplo:
   HGLOBAL hglb;
   char* pszBuffer;

   hglb = GlobalAlloc (GHND, 2048);
      // GHND allocates the memory as moveable and
      // initialized to 0
      // 2048 is the amount of memory to be allocated...
   pszBuffer = GlobalLock (hglb);
   ...
   GlobalUnlock (hglb);
   GlobalFree (hglb);
				
GlobalAlloc A função aloca memória em múltiplos de 4 K.

Se você quiser compartilhar a memória alocada na DLL com outros programas, você deve alocá-lo usando o sinalizador GMEM_SHARED. Se você quiser compartilhar a memória através de DDE, você deve alocar usando o sinalizador GMEM_DDESHARE.

Ser cuidado ao armazenar dados em variáveis estáticas

Se você tentar armazenar dados em uma DLL usando variáveis globais ou estáticas, não se surpreenda se esses valores foram alterados quando você chama sua DLL em seguida. Os dados armazenados em dessa forma serão comuns a todos os aplicativos que acessam essa DLL. Não importa como muitos aplicativos usam uma DLL, há apenas uma instância da DLL. A melhor maneira para contornar esse problema é retornar as estruturas da DLL e passá-las em novamente quando forem necessários.

Identificadores de arquivo

Não é possível compartilhar identificadores de arquivo entre aplicativos ou DLLs. Cada aplicativo tem sua própria tabela de identificador de arquivo. Para que os dois aplicativos usam o mesmo arquivo usando uma DLL, ele devem ambos abrir o arquivo individualmente.

1.4 Criação de uma DLL usando o Visual C++

Aqui estão as etapas necessárias para criar uma DLL usando o Visual C++:

  1. Inicie o Visual C++.
  2. Crie um novo projeto, escolha Novo no menu Project. Selecione as seguintes opções:

    • Defina o tipo de projeto como "Windows biblioteca de vínculo dinâmico (.dll)"
    • Desmarque a caixa de seleção "Usar Microsoft Foundation Classes".
    Você também pode definir ou exibir essas opções mais tarde escolhendo Project no menu de opções.
  3. Adicione os arquivos existentes .C e .def para o projeto, usando a caixa de diálogo que surge quando você escolhe Edit a partir do menu Project. Ou insira seu código diretamente na janela de edição do Visual C++. (Consulte o código de exemplo .C e .def listado abaixo.)
  4. No menu Project, escolha Build <yourname>.dll opção.

DLL de 1.5 exemplo C

A seguinte DLL contém a função GetDiskInfo, que pode ser chamada a partir do Visual Basic. Ela retornará o espaço em disco disponível, o nome atual da unidade e o nome do volume.
      C Code Example, DISKINFO.C:

   #include <windows.h>
   #include <dos.h>

   int CALLBACK LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize,
   LPSTR lpszCmdLine)

   // The following is required only under Windows version 3.1
   // Win32 does not require or support UnlockData()
   {
      if (wHeapSize > 0)
         UnlockData (0);  //Unlocks the data segment of the library.
      return 1;
   }

   void __export CALLBACK GetDiskInfo (char *cDrive, char *szVolumeName,
   unsigned long *ulFreeSpace)
   {
      unsigned drive;
      struct _diskfree_t driveinfo;
      struct _find_t c_file;

      _dos_getdrive (&drive);
      _dos_getdiskfree( drive, &driveinfo );

      if (!_dos_findfirst( "*.*", _A_VOLID, &c_file ))
         wsprintf( szVolumeName, "%s", c_file.name);
      else
         wsprintf ( szVolumeName, "NO LABEL");

      *cDrive = drive + 'A' -1;

      *ulFreeSpace = (unsigned long) driveinfo.avail_clusters * (unsigned
         long) driveinfo.sectors_per_cluster * (unsigned long)
         driveinfo.bytes_per_sector;
   }
				
use o seguinte arquivo DISKINFO.DEF no Visual C++:
LIBRARY diskinfo
Descrição 'GetDiskInfo podem ser chamadas partir do Visual Basic '
EXETYPE WINDOWS 3.1
CÓDIGO PRELOAD MOVÍVEIS DISCARDABLE
DADOS PRELOAD ÚNICO MÓVEL
HEAPSIZE 4096
EXPORTAÇÕES
GetDiskInfo @ 1
Observação: O nome LIBRARY no arquivo .def deve ser o mesmo que o nome do arquivo DLL, senão lhe dará do Visual Basic "Erro ao carregar DLL". Por exemplo, crie o arquivo DISKINFO.DLL usando a instrução LIBRARY DISKINFO no arquivo .def acima.

SEÇÃO B

DLLs de chamada 2.0 a partir do Visual Basic

No Visual Basic, todas as funções, incluindo funções DLL, que você deseja fazer a chamada deve ser declarado primeiro usando a instrução Declare. Você pode declarar suas funções na seção declarações de um formulário ou um módulo. Se você declarar um procedimento DLL ou função em um formulário, é particular para esse formulário. Para tornar pública, você deve declará-lo em um módulo. A seguir está um exemplo de instrução Declare:
   Declare Sub getdiskinfo Lib "c:\somepath\diskinfo.dll"
      (ByVal mydrive As String, ByVal myvolume As String, free As Long)
				
você deve inserir a instrução Declare toda como um única linha. Essa determinada instrução Declare Declara o procedimento definido pelo usuário que GETDISKINFO localizado no usuário criado DISKINFO.DLL arquivo.

Depois de declarar a função, você pode chamar e usar a função assim como você poderia chamar e usar uma função do Visual Basic.

Parâmetros DLL 2.1

Como DLLs normalmente são escritas em C, DLLs podem usar uma ampla variedade de parâmetros não diretamente suportado pelo Visual Basic. Como resultado, quando passar parâmetros, o programador tem que localizar o tipo de dados apropriado para passar.

Passando argumentos por valor ou por referência

Por padrão, o Visual Basic passa todos os argumentos por referência. (Ao passar por referência, Visual Basic fornece um endereço de distância de 32 bits). No entanto, muitas funções DLL esperam um argumento para ser passada por valor. Isso pode ser obtido, colocando a palavra-chave ByVal na frente da declaração de argumento.

As seções a seguir mostram como converter parâmetros para o Visual Basic.

Parâmetros numéricos de 8 a 16 bits

Passe parâmetros de numéricos de 8 a 16 bits (int, int curto, não assinado, unsigned short, BOOL e WORD) como Integer.

Parâmetros numéricos de 32 bits

Passar parâmetros numéricos de 32 bits (tempo, sem sinal longa e DWORD) como LONG.

Identificadores de objeto

Todos os identificadores são valores de inteiro de 16 bits exclusivo associados a uma janela e são passados por valor, portanto, passar esses parâmetros como Integer.

Seqüências de caracteres

Seqüências de caracteres incluem os tipos de dados LPSTR e LPBYTE (ponteiro para caracteres) ou ponteiro para caracteres não assinados. Passe esses parâmetros como (ByVal paramname As String). Para passar cadeias de caracteres Visual Basic diretamente, passe-los como (param As String).

Para obter informações adicionais sobre passanado seqüências entre Visual Basic e um DLL C, consulte o seguinte artigo na Base de dados de Conhecimento da Microsoft:
118643  (http://support.microsoft.com/kb/118643/EN-US/ ) Como passar uma seqüência ou seqüência de matriz entre VB e C uma DLL
Observação: Visual Basic seqüências requerem tratamento especial, portanto, não passe seqüências de caracteres diretamente, a menos que a DLL a exija explicitamente.

Ponteiros para valores numéricos

Passe ponteiros para valores numéricos simplesmente não utilizando a palavra-chave ByVal.

Estruturas

Se o tipo definido pelo usuário do Visual Basic corresponde à estrutura esperada pela DLL, a estrutura pode ser passada por referência.

Observação: Estruturas não podem ser passadas por valor.

Ponteiros para matrizes

Passe o primeiro elemento da matriz por referência.

Ponteiros para funções

Visual Basic não oferece suporte a funções de retorno de chamada, portanto funções DLL com ponteiros para funções não podem ser usadas com o Visual Basic.

Ponteiros nulos

Se uma DLL espera um ponteiro nulo, passe para ele como (ByVal paramname as any). Você pode usar 0 & como o valor de paramname ao chamar a DLL.

Solução de problemas de 2.2

Abaixo estão soluções para alguns problemas que podem ser encontrados.

Recursos do sistema manter ponto inferiores após a DLL É chamada

Se sua DLL está usando objetos GDI, você deve lembrar-se liberá-los após usá-los. Isso não pode ser óbvio no Visual Basic, mas quando usando o SDK (software development kit) do Windows se você criar um objeto GDI (por exemplo, CreateBrushIndirect), você deve excluí-la usando ExcluirObjeto posteriormente.

Erro de convenção de chamada de DLL incorreto

Este erro geralmente é causado por omitindo incorretamente ou incluindo a palavra-chave ByVal da instrução Declare. Este erro também pode ser causado se errado os parâmetros forem passados.

Erro ao carregar DLL

Este erro ocorre quando você chamar um procedimento dynamic-link library, biblioteca de vínculo dinâmico e o arquivo especificado na instrução Declare do procedimento não pode ser carregado. Você pode usar a função do Microsoft Windows API LoadLibrary para descobrir informações mais específicas sobre por que uma DLL Falha ao carregar.

Falha geral de proteção (GP)

Falhas GP ocorrem quando seu programa grava em um bloco de memória que não pertence a ele. Os dois motivos provavelmente para isso são:

  • Overstepped um limite de matriz. C não verifica o subscrito de matriz que você está escrevendo a é válido. Portanto, você pode facilmente escrever para a memória que não possui.
  • Você está usando um ponteiro para um local de memória que você tiver liberado. A melhor opção é atribuir NULL para todos os ponteiros depois de liberar a memória.
Uma falha de diretiva de grupo também pode ocorrer quando um tipo de variável incorreto é passado para a função DLL.

Programa de chamada do 2.3 exemplo Visual Basic

Há duas partes para chamar uma DLL em um programa do Visual Basic. Primeiro declarar a função, e você usá-lo no código do evento.

Eis um exemplo de uma instrução Declare. A instrução Declare deve ser colocada em um módulo ou em seção Declaração geral de um formulário.
   ' Enter the following Declare as one, single line:
   Declare Sub getdiskinfo Lib "c:\dllartic\diskinfo.dll"

      (ByVal mydrive As String, ByVal myvolume As String, free As Long)
				
ByVal especificar instruções exatamente como mostrado, ou então uma falha de GP pode ocorrer.

Depois que a função é declarada, você pode usá-lo no código do evento. O exemplo a seguir usa uma função da DLL no código de evento Click de Command1:
   Sub Command1_Click ()
      Dim drive As String * 1
      Dim volume As String * 20
      Dim free As Long
      Call getdiskinfo(drive, volume, free)
      Text1.Text = drive
      Text2.Text = volume
      Text3.Text = Str$(free)
   End Sub
				

A informação contida neste artigo aplica-se a:
  • Microsoft Visual Basic 3.0 Professional Edition
  • Microsoft Visual Basic 3.0 Professional Edition
Palavras-chave: 
kbmt kbhowto kbprogramming KB106553 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 106553  (http://support.microsoft.com/kb/106553/en-us/ )
Retired KB ArticleAviso de Isenção de Responsabilidade sobre Conteúdo do KB Aposentado
Este artigo trata de produtos para os quais a Microsoft não mais oferece suporte. Por esta razão, este artigo é oferecido "como está" e não será mais atualizado.