18
E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I 171 8 8 . . C C r r i i a a n n d d o o D D L L L L s s As bibliotecas de enlace dinâmico (DLL - Dynamic-link libraries) fornecem uma forma modular de construir aplicações de forma que a funcionalidade possa ser atualizada e reutilizada de forma mais flexível. Elas ajudam a reduzir a sobrecarga de memória quando muitas aplicações usam a mesma funcionalidade ao mesmo tempo porque embora cada aplicação tenha o seu próprio conjunto de dados, elas podem compartilhar o código. No Windows as DLL são módulos que contêm funções e dados. Uma DLL é carregada em tempo de execução pelos seus módulos invocadores (.EXE ou outra DLL). Quando uma DLL for carregada, ela é mapeada no espaço de endereços do processo que a invocou. As DLL podem definir dois tipos de funções: exportadas e internas. As funções exportadas podem ser chamadas por outros módulos. As funções internas podem somente ser chamadas dentro da DLL onde elas estão definidas. Um arquivo .DLL é uma coleção de arquivos .OBJ ou módulos que um .EXE pode enlaçar de forma estática (i.e. que a DLL deva estar presente para que o .EXE ser executado) ou dinâmica (i.e. que a DLL será carregada somente quando o .EXE precisar). Existe uma diferença entre o “enlace estático” de uma DLL e o “uso estático do enlace”. O enlace estático significa que se está fazendo o enlace com uma biblioteca que contém todos os .OBJ necessários. Isto não é uma DLL, e sim uma biblioteca estática. Tipicamente essas possuem a extensão .LIB. O uso estático do enlace com uma .DLL significa que se está fazendo um enlace que contém referências para a DLL (também usa .LIB, mas sem os .OBJ). O carregamento dinâmico da .DLL significa que se está chamando a função da WinAPI, LoadLibrary(...). Assim, as três permutações possíveis são: o enlace estático com uma .LIB, o uso estático do enlace com uma biblioteca de importação (também .LIB) que possui referências para uma .DLL, e o carregamento dinâmico de uma .DLL.

08-DLL-C++BuilderV10

Embed Size (px)

DESCRIPTION

As bibliotecas de enlace dinâmico (DLL - Dynamic-link libraries) fornecem uma forma modular de construir aplicações de forma que a funcionalidade possa ser atualizada e reutilizada de forma mais flexível. Elas ajudam a reduzir a sobrecarga de memória quando muitas aplicações usam a mesma funcionalidade ao mesmo tempo porque embora cada aplicação tenha o seu próprio conjunto de dados, elas podem compartilhar o código. 171 D E

Citation preview

Page 1: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

171

88.. CCrriiaannddoo DDLLLLss As bibliotecas de enlace dinâmico (DLL - Dynamic-link libraries) fornecem

uma forma modular de construir aplicações de forma que a funcionalidade possa

ser atualizada e reutilizada de forma mais flexível. Elas ajudam a reduzir a

sobrecarga de memória quando muitas aplicações usam a mesma funcionalidade

ao mesmo tempo porque embora cada aplicação tenha o seu próprio conjunto de

dados, elas podem compartilhar o código.

No Windows as DLL são módulos que contêm funções e dados. Uma DLL é

carregada em tempo de execução pelos seus módulos invocadores (.EXE ou outra

DLL). Quando uma DLL for carregada, ela é mapeada no espaço de endereços do

processo que a invocou.

As DLL podem definir dois tipos de funções: exportadas e internas. As

funções exportadas podem ser chamadas por outros módulos. As funções

internas podem somente ser chamadas dentro da DLL onde elas estão definidas.

Um arquivo .DLL é uma coleção de arquivos .OBJ ou módulos que um

.EXE pode enlaçar de forma estática (i.e. que a DLL deva estar presente para que

o .EXE ser executado) ou dinâmica (i.e. que a DLL será carregada somente

quando o .EXE precisar).

Existe uma diferença entre o “enlace estático” de uma DLL e o “uso

estático do enlace”.

O enlace estático significa que se está fazendo o enlace com uma biblioteca

que contém todos os .OBJ necessários. Isto não é uma DLL, e sim uma biblioteca

