Capítulo 7

Transcrição

Capítulo 7
Universidade Federal do Rio de Janeiro
N ú c l e o d e C o mputação Eletrônica
Divisão de Assistência ao Usuário
Capítulo 7
DINAMIC LINK LIBRARIES
Neste capítulo discutiremos o que é uma DLL, seus aspectos e tipos e ainda, porquê é
tão importante para as aplicações Windows
O QUE É UMA DLL?
Dinamic Link Libraries são módulos de programas que armazenam código, dados ou
recursos que podem ser compartilhados entre diversas aplicações Windows. Uma DLL
é funcionalmente equivalente a uma unit, pois representa uma coleção de funções
externas ao módulo principal da aplicação. A principal diferença entre DLL e unit está
no modo como são linkadas, pois a unit é linkada em tempo de compilação, enquanto
que a DLL é linkada em tempo de execução.
Um dos principais usos das DLLs é permitir que as aplicações carregam código
executável em run-time, ao invés de linkar o código a aplicação em compile-time.
As DLLs KERNEL32.DLL, USER32.DLL e GDI32.DLL são 3 das DLLs que compõem a
Win32. O Kernel32.dll é responsável pela gerência de memória, processos e threads. O
User32.dll possui rotinas para que a interface com o usuário possa criar janelas e
manipular mensagens, O Gdi32.dll, manipula gráficos. Outras DLLs importantes são:
ADVAPI32.DLL (gerencia a segurança de objetos e do Registry) e COMDLG32.DLL que
manipula janelas de diálogo.
Outra grande vantagem do uso de DLLs, é tornar a aplic ação modular, isso simplifica a
atualização da aplicação, pois só é necessário atualizar a DLL e não toda a aplicação. O
S.O. Windows é um grande exemplo de modularidade. Uma DLL é basicamente a
mesma coisa que uma programa executável, a principal diferença é que uma DLL não é
um arquivo executável independente, apesar de armazenar código executável. A
maioria das DLLs possuem a extensão .dll, porém existem outras extensões tais como:
.drv ( device driver), .sys (arquivos do sistema), .fon( recursos de fonte).
DLLs compartilham seu código com outras aplicações em um processo chamado
Linkagem Dinâmica. Quando uma aplicação usa uma DLL, a Win32 assegura que
somente uma cópia daquela DLL está em memória, esta tarefa é realizada através de
uma arquivo mapeado em memória, isto é, a DLL é carregada na heap da Win32 e
depois mapeada no endereço do processo chamador. Quando uma DLL é chamada por
múltiplos processos, cada processo recebe uma imagem da DLL. Isso não significa que
existem diversas copias da DLL em memória, A imagem da DLL é coloca na espaço de
endereçamento de cada processo, através do mapeamento da heap do sistema.
Delphi
Pag. 109
Universidade Federal do Rio de Janeiro
Núcleo de Computação Eletrônica
Divisão de Assistência ao Usuário
CRIANDO UMA DLL
Para criar uma DLL, selecione o item de menu File/New:
O Delphi cria o esqueleto de uma DLL, veja a figura abaixo:
Delphi
Pag. 110
Universidade Federal do Rio de Janeiro
N ú c l e o d e C o mputação Eletrônica
Divisão de Assistência ao Usuário
Uma vez gerado o código do esqueleto da DLL, basta adicionar o conjunto de funções
que serão exportadas. O código abaixo ilustra uma DLL de funções matemáticas
triviais.
library math;
uses
SysUtils,
Classes;
function pi : extended;
begin
result := 3.14159;
end;
function AreaCircunf(Raio: Extended): Extended; stdcall; export;
begin
result := pi*sqr(raio);
end;
function soma(A,B: Extended):Extended;stdcall; export;
begin
result := A+B;
end;
function Multiplica (A,B: Extended): Extended; stdcall; export;
begin
result := A*B;
end;
exports
AreaCircunf index 1,
Soma Index 2,
Multiplica index 3;
begin
end.
A função PI não está sendo exportada, pois é privada à DLL. Funções privadas em
DLLs só podem ser usadas no interior da library.
CARREAGANDO UMA DLL
Uma DLL pode ser carregada de duas maneiras distintas: Estaticamente ou
Dinamicamente. A escolha de como carregar uma DLL deverá levar em consideração a
vantagem e desvantagem de cada modo.
STATIC LINKING x DYNAMIC LINKING
A linkagem estática (Static Linking) refere-se ao método usado pelo compilador
Delphi para carregar a DLL, isto é, O método estático sempre referencia o mesmo
endereço de entrada na DLL e o Windows, ao carregar o aplicativo para a memória,
Delphi
Pag. 111
Universidade Federal do Rio de Janeiro
Núcleo de Computação Eletrônica
Divisão de Assistência ao Usuário
também carrega a DLL. Caso a DLL não seja encontrada, Windows não permite que o
aplicativo seja executado pois falta um componente essencial. A linkagem estática pode
ser feita através do .DPR ou da própria unit.
O código abaixo ilustra a importação de uma DLL estaticamente.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function Soma (A,B : Extended): Extended;
external 'teste.dll' index 2;
procedure TForm1.Button1Click(Sender: TObject);
begin
Soma(1,2);
end;
end.
A carga dinâmica (Dinamic Linking) a ligação entre a chamada da função e o código
executável é resolvido em run-time através do uso de uma referência externa à função
da DLL. Essa declaração geralmente é feita em uma unit separada chamada Import.
Esta unit declara as funções e procedimentos importados.
Suponha que você possui uma DLL chamada MAXLIB.DLL que possui a função:
Function Max(I1, I2 : integer): integer;
A unit Import será:
Unit MaxUnit;
Interface
Delphi
Pag. 112
Universidade Federal do Rio de Janeiro
N ú c l e o d e C o mputação Eletrônica
Divisão de Assistência ao Usuário
Function Max(I1, I2: Integer): Integer;
Implementation
Function Max; External ‘MaxLib’;
End.
Este exemplo ilustra uma das duas formas de fazer uma carga dinâmica, ele é chamado
Implicit Loading. A outra forma de fazer a carga dinâmica de uma DLL é através do
uso da API LoadLibrary( ). Neste caso, chamamos de Explicit Loading.
Deve-se atentar para o modo de carga de uma DLL. Por exemplo, suponha que uma
DLL possua muitas funções e nem sempre sua aplicação faz uso dessas rotinas, logo, se
a carga da DLL for implícita, haverá um desperdício de memória, então neste caso
deve-se fazer uma carga explícita.
A Win32 possui funções específicas para DLLs, a saber: LoadLibrary( ), FreeLibrary( )
e GetProcAddress( ).
LoadLibrary( )
FreeLibrary( )
GetProcAddress( )
Faz a carga de uma DLL e faz seu mapeamento no espaço de
endereçamento do p rocesso.
Libera a instância da library
Retorna o endereço de uma função
O exemplo abaixo ilustra uma carga explícita:
procedure TMainForm.btnGetCalendarClick(Sender: TObject);
var
LibHandle
: THandle;
ShowCalendar: TShowCalendar;
begin
{ Tenta carregar a DLL }
LibHandle := LoadLibrary('CALENDARLIB.DLL');
try
if LibHandle = 0 then
raise EDLLLoadError.Create('Unable to Load DLL');
@ShowCalendar := GetProcAddress(LibHandle, 'ShowCalendar');
if not (@ShowCalendar = nil) then
lblDate.Caption := DateToStr(ShowCalendar(Application.Handle, Caption))
else
RaiseLastWin32Error;
finally
FreeLibrary(LibHandle); // Descarrea a DLL.
end;
end;
EXCEPTIONS em DLLs
Nas versões anteriores do Delphi , fazia -se necessário verificar se ocorreria uma
exception na DLL, caso ocorre-se a exception ela deveria ser capturada antes que
escapa-se da DLL. No Delphi 4 isso não é mais necessário pois as exceptions do Delphi4
Delphi
Pag. 113
Universidade Federal do Rio de Janeiro
Núcleo de Computação Eletrônica
Divisão de Assistência ao Usuário
são mapedas como exceptions da Win32. Para que isso funcione, você deve incluir a
unit SysUtils na cláusula uses da DLL.
A DIRETIVA SAFECALL
Funções do tipo SafeCall são usadas em manipulação de exceções e no COM, que
garantem que qualquer exceção será propagada ao chamador da função. Resumindo,
uma função do tipo SafeCall converte a exceção em um valor de retorno HResult. Veja
um exemplo da sintaxe de uma função SafeCall:
Function
NCE_UFRJ(Serra : Integer): Integer; Safecall;
O compilador enxerga a função como:
Function
NCE_UFRJ(Serra : Integer): Integer; HResult; StdCall;
O compilado ainda insere implicitamente um bloco Try..Except que envolve toda o
conteúdo da função e captura qualquer exceção.
HOUSEKEEPING
Algumas vezes, necessitamos desalocar estruturas alocadas durante a execução de uma
DLL. A melhor maneira de fazer isso é implementar toda a funcionalidade da DLL em
unit a serem utilizadas pela DLL. O código para desalocar as estruturas poderia ser
colocado na cláusula Finalization das units que fazes as alocações. Recomenda-se que
toda unit que possui uma sessão Initialization também inclua uma sessão Finalization.
LOCALIZAÇÃO DOS .DLL
Para garantir que uma DLL será encontrada no momento de sua chamada, é necessário
que ela esteja em um dos seguintes diretórios:
•
•
•
•
Delphi
Diretório do programa executável;
Diretório \WINDOWS
Diretório \WINDOWS\SYSTEM
Ou qualquer outro diretório mencionado na variável de ambiente PATH.
Pag. 114