Passo a passo: Criar e usar sua própria Biblioteca de vínculo dinâmico (C++)

Este passo a passo mostra como usar o IDE do Visual Studio para criar sua própria biblioteca de vínculo dinâmico (DLL) em C++ e, em seguida, usá-la a partir de outro aplicativo C++. Em seguida, ele mostra como usar a DLL de outro aplicativo C++. DLLs (também conhecidas como bibliotecas compartilhadas em sistemas operacionais baseados em UNIX) são um dos tipos mais úteis de componentes do Windows. Você pode usá-las como uma forma de compartilhar código e recursos, e para reduzir o tamanho dos seus aplicativos. As DLLs podem até facilitar o serviço e estender seus aplicativos.

Neste passo a passo, você criará uma DLL que implementa algumas funções matemáticas. Depois, criará um aplicativo de console que utiliza as funções da DLL. Você também terá uma introdução sobre algumas técnicas de programação e convenções usadas nas DLLs do Windows.

Este passo a passo apresenta estas tarefas:

  • Crie um projeto de DLL no Visual Studio.

  • Adicione variáveis e funções exportadas para a DLL.

  • Crie um projeto de aplicativo de console no Visual Studio.

  • Use as funções e variáveis importadas da DLL no aplicativo de console.

  • Execute o aplicativo concluído.

Como uma biblioteca de vínculo dinâmico, uma DLL exporta variáveis, funções e recursos por nome. Um aplicativo cliente importa os nomes para usar essas variáveis, funções e recursos. Ao contrário de uma biblioteca vinculada estaticamente, o Windows conecta as importações em seu aplicativo às exportações em uma DLL no momento do carregamento ou no tempo de execução, ao invés de conectá-las ao link de vinculação. O Windows requer informações adicionais que não fazem parte do modelo de compilação em C++ padrão para fazer essas conexões. O compilador MSVC implementa algumas extensões específicas da Microsoft para C++ para fornecer essas informações adicionais. Explicaremos essas extensões à medida que avançarmos.

Este passo a passo cria duas soluções do Visual Studio: uma que cria a DLL e outra que compila o aplicativo cliente. A DLL usa a convenção de chamada C. Ela pode ser chamada de aplicativos escritos em outras linguagens de programação, desde que a plataforma, convenções de chamada e convenções de vinculação correspondam. O aplicativo cliente usa a vinculação implícita, em que o Windows vincula o aplicativo à DLL no tempo de carregamento. Essa vinculação permite que o aplicativo chame as funções fornecidas pela DLL como as funções de uma biblioteca vinculada estaticamente.

Este passo a passo não aborda algumas situações comuns. O código não mostra o uso de DLLs de C++ por outras linguagens de programação. Ele não mostra como criar uma DLL somente de recursos ou como usar a vinculação explícita para carregar DLLs em tempo de execução, em vez de em tempo de carga. Fique tranquilo, você pode usar o Visual C++ para fazer todas essas coisas.

Embora o código da DLL seja escrito em C++, usamos interfaces de estilo C para as funções exportadas. Há dois motivos principais para isso: primeiro, muitas outras linguagens dão suporte a importações de funções de estilo C. O aplicativo cliente não precisa ser escrito em C++. Em segundo lugar, isso evita algumas armadilhas comuns relacionadas a classes e funções de membro exportadas. É fácil cometer erros difíceis de diagnosticar ao exportar classes, uma vez que tudo o que se refere dentro de uma declaração de classe tem que ter uma instanciação que também é exportada. Essa restrição se aplica a DLLs, mas não a bibliotecas estáticas. Se suas classes forem de estilo de dados antigos simples, é provável que você não encontre esse problema.

Para saber mais sobre DLLs, consulte Criar DLLs C/C ++ no Visual Studio. Para saber mais sobre vinculação implícita e explícita, confira Determinar qual método de associação usar. Para saber mais sobre como criar DLLs C++ para usar com linguagens de programação que usam convenções de vinculação de linguagem C, consulte Exportando funções do C++ a serem usadas em executáveis da linguagem C. Para saber mais sobre como criar DLLs para usar com linguagens .NET, consulte Chamando funções DLL a partir de aplicativos Visual Basic.