estática. Tipicamente essas possuem a extensão .LIB.

O uso estático do enlace com uma .DLL significa que se está fazendo um

enlace que contém referências para a DLL (também usa .LIB, mas sem os .OBJ).

O carregamento dinâmico da .DLL significa que se está chamando a

função da WinAPI, LoadLibrary(...).

Assim, as três permutações possíveis são: o enlace estático com uma .LIB,

o uso estático do enlace com uma biblioteca de importação (também .LIB) que

possui referências para uma .DLL, e o carregamento dinâmico de uma .DLL.

Page 2: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

172

88..11.. TTiippooss ddee EEnnllaaccee DDiinnââmmiiccoo Existem duas formas de chamar uma função em uma DLL:

� No enlace dinâmico durante o carregamento do programa quando um módulo faz chamadas explícitas a funções exportadas pela DLL. Isto requer que existe um

enlace do módulo com a biblioteca de importação da DLL. Uma biblioteca de importação fornece ao sistema operacional com a informação necessária para carregar a DLL e localizar as funções exportadas pela DLL quando a aplicação for

carregada.

� No enlace dinâmico durante o tempo de execução, um módulo usa a função LoadLibrary para carregar a DLL durante o tempo de execução. Depois que a DLL for carregada, o módulo chama a função GetProcAddress para capturar os endereços das funções exportadas da DLL O módulo chama as funções

exportadas pela DLL usando os ponteiros para função retornados pela função GetProcAddress. Isto elimina a necessidade de uma biblioteca de importação.

88..22.. DDLLLL ee GGeerreenncciiaammeennttoo ddee

MMeemmóórriiaa Cada processo que carrega a DLL mapeia-a dentro do seu espaço virtual

de endereços. Depois que o processo carregar a DLL dentro dos seus endereços

virtuais ele pode invocara as funções exportadas.

O sistema mantém um contador de referência para cada DLL. Quando

uma aplicação carrega a DLL o contador é incrementado de um. Quando a

aplicação acaba ou quando o contador de referência chegar a zero, a DLL é

descarregada do espaço virtual de endereços.

Assim como as demais funções, as funções exportadas da DLL são

executadas dentro do contexto da aplicação que a chamou. Desta forma, se

aplicam as seguintes condições:

� A tarefa do processo que chamou a DLL pode usar manipuladores abertos pela função da DLL. De forma análoga, os manipuladores abertos por qualquer tarefa do processo invocador podem também ser usados pelas funções da DLL.

� As DLL usam a pilha do processo invocador e o seu espaço virtual de endereços.

� As DLL alocam memória a partir do espaço virtual de endereços do processo

invocador.

88..33.. VVaannttaaggeennss ddoo EEnnllaaccee DDiinnââmmiiccoo O enlaçamento dinâmico possui as seguintes vantagens sobre o

enlaçamento estático:

� Os processos que carregam a DLL no mesmo endereço base podem usar uma

única DLL de forma simultânea, compartilhando uma única cópia do código da DLL na memória física. Fazendo isto se poupa memória e reduz a fragmentação.

Page 3: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

173

� Quando as funções de uma DLL mudarem, as aplicações que as usam não

precisam ser recompiladas ou re-ligadas enquanto os argumentos das funções, as formas de chamada e os tipos de valores de retorno não mudarem. Em contraste, os códigos-objeto de enlace estático requerem que a aplicação seja re-ligada

quando mudarem as funções.

� Uma DLL pode fornecer suporte pós-venda. Por exemplo, uma DLL de driver de

display pode ser modificada para suportar um display que não estava disponível quando a aplicação foi vendida.

� Os programas escritos em diferentes linguagens de programação podem chamar a mesma função da DLL sempre que os programas sigam o mesmo padrão de

chamada que a função utiliza. As convenções de chamada (tais como C, Pascal e outras) controlam a ordem na qual a função invocada deve colocar os argumentos na pilha, se a função invocada ou invocadora é responsável por limpar a pilha, e se os argumentos são passados através dos registradores.

Uma potencial desvantagem no uso das DLL é que a aplicação não é auto-

contida; ela depende da existência de um módulo separado (a DLL). O sistema

termina os processos que usam enlace dinâmico em tempo de carregamento se

eles requererem uma DLL que não é encontrada no início do processo e provoca

uma mensagem de erro para o usuário. O sistema não termina os processos que

usam enlace dinâmico em tempo de execução nesta situação, no entanto as

funções exportadas pela DLL não ficam disponíveis para o programa.

88..44.. FFuunnççããoo EEnnttrraaddaa Todas as DLL devem ter um ponto de entrada ou de início assim como as

aplicações (função main). O sistema operacional chama a função de início

quando os processos e tarefas carregam ou terminam a DLL. Se a DLL estiver

ligada com uma biblioteca tal como uma biblioteca C em tempo de execução, ela

pode fornecer a função de início e permitir que seja fornecida uma função de

inicialização separada.

Se for colocado o próprio ponto de início, pode ser usada a função

DllEntryPoint. O nome DllEntryPoint é um lugar para colocar a função definida

pelo usuário. Geralmente o programador pode especificar um ponto de início

para a sua DLL usando o linker.

88..55.. QQuuaannddoo uussaarr PPaacckkaaggeess ee DDLLLLss Para a maioria das aplicações escritas em C++Builder, os packages

fornecem grande flexibilidade e são mais fáceis de criar que DLLs. No entanto,

Page 4: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

174

existem várias situações onde as DLLs são mais convenientes para os seus

projetos:

� Quando o módulo será chamado a partir de aplicações não-C++Builder.

� Quando se quer estender a funcionalidade de um servidor web.

� Quando se cria módulos de código para ser usado por desenvolvedores terceiros.

� Quando o projeto é um contêiner OLE.

88..66.. CCrriiaannddoo DDLLLLss nnoo CC++++BBuuiillddeerr A criação de DLLs em C++Builder é igual à criação em C++. Proceder da

seguinte maneira:

1 Escolher a opção de menu File + New para mostrar a janela de

diálogo New Items.

2 Escolher o ícone DLL e pressionar OK.

3 Escolher o tipo de fonte (C ou C++) para o módulo principal. Se você

desejar que o ponto inicial seja no estilo do MSVC++ (DllMain()) selecionar a

opção correspondente. Caso contrário será usado DllEntryPoint() como ponto

inicial. Selecione Use VCL para criar DLL contendo componentes VCL. Esta

opção é válida somente para módulos com fonte C++. Se desejar que a DLL seja

multitarefa assinalar a opção Multi-threaded.

4 Pressionar o botão OK.

Page 5: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

175

As funções exportadas no código devem ser identificadas usando o

modificador __declspec (dllexport) tanto para o Borland C++ ou Microsoft Visual

C++. Por exemplo, o código que segue é legal tanto no C++ Builder e outros

compiladores Windows C++.

// MinhaDLL.cpp double dblValue(double); double halfValue(double); extern "C" __declspec(dllexport) double changeValue(double, bool); double dblValue(double value){ return 2.0 * value; }; double halfValue(double value){ return value / 2.0; } double changeValue(double value, bool whichOp){ return whichOp ? dblValue(value) : halfValue(value); }

No código acima, a função changeValue é exportada e então fica disponível

para outras aplicações. As funções dblValue e halfValue são internas e não

podem ser chamadas de fora da DLL.

88..66..11.. EExxeemmpplloo ddee DDLLLL Depois de executar os 4 passos da seção anterior, utilize a opção de menu

Save Project As... Crie uma pasta nova. Altere então os nomes padrão Unit1.cpp

para UMinhaDLL.cpp e Project1.bpr para MinhaDLL.bpr.

A continuação, apague as linhas de comentário no UMinhaDLL.cpp para

que o código apareça da seguinte forma:

#include <windows.h> #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

Page 6: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

176

{ return 1; } //---------------------------------------------------------------------------

Acrescente o programa exemplo da seção anterior para aparecer como

segue:

//--------------------------------------------------------------------------- #include <vcl.h> #include <windows.h> #pragma hdrstop double dblValue(double); double halfValue(double); extern "C" __declspec(dllexport) double changeValue(double, bool); //--------------------------------------------------------------------------- #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- double dblValue(double value){ return 2.0 * value; }; //--------------------------------------------------------------------------- double halfValue(double value){ return value / 2.0; } //--------------------------------------------------------------------------- double changeValue(double value, bool whichOp){ return whichOp ? dblValue(value) : halfValue(value); } //---------------------------------------------------------------------------