Pré-requisitos

  • Um computador que executa o Microsoft Windows 7 ou versões posteriores. Recomendamos a versão mais recente do Windows para obter a melhor experiência de desenvolvimento.
  • Uma cópia do Visual Studio. Para saber mais sobre como fazer o download e instalar o Visual Studio, consulte Instalar o Visual Studio. Quando executar o instalador, certifique-se de que a carga de trabalho de Desenvolvimento para desktop com C++ esteja marcada. Não se preocupe se não tiver instalado essa carga de trabalho quando instalou o Visual Studio. Você pode executar o instalador novamente e instalá-la agora.

    Visual Studio Installer, Desktop development with C++ workload.

  • Uma cópia do Visual Studio. Para saber mais sobre como fazer o download e instalar o Visual Studio 2015, consulte Instalar o Visual Studio 2015. Use uma instalação personalizada para instalar o compilador E as ferramentas do C++, pois elas não são instaladas por padrão.
  • Um reconhecimento dos princípios básicos do uso do IDE do Visual Studio. Se já tiver usado aplicativos de desktop do Windows, você provavelmente não terá problemas. Para ver uma introdução, consulte Tour pelos recursos do IDE do Visual Studio.

  • Um reconhecimento dos princípios básicos da linguagem C++ a seguir. Não se preocupe, não faremos nada muito complicado.

Observação

Este passo a passo pressupõe que você esteja usando o Visual Studio 2017 versão 15.9 ou posterior. Algumas versões anteriores do Visual Studio 2017 tinham defeitos nos modelos de código ou usavam caixas de diálogo de interface do usuário diferentes. Para evitar problemas, use o Instalador do Visual Studio para atualizar o Visual Studio 2017 para a versão 15.9 ou posterior.

Criar o projeto de DLL

Neste conjunto de tarefas, você cria um projeto para sua DLL, adiciona código e o compila. Para começar, inicie o IDE do Visual Studio e, se necessário, entre. As instruções variam um pouco dependendo da versão do Visual Studio que você está usando. Verifique se tem a versão correta marcada no controle na parte superior esquerda desta página.

Para criar um projeto de DLL no Visual Studio 2019

  1. Na barra de menus, escolha Arquivo>Novo>Projeto para abrir a caixa de diálogo Criar um projeto.

    Screenshot of the Create a new project dialog with the Dynamic Link Library template highlighted.

  2. Na parte superior da caixa de diálogo, defina Linguagem como C++, Plataforma como Windows e Tipo de projeto como Biblioteca.

  3. Na lista filtrada de tipos de projeto, selecione Biblioteca de vínculo dinâmico (DLL) e, em seguida, escolha Avançar.

  4. Na página Configurar seu novo projeto, insira MathLibrary na caixa Nome do projeto para especificar um nome para o projeto. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Desmarque a opção Colocar a solução e o projeto no mesmo diretório se ela estiver marcada.

  5. Escolha o botão Criar para criar o projeto.

Quando a solução é criada, você verá os arquivos de projeto e de origem gerados na janela do Gerenciador de soluções no Visual Studio.

Screenshot of the Solution Explorer window with the Math Library project highlighted.

Para criar um projeto de DLL no Visual Studio 2017

  1. Na barra de menus, escolha Arquivo>Novo>Projeto para abrir a caixa de diálogo Novo Projeto.

  2. No painel esquerdo da caixa de diálogo Novo projeto, selecione Instalado>Visual C++>Área de Trabalho do Windows. No painel central, selecione DLL (Biblioteca de vínculo dinâmico). Digite MathLibrary na caixa de diálogo Nome para especificar o nome do projeto. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Marque a opção Criar diretório para a solução se ela estiver desmarcada.

    Screenshot of the New Project dialog box showing Math Library in the Name text box.

  3. Escolha o botão OK para criar o projeto.