O último passo é o de montar a DLL. Para fazer isto usar a opção de menu

Project + Build MinhaDLL. Se não houver erros serão criados os arquivos

mostrados na figura a seguir.

O arquivo MinhaDLL.DLL implementa a biblioteca que pode ser ligada de

forma dinâmica ou estática. Os arquivos MinhaDLL.OBJ e MinhaDLL.LIB são

Page 7: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

177

usados para efetuar ligações estáticas (se for o caso). Qualquer módulo poderá

agora usar a função double changeValue(double, bool) exportada pela DLL.

88..77.. UUssaannddoo DDLLLLss nnoo CC++++BBuuiillddeerr Uma DLL Windows pode ser usada em uma aplicação C++Builder como

em qualquer aplicação C++.

88..77..11.. CCaarrrreeggaammeennttoo EEssttááttiiccoo Para carregar estaticamente uma DLL quando a aplicação C++Builder for

carregada deve se ligar o arquivo de importação da biblioteca DLL em tempo de

ligação.

Para carregar uma DLL de forma estática quando for carregada a aplicação

C++ Builder, deve se ligar o arquivo da biblioteca de importação para a tal DLL

na aplicação C++ Builder em tempo de ligação. Para adicionar uma biblioteca de

importação em uma aplicação C++ Builder, deve se abrir o arquivo make file

(.BPR) da aplicação e adicionar o nome da biblioteca de importação na lista de

bibliotecas designadas pela variável ALLIB. Se necessário, deve se adicionar o

caminho.

Para fazer isto abra o projeto da aplicação que irá chamar as funções da

DLL. Visualizar então o Gerenciador de Projetos.

No Gerenciador de Projetos selecionar o arquivo .EXE e clicando com o

botão direito do mouse, escolher a opção Add... do menu de contexto.

Page 8: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

178

A partir daí abrirá uma janela Add to project. Alterar o tipo de arquivo

para Library file (*.lib) como mostra a figura a seguir e então selecione o arquivo

.LIB da biblioteca de funções a ser importada pressionando o botão Open.

Após isto a biblioteca será adicionada ao projeto da aplicação.

Page 9: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

179

As funções exportadas da DLL ficarão então disponíveis para o uso pela

aplicação. O protótipo das funções da DLL na aplicação deve usar o modificador

de acesso __declspec (dllimport):

__declspec(dllimport) tipo_de_retorno nome_da_função_importada(parâmetros);

88..77..22.. CCaarrrreeggaammeennttoo DDiinnââmmiiccoo Para carregar dinamicamente uma DLL durante a execução da aplicação

C++ Builder, pode se usar as funções da Windows API chamada LoadLibrary()

para carregar a DLL, então usar a função GetProcAddress() para obter ponteiros

para as funções individuais e finalmente a função FreeLibrary(). O programa

exemplo a seguir mostra o carregamento dinâmico da DLL da seção anterior.

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "UMain.h" HINSTANCE hinstLib; // manipulador de biblioteca static double(__stdcall *changeValue)(double,bool); // ponteiro para função //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { double x; // Pega um manipulador para o módulo DLL. hinstLib = LoadLibrary("DLL"); // Se o manipulador for válido, tenta pegar o endereço da função. if (hinstLib != NULL) { changeValue = (double (__stdcall *)(double,bool))GetProcAddress(hinstLib, "changeValue");

Page 10: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

180

// Se o endereço da função é válido, chama a função da DLL. if (changeValue != NULL){ x = changeValue(4.9,0); } else{ // Se não foi possível chamar a função da DLL, emite uma mensagem. ShowMessage("Não consegui achar a função"); } } // Se não foi possível chamar a DLL, emite uma mensagem. else{ ShowMessage("Não consegui achar a DLL"); return; } // A seguir a DLL pára de existir no espaço de endereçamento da memória para este programa. FreeLibrary(hinstLib); } //---------------------------------------------------------------------------

Uma forma alternativa de carregar uma DLL durante a execução de uma

aplicação C++Builder é incluir a biblioteca de importação, da mesma forma que o

carregamento estático, e então setar a opção delay load linker na opção de

menu Project + Options na aba Advanced Linker.

88..88.. CCrriiaannddoo DDLLLLss ccoonntteennddoo

ccoommppoonneenntteess VVCCLL Uma das forças das DLLs é que a DLL criada com uma ferramenta de

desenvolvimento pode freqüentemente ser usada por uma aplicação escrita

usando uma ferramenta diferente. Quando as DLLs contiverem componentes

VCL (tais como quadros) que podem ser utilizadas por outras aplicações, devem

se fornecidas rotinas exportadas que usam convenções padronizadas de

chamada evitando as chamadas especificas do C++ e que não requeiram que a

aplicação que por ventura possa chamar a DLL de ter que suportar a biblioteca

VCL para poder funcionar. Para criar componentes VCL que possam ser

exportados devem ser usados os packages de runtime.

Por exemplo, supor que se deseja criar uma DLL para mostrar a seguinte

janela de diálogo:

Page 11: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

181

O primeiro passo é iniciar um novo projeto com a opção de menu File +

New... Então, escolher a opção DLL Wizard e o botão OK.

O projeto criado deverá aparecer no Gerenciador de projetos da seguinte

forma:

Page 12: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

182

A partir daí usar a opção de menu File + Save Project As... para salvar o

projeto da DLL em uma nova pasta.

A seguir selecionar a opção de menu File + New Form. O Gerenciador de

Programas ficará da seguinte forma:

Como passo seguinte, selecionar o arquivo DLLMain.cpp e usando o botão

direto do mouse no menu de contexto escolher Remove From Project.

Page 13: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

183

A continuação usar a opção de menu File + Save All e salve o arquivo

default Unit1.cpp como DLLMain.cpp.

O Gerenciador de Programas ficará agora da seguinte forma:

A seguir, alterar o Form1 para ter a seguinte forma:

Renomeiar a propriedade Name do Label1 para LabelText, Button1 para

YesButton e Button2 para NoButton. Criar um gerenciador para o evento

OnClick para os dois botões. Depois disso, alterar os arquivos DLLMain.cpp e

DLLMain.h para ficar como segue.

Arquivo DLLMAIN.H

// DLLMAIN.H //---------------------------------------------------------------------

Page 14: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

184

#ifndef dllMainH #define dllMainH //--------------------------------------------------------------------- #include <vcl\Classes.hpp> #include <vcl\Controls.hpp> #include <vcl\StdCtrls.hpp> #include <vcl\Forms.hpp> //--------------------------------------------------------------------- class TYesNoDialog : public TForm { __published: // IDE-managed Components TLabel *LabelText; TButton *YesButton; TButton *NoButton; void __fastcall YesButtonClick(TObject *Sender); void __fastcall NoButtonClick(TObject *Sender); private: // User declarations bool returnValue; public: // User declarations virtual __fastcall TYesNoDialog(TComponent *Owner); bool __fastcall GetReturnValue(); }; // exported interface function extern "C" __declspec(dllexport) bool InvokeYesNoDialog(); //--------------------------------------------------------------------- extern TYesNoDialog *YesNoDialog; //--------------------------------------------------------------------- #endif

Arquivo DLLMAIN.CPP

// DLLMAIN.CPP //--------------------------------------------------------------------- #include <vcl\vcl.h> #pragma hdrstop #include "dllMain.h" //--------------------------------------------------------------------- #pragma resource "*.dfm" TYesNoDialog *YesNoDialog; //--------------------------------------------------------------------- __fastcall TYesNoDialog::TYesNoDialog(TComponent *Owner) : TForm(Owner) { returnValue = false; } //--------------------------------------------------------------------- void __fastcall TYesNoDialog::YesButtonClick(TObject *Sender) { returnValue = true; Close(); } //--------------------------------------------------------------------- void __fastcall TYesNoDialog::NoButtonClick(TObject *Sender) { returnValue = false; Close(); } //--------------------------------------------------------------------- bool __fastcall TYesNoDialog::GetReturnValue() { return returnValue; } //--------------------------------------------------------------------- // função de interface de exportação padrão C++ com uso da VCL