Quando a solução é criada, você verá os arquivos de projeto e de origem gerados na janela do Gerenciador de soluções no Visual Studio.

Screenshot of the Solution Explorer window with the Math Library highlighted.

Para criar um projeto de DLL no Visual Studio 2015 e em versões mais antigas.

  1. Na barra de menus, escolha Arquivo>Novo>Projeto.

  2. No painel esquerdo da caixa de diálogo Novo Projeto, expanda Modelos>Instalados e escolha Visual C++. Em seguida, no painel central, escolha Aplicativo de Console Win32. Digite MathLibrary na caixa de edição Nome para especificar o nome do projeto. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Marque a opção Criar diretório para a solução se ela estiver desmarcada.

    Screenshot of the New Project dialog box showing Math Library in the Name text box.

  3. Escolha o botão OK para ignorar a caixa de diálogo Novo Projeto e iniciar o Assistente de Aplicativo Win32.

    Screenshot of the Win32 Application Wizard Overview page.

  4. Escolha o botão Avançar. Na página Configurações do Aplicativo, em Tipo de Aplicativo, escolha DLL.

    Screenshot of the Win32 Application Wizard Application Settings Page.

  5. Escolha o botão Concluir para criar o projeto.

Quando o assistente concluir a solução, você verá os arquivos de projeto e de origem gerados na janela do Gerenciador de Soluções no Visual Studio.

Screenshot of the Solution Explorer window with the Math Library highlighted.

No momento, essa DLL não faz muita coisa. Em seguida, você criará um arquivo de cabeçalho para declarar as funções que sua DLL exporta e, em seguida, adicione as definições de função à DLL para torná-la mais útil.

Para adicionar um arquivo de cabeçalho à DLL

  1. Para criar um arquivo de cabeçalho para suas funções, na barra de menus, escolha Projeto>Adicionar Novo Item.

  2. Na caixa de diálogo Adicionar Novo Item, no painel à esquerda, escolha Visual C++. No painel central, escolha Arquivo de Cabeçalho (.h). Especifique MathLibrary.h como o nome do arquivo de cabeçalho.

    Screenshot of the Add New Item dialog with the C plus plus Header File template selected, and MathLibrary.h entered in the Name textbox.

  3. Escolha o botão Adicionar para gerar um arquivo de cabeçalho em branco, que é exibido em uma nova janela do editor.

    Screenshot of the empty MathLibrary.h file in the editor.

  4. Substitua o conteúdo do arquivo de cabeçalho por este código:

    // MathLibrary.h - Contains declarations of math functions
    #pragma once
    
    #ifdef MATHLIBRARY_EXPORTS
    #define MATHLIBRARY_API __declspec(dllexport)
    #else
    #define MATHLIBRARY_API __declspec(dllimport)
    #endif
    
    // The Fibonacci recurrence relation describes a sequence F
    // where F(n) is { n = 0, a
    //               { n = 1, b
    //               { n > 1, F(n-2) + F(n-1)
    // for some initial integral values a and b.
    // If the sequence is initialized F(0) = 1, F(1) = 1,
    // then this relation produces the well-known Fibonacci
    // sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    extern "C" MATHLIBRARY_API void fibonacci_init(
        const unsigned long long a, const unsigned long long b);
    
    // Produce the next value in the sequence.
    // Returns true on success and updates current value and index;
    // false on overflow, leaves current value and index unchanged.
    extern "C" MATHLIBRARY_API bool fibonacci_next();
    
    // Get the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();
    
    // Get the position of the current value in the sequence.
    extern "C" MATHLIBRARY_API unsigned fibonacci_index();
    

Este arquivo de cabeçalho declara algumas funções para produzir uma sequência de Fibonacci generalizada, tendo em conta dois valores iniciais. Uma chamada para fibonacci_init(1, 1) gera a conhecida sequência de números de Fibonacci.

Observe as instruções do pré-processador na parte superior do arquivo. O novo modelo de projeto de um projeto DLL adiciona <PROJECTNAME>_EXPORTS às macros de pré-processador definidas. Neste exemplo, o Visual Studio define MATHLIBRARY_EXPORTS quando seu projeto de DLL MathLibrary é compilado.

Quando a macro MATHLIBRARY_EXPORTS é definida, a macro MATHLIBRARY_API define o modificador __declspec(dllexport) nas declarações da função. Esse modificador informa ao compilador e ao vinculador para exportar uma função ou variável da DLL para ser usada por outros aplicativos. Quando MATHLIBRARY_EXPORTS está indefinido, por exemplo, quando o arquivo de cabeçalho é incluído por um aplicativo cliente, MATHLIBRARY_API aplica o modificador __declspec(dllimport) às declarações. Esse modificador otimiza a importação da função ou variáveis em aplicativos. Para saber mais, confira dllexport, dllimport.

Para adicionar uma implementação à DLL

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó Arquivos de origem e escolha Adicionar>Novo item. Crie um novo arquivo .cpp chamado MathLibrary.cpp, da mesma forma que você adicionou um novo arquivo de cabeçalho na etapa anterior.

  2. Na janela do editor, escolha a guia para MathLibrary.cpp se já estiver aberta. Caso contrário, no Gerenciador de Soluções, clique duas vezes em MathLibrary.cpp na pasta Arquivos de origem do projeto MathLibrary para abri-la.

  3. No editor, substitua o conteúdo do arquivo MathLibrary.cpp pelo código a seguir:

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    
  1. Na janela do editor, escolha a guia para MathLibrary.cpp se já estiver aberta. Caso contrário, no Gerenciador de Soluções, clique duas vezes em MathLibrary.cpp na pasta Arquivos de origem do projeto MathLibrary para abri-la.

  2. No editor, substitua o conteúdo do arquivo MathLibrary.cpp pelo código a seguir:

    // MathLibrary.cpp : Defines the exported functions for the DLL.
    #include "stdafx.h" // use pch.h in Visual Studio 2019 and later
    #include <utility>
    #include <limits.h>
    #include "MathLibrary.h"
    
    // DLL internal state variables:
    static unsigned long long previous_;  // Previous value, if any
    static unsigned long long current_;   // Current sequence value
    static unsigned index_;               // Current seq. position
    
    // Initialize a Fibonacci relation sequence
    // such that F(0) = a, F(1) = b.
    // This function must be called before any other function.
    void fibonacci_init(
        const unsigned long long a,
        const unsigned long long b)
    {
        index_ = 0;
        current_ = a;
        previous_ = b; // see special case when initialized
    }
    
    // Produce the next value in the sequence.
    // Returns true on success, false on overflow.
    bool fibonacci_next()
    {
        // check to see if we'd overflow result or position
        if ((ULLONG_MAX - previous_ < current_) ||
            (UINT_MAX == index_))
        {
            return false;
        }
    
        // Special case when index == 0, just return b value
        if (index_ > 0)
        {
            // otherwise, calculate next sequence value
            previous_ += current_;
        }
        std::swap(current_, previous_);
        ++index_;
        return true;
    }
    
    // Get the current value in the sequence.
    unsigned long long fibonacci_current()
    {
        return current_;
    }
    
    // Get the current index position in the sequence.
    unsigned fibonacci_index()
    {
        return index_;
    }
    

Para verificar se tudo está funcionando bem, compile a biblioteca de vínculo dinâmico. Para compilar, escolha Compilar>Compilar solução na barra de menus. A saída da DLL e do compilador relacionado são colocadas em uma pasta chamada Depuração diretamente abaixo da pasta da solução. Se você criar um build de versão, a saída será colocada em uma pasta chamada Versão. A saída deve parecer com esta:

1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>stdafx.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 ------
1>MathLibrary.cpp
1>dllmain.cpp
1>Generating Code...
1>   Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.pdb (Partial PDB)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Parabéns, você criou uma DLL usando o Visual Studio! A seguir, você criará um aplicativo cliente que usa as funções exportadas pela DLL.

Criar um aplicativo cliente que usa a DLL

Ao criar uma DLL, pense em como os aplicativos cliente podem usá-la. Para chamar as funções ou acessar os dados exportados por uma DLL, o código-fonte do cliente deve ter as declarações disponíveis em tempo de compilação. No tempo de vinculação, o vinculador requer informações para resolver as chamadas de função ou os acessos a dados. Uma DLL fornece essas informações em uma biblioteca de importação, um arquivo que contém informações sobre como localizar as funções e os dados, em vez do código real. E no tempo de execução a DLL deve estar disponível para o cliente, em um local que o sistema operacional possa localizá-la.

Independentemente de ele ser seu ou de terceiros, seu projeto de aplicativo cliente precisa de várias informações para usar uma DLL. Ele precisa encontrar os cabeçalhos que declaram as exportações de DLL, as bibliotecas de importação para o vinculador e a própria DLL. Uma solução é copiar todos esses arquivos para o projeto de cliente. No caso de DLLs de terceiros que provavelmente não serão alteradas enquanto seu cliente estiver em desenvolvimento, esse método pode ser a melhor maneira de usá-las. No entanto, quando você também compila a DLL, é melhor evitar a duplicação. Se você fizer uma cópia local dos arquivos DLL que estão em desenvolvimento, poderá acidentalmente alterar um arquivo de cabeçalho em uma cópia, mas não o outro arquivo, ou usar uma biblioteca desatualizada.

Para evitar código dessincronizado, recomendamos definir o caminho de inclusão no projeto de cliente para incluir os arquivos de cabeçalho da sua DLL diretamente do seu projeto de DLL. Além disso, defina o caminho da biblioteca em seu projeto de cliente para incluir as bibliotecas de importação de DLLs do projeto da DLL. Por fim, copie a DLL compilada do projeto da DLL para seu diretório cliente de saída compilado. Esta etapa permite que seu aplicativo cliente use o mesmo código de DLL que você compilou.

Para criar um aplicativo cliente no Visual Studio

  1. Na barra de menus, escolha Arquivo>Novo>Projeto para abrir a caixa de diálogo Criar um projeto.

  2. Na parte superior da caixa de diálogo, defina Linguagem como C++, Plataforma como Windows e Tipo de projeto como Console.

  3. Na lista filtrada de tipos de projeto, escolha Aplicativo de Console e, em seguida, escolha Avançar.

  4. Na página Configurar seu novo projeto, insira MathClient na caixa Nome do projeto para especificar um nome para o projeto. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Desmarque a opção Colocar a solução e o projeto no mesmo diretório se ela estiver marcada.

    Screenshot of the Create a new project dialog box with the Console App option highlighted.

  5. Escolha o botão Criar para criar o projeto do cliente.

Um projeto de aplicativo de console mínimo será criado para você. O nome do arquivo de origem principal é o mesmo nome do projeto inserido anteriormente. Neste exemplo, o nome usado é MathClient.cpp. Você pode compilá-lo, mas ele ainda não usa a DLL.

Para criar um aplicativo cliente no Visual Studio 2017

  1. Para criar um aplicativo C++ que use a DLL que você criou, escolha Arquivo>Novo>Projeto na barra de menus.

  2. No painel esquerdo da caixa de diálogo Novo Projeto, escolha Windows Desktop em Visual C++>Instalado. No painel central, clique em Aplicativo de Console do Windows. Especifique o nome do projeto MathClient na caixa de edição Nome. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Marque a opção Criar diretório para a solução se ela estiver desmarcada.

    Screenshot of the New Project dialog box with Installed > Visual C plus plus > Windows Desktop selected, Windows Console Application highlighted, and Math Client typed in the Name text box.

  3. Escolha OK para criar o projeto de aplicativo cliente.

Um projeto de aplicativo de console mínimo será criado para você. O nome do arquivo de origem principal é o mesmo nome do projeto inserido anteriormente. Neste exemplo, o nome usado é MathClient.cpp. Você pode compilá-lo, mas ele ainda não usa a DLL.

Para criar um aplicativo cliente no Visual Studio 2015

  1. Para criar um aplicativo C++ que use a DLL que você criou, escolha Arquivo>Novo>Projeto na barra de menus.

  2. No painel esquerdo da caixa de diálogo Novo Projeto, escolha Win32 em Modelos>Instalados do>Visual C++. No painel central, escolha Aplicativo de Console Win32. Especifique o nome do projeto MathClient na caixa de edição Nome. Deixe o Local e o Nome da solução com os valores padrão. Defina Solução para Criar uma nova solução. Marque a opção Criar diretório para a solução se ela estiver desmarcada.

    Screenshot of the New Project dialog box with Installed > Templates > Visual C plus plus > Win32 selected, Win32 Console Application Visual C plus plus highlighted, and Math Client typed in the Name text box.

  3. Escolha o botão OK para ignorar a caixa de diálogo Novo Projeto e iniciar o Assistente de Aplicativo Win32. Na página Visão geral da caixa de diálogo Assistente de Aplicativo Win32, clique no botão Avançar.

  4. Na página Configurações do Aplicativo, em Tipo de Aplicativo, escolha Aplicativo de Console, caso ainda não esteja marcado.

  5. Escolha o botão Concluir para criar o projeto.

Quando o assistente for concluído, um projeto de aplicativo de console mínimo será criado para você. O nome do arquivo de origem principal é o mesmo nome do projeto inserido anteriormente. Neste exemplo, o nome usado é MathClient.cpp. Você pode compilá-lo, mas ele ainda não usa a DLL.

Em seguida, para chamar as funções MathLibrary em seu código-fonte, seu projeto deve incluir o arquivo MathLibrary.h. Você poderia copiar esse arquivo de cabeçalho para o projeto do aplicativo cliente e adicioná-lo ao projeto como um item existente. Esse método pode ser uma boa opção para bibliotecas de terceiros. No entanto, se você estiver trabalhando no código para sua DLL e seu cliente ao mesmo tempo, os arquivos de cabeçalho poderão ficar fora de sincronia. Para evitar esse problema, defina o caminho de Diretórios de inclusão adicional em seu projeto para incluir o caminho para o cabeçalho original.

Para adicionar o cabeçalho da DLL ao caminho de inclusão

  1. Clique com botão direito do mouse no nó MathClient no Gerenciador de Soluções para abrir a caixa de diálogo Páginas de Propriedades.

  2. Na caixa da lista suspensa Configuração, selecione Todas as configurações caso a opção ainda não esteja marcada.

  3. No painel à esquerda, escolha Propriedades de configuração>C/C++>Geral.

  4. No painel de propriedades, escolha o controle suspenso ao lado da caixa de edição Diretórios de Inclusão Adicionais e, em seguida, escolha Editar.

    Screenshot of the Property Pages dialog showing the Edit command in the Additional Include Directories property drop-down.

  5. Clique duas vezes no painel superior da caixa de diálogo Diretórios de Inclusão Adicionais para ativar um controle de edição. Ou escolha o ícone de pasta para criar uma nova entrada.

  6. No controle de edição, especifique o caminho para o local do arquivo de cabeçalho MathLibrary.h. Você pode escolher o controle de reticências (...) para navegar até a pasta correta.

    Você também pode inserir um caminho relativo dos arquivos de origem do cliente para a pasta que contém os arquivos de cabeçalho DLL. Se você seguiu as instruções para colocar seu projeto cliente em uma solução separada da DLL, o caminho relativo deverá ter esta aparência:

    ..\..\MathLibrary\MathLibrary

    Se seus projetos de DLL e cliente estiverem na mesma solução, o caminho relativo poderá ser semelhante a este:

    ..\MathLibrary

    Quando a DLL e os projetos do cliente estiverem em outras pastas, ajuste o caminho relativo para corresponder. Ou use o controle de reticências para procurar a pasta.

    Screenshot of the Additional Include Directories dialog showing the relative path to the MathLibrary directory.

  7. Depois de inserir o caminho para o arquivo de cabeçalho na caixa de diálogo Diretórios de inclusão adicional, escolha o botão OK. Na caixa de diálogo Páginas de Propriedades, selecione o botão OK para salvar as alterações.