Page 15: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

185

bool InvokeYesNoDialog(){ bool returnValue; TYesNoDialog *YesNoDialog = new TYesNoDialog(NULL); YesNoDialog->ShowModal(); returnValue = YesNoDialog->GetReturnValue(); delete YesNoDialog; return returnValue; } //---------------------------------------------------------------------

Para criar a DLL usar a opção de menu Project + Build DLLVCL e o sistema

irá gerar os arquivos DLLVCL.DLL, DLLVLC.LIB e DLL.OBJ.

O código deste exemplo mostra uma janela de diálogo e armazena o valor

true no membro privado de dados returnValue se o botão Sim for pressionado.

Caso contrário returnValue será false. A função public GetReturnValue()

retorna o valor de returnValue quando chamada.

Para invocar a janela de diálogo e determinar qual botão foi pressionado, a

aplicação invocadora chama a função exportada InvokeYesNoDialog(). Esta

função é declarada em DLLMAIN.H como uma função de exportação usando a

ligação C (evitando o padrão C++) e outras convenções que possam limitar o uso

da DLL por programas feitos em outras linguagens. A função é definida em

DLLMAIN.CPP.

Pelo uso de funções padrões C como interface na DLL, qualquer aplicação

invocadora, criada ou não com C++ Builder, pode usar a DLL. A funcionalidade

da VCL requerida para suportar a janela de diálogo é ligada junto à DLL em si, e

a aplicação invocadora não precisará saber nada a respeito disso.

Notar que quando criar uma DLL que usa a VCL, os componentes

requeridos são ligados dentro da DLL resultando em uma quantidade razoável de

sobrecarga no tamanho da mesma. O impacto desta sobrecarga no tamanho total

da aplicação pode ser minimizado pela combinação de vários componentes em

uma única DLL que somente precisa uma única cópia dos componentes de

suporte da VCL.

Page 16: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

186

88..99.. CCrriiaannddoo uummaa AApplliiccaaççããoo qquuee

cchhaammaa ffuunnççõõeess ddaa DDLLLL ccoonntteennddoo

ccoommppoonneenntteess VVCCLL Para poder usar a DLL da seção anterior, criar uma nova aplicação usando

a opção de menu File + New Application. Como de praxe, continue a salvar a nova

aplicação em um novo diretório. Salvar a nova aplicação com novos nomes para o

arquivo .CPP e .PRJ no mesmo diretório onde estão os arquivos da DLL. Para este

exemplo, salvar Unit1.cpp como UChamaDLL.cpp e Project1.bpr como

ChamaDLLVCL.bpr.

A seguir, adicionar a biblioteca de exportação da DLL, usando o botão

direito do mouse no Gerenciador de Projeto, chamada DLLVCL.LIB. Assim o

gerenciador de programas deverá parecer como:

Alterar o Form1 para parecer da seguinte forma:

Crie um gerenciador de eventos para o OnClick do botão e acrescente a

declaração da função de exportação InvokeYesNoDialog() que vem da DLL. O

código de UChamaDLLVCL.cpp deverá aparecer como segue:

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop

Page 17: 08-DLL-C++BuilderV10

E N G E N H A R I A D E P R O C E S S A M E N T O D I G I T A L I I

187

#include "UChamaDLLVCL.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; extern "C" __declspec(dllimport) bool InvokeYesNoDialog(void); //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { bool bOption = InvokeYesNoDialog(); if (bOption) Label1->Caption = "Opção escolhida na DLL: SIM"; else Label1->Caption = "Opção escolhida na DLL: NÃO"; } //---------------------------------------------------------------------------

Executando o programa tem-se:

Pressionando o botão Chama Diálogo da DLL, invocando a função

exportada:

Pressionando o botão Sim, por exemplo:

Page 18: 08-DLL-C++BuilderV10

L U I S F E R N A N D O E S P I N O S A C O C I A N

188

A DLL retorna valor true, a janela da DLL é fechada e o aplicativo altera o

conteúdo de Label1->Text.