Agora você pode incluir o arquivo MathLibrary.h e usar as funções que ele declara em seu aplicativo cliente. Substitua o conteúdo de MathClient.cpp usando este código:

// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"

int main()
{
    // Initialize a Fibonacci relation sequence.
    fibonacci_init(1, 1);
    // Write out the sequence values until overflow.
    do {
        std::cout << fibonacci_index() << ": "
            << fibonacci_current() << std::endl;
    } while (fibonacci_next());
    // Report count of values written before overflow.
    std::cout << fibonacci_index() + 1 <<
        " Fibonacci sequence values fit in an " <<
        "unsigned 64-bit integer." << std::endl;
}

Esse código pode ser compilado, mas não vinculado. Se você criar o aplicativo cliente agora, a lista de erros mostrará vários erros LNK2019. Isso ocorre porque seu projeto não tem algumas informações: você ainda não especificou que seu projeto tem uma dependência na biblioteca MathLibrary.lib. E você não disse ao vinculador como encontrar o arquivo MathLibrary.lib.

Para corrigir esse problema, você pode copiar o arquivo de biblioteca diretamente no projeto do aplicativo cliente. O vinculador localizaria e o usaria automaticamente. Porém, se a biblioteca e o aplicativo cliente estiverem em desenvolvimento, isso pode levar a alterações em uma cópia que não são mostradas na outra. Para evitar esse problema, você pode definir a propriedade Dependências adicionais para informar ao sistema de build que seu projeto depende da MathLibrary.lib. Você pode definir um caminho para Diretórios de biblioteca adicionais em seu projeto para incluir o caminho para a biblioteca original quando a vinculação ocorrer.

Para adicionar a biblioteca de importação da DLL ao projeto

  1. Clique com o botão direito no nó MathClient no Gerenciador de soluções e escolha Propriedades para abrir o diálogo Páginas de propriedades.

  2. Na caixa da lista suspensa Configuração, selecione Todas as configurações caso a opção ainda não esteja marcada. Isso garante que todas as alterações de propriedade se apliquem a builds de depuração e versão.

  3. No painel à esquerda, escolha Propriedades de configuração>Vinculador>Entrada. No painel de propriedades, escolha o controle suspenso ao lado da caixa de edição Dependências Adicionais e, em seguida, escolha Editar.

    Screenshot of the Property Pages dialog showing the Edit command in the Linker > Input > Additional Dependencies property drop-down.

  4. Na caixa de diálogo Dependências Adicionais, adicione MathLibrary.lib à lista no controle de edição superior.

    Screenshot of the Additional Dependencies dialog showing the MathLibrary.lib file.

  5. Escolha OK para voltar para a caixa de diálogo Páginas de Propriedades.

  6. No painel à esquerda, escolha Propriedades de configuração>Vinculador>Geral. No painel de propriedades, selecione o controle suspenso ao lado da caixa de edição Diretórios de Biblioteca Adicionais e, em seguida, escolha Editar.

    Screenshot of the Property Pages dialog showing the Edit command in the Linker > General > Additional Library Directories property drop-down.

  7. Clique duas vezes no painel superior da caixa de diálogo Diretórios de Biblioteca Adicionais para ativar um controle de edição. No controle de edição, especifique o caminho para o local do arquivo MathLibrary.lib. Por padrão, ele está em uma pasta chamada Depurar diretamente na pasta da solução DLL. Se você criar um build de versão, o arquivo será colocado em uma pasta chamada Versão. Você pode usar a macro $(IntDir) para que o vinculador possa encontrar sua DLL, independentemente do tipo de build que você criar. Se você seguiu as instruções para colocar seu projeto cliente em uma solução separada da DLL, o caminho relativo deverá ter esta aparência:

    ..\..\MathLibrary\$(IntDir)

    Se sua DLL e projetos de cliente estiverem em outros locais, ajuste o caminho relativo para corresponder.

    Screenshot of the Additional Library Directories dialog.

  8. Depois de inserir o caminho para o arquivo de biblioteca na caixa de diálogo Diretórios de Biblioteca Adicionais, escolha o botão OK para voltar para a caixa de diálogo Páginas de Propriedades. Escolha OK para salvar as alterações de propriedade.

Seu aplicativo cliente pode compilar e vincular com êxito, mas ainda não tem tudo aquilo que precisa para ser executado. Quando o sistema operacional carrega seu aplicativo, ele procura a DLL MathLibrary. Se não conseguir encontrar a DLL em determinados diretórios do sistema, o caminho do ambiente ou o diretório local do aplicativo, o carregamento falhará. Dependendo do sistema operacional, você verá uma mensagem de erro como esta:

Screenshot of the error dialog, MathLibrary DLL not found.

Uma maneira de evitar esse problema é copiar a DLL para o diretório que contém o executável do cliente como parte do processo de compilação. Você pode adicionar um Evento Pós-Build ao projeto para adicionar um comando que copia a DLL para o diretório de saída da compilação. O comando especificado aqui copia a DLL somente se ela estiver ausente ou tiver sido alterada. Ele usa macros para copiar de e para os locais de depuração ou versão, com base na configuração de build.

Para copiar a DLL em um evento pós-compilação

  1. Clique com o botão direito no nó MathClient no Gerenciador de soluções e escolha Propriedades para abrir o diálogo Páginas de propriedades.

  2. Na caixa da lista suspensa Configuração, escolha Todas as Configurações caso a opção ainda não esteja marcada.

  3. No painel à esquerda, selecione Propriedades de configuração>Evento de build>Evento pós-build.

  4. No painel de propriedades, escolha o controle de edição no campo Linha de Comando. Se você seguiu as instruções para colocar seu projeto cliente em uma solução separada da DLL, digite esse comando:

    xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"

    Se seus projetos de DLL e cliente estiverem em outros diretórios, altere o caminho relativo para a DLL para corresponder.

    Screenshot of the Property Pages dialog showing the post build event command line property.

  5. Escolha o botão OK para salvar suas alterações nas propriedades do projeto.

Agora, seu aplicativo cliente tem tudo aquilo que precisa para ser compilado e executado. Compile o aplicativo escolhendo Compilar>Compilar Solução na barra de menus. A janela Saída no Visual Studio deve ter algo semelhante ao exemplo a seguir, dependendo da sua versão do Visual Studio:

1>------ Build started: Project: MathClient, Configuration: Debug Win32 ------
1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Parabéns, você criou um aplicativo que chama as funções na sua DLL. Agora, execute seu aplicativo para ver o que ele faz. Na barra de menus, escolha Depurar>Iniciar Sem Depurar. O Visual Studio abre uma janela de comando para o programa ser executado. A última parte da saída deverá se parecer com:

Screenshot of the command window output when you start the client app without debugging.

Pressione qualquer tecla para fechar a janela de comando.

Agora que você criou uma DLL e um aplicativo cliente, comece a fazer experimentos. Tente definir pontos de interrupção no código do aplicativo cliente e executar o aplicativo no depurador. Veja o que acontece quando você entra em uma chamada de biblioteca. Adicione outras funções à biblioteca ou crie outro aplicativo cliente que usa sua DLL.

Quando implantar seu aplicativo, implante também as DLLs que ele usa. A maneira mais simples de disponibilizar as DLLs que você compila ou que inclui de terceiros é colocá-las no mesmo diretório do seu aplicativo. Ele é conhecido como implantação do local do aplicativo. Para saber mais sobre implantação, confira Implantação no Visual C++.

Confira também

Chamando funções DLL de aplicativos Visual Basic