Dll - rotinas de início e término do processo/thread
Lambda! Lambda! Lambda!
Ja se faz um longo tempo que não posto aqui, e assuntos não faltaram como lançamento do Delphi 2009, Visual Studio 2010, o término do meu curso técnico em eletrônica - e falando nele estarei na FIERGS POA do dia 24/06 á 27/06 no INOVA SENAI.
Enfim que de falar e o assunto de hoje é sobre os eventos de entrada/saída da DLL no Delphi. Me deparei com um problema parecido estes dias, criei um aplicativo parecido com o gerenciador de serviço do Windows mas, com muitos plus (hehehehe), e todos os serviço se basseiam em uma DLL (aliás devo me lembrar de postar mais sobre ele, tem muita coisa enteressante nele que vale apena repassar para vocês). E uma das coisas que aprendi com ele, foi descobrir como capturar os eventos de entrada/saída da DLL.
A váriavel DLLProc global corresponder a um ponteiro de procedimento ao qual pode ser atribuído o precedimento de entrada/saída. Essa variável inicia-se em nil, ao menos que você defina seu própio porcedimento. Ao definir um procedimento de entrada/saída, será possível responder aos eventos listados:
DLL_PROCESS_ATTACH: A DLL será anexada ao espaço de endereços do processo atual, quando o mesmo iniciar ou quando for feita uma chamada para LoadLibrary(). As DLLs inicializam quaisquer dados da instância durante esse evento.
DLL_PROCESS_DETACH: A DLL será desanexada do espaço de endereços do processo de chamada. Isso ocorrerá durante a saída de um processo de limpeza ou quando for feita uma chamda para FreeLibrary(). A DLL pode liberar quaisquer dados da instância durante esse evento.
DLL_THREAD_ATTACH: Esse evento ocorrerá quando o processo atual criar um novo thread. Quando isso ocorrer, o sistema chamará a função de ponto de entrada de quaisquer DLLs anexadas ao processo. Essa chamada é feita no contexto de novo thread e pode ser usada para alocar quaisquer dados específicos ao thread.
DLL_THREAD_DETACH: Este evento ocorrerá quando o thread estiver saindo. Durante esse evento, a DLL pode liberar quaisquer dados inicializados específicos do thread.
Código-fonte para DllEntry.dpr:
library DllEntry; uses SysUtils, Windows, Dialogs, Classes; procedure DLLEntryPoint(dwReasson: DWord); begin case dwReasson of DLL_PROCESS_ATTACH: ShowMessage('Anexando ao processo'); DLL_PROCESS_DETACH: ShowMessage('Desanexando do processo'); DLL_THREAD_ATTACH : MessageBeep(0); DLL_THREAD_DETACH : MessageBeep(0); end; end; begin { Primeirto, atribui o procedimento à variável DLLProc } DllProc := @DLLEntryPoint; { Agora, chama o procedimento apra refletir se a DLL está anexada ao processo } DLLEntryPoint(DLL_PROCESS_ATTACH); end.
Código de exemplo para demonstração de entrada/saída da DLL:
unit ufrmPrincipal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TTestThread = class(TThread) procedure Execute; override; procedure SetCaptionData; end; TfrmPrincipal = class(TForm) btnLoadLibrary: TButton; btnFreeLibrary: TButton; btnCreateThread: TButton; btnFreeThread: TButton; Label1: TLabel; lblCount: TLabel; procedure btnLoadLibraryClick(Sender: TObject); procedure btnFreeLibraryClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnCreateThreadClick(Sender: TObject); procedure btnFreeThreadClick(Sender: TObject); private LibHandle : THandle; TestThread: TTestThread; Counter : Integer; GoThread : Boolean; end; var frmPrincipal: TfrmPrincipal; implementation {$R *.dfm} { TTestThread } procedure TTestThread.Execute; begin while frmPrincipal.GoThread do begin Synchronize(SetCaptionData); Inc(frmPrincipal.Counter); end; end; procedure TTestThread.SetCaptionData; begin frmPrincipal.lblCount.Caption := IntToStr(frmPrincipal.Counter); end; procedure TfrmPrincipal.btnCreateThreadClick(Sender: TObject); { Este procedimento cria a instância da TThread. Se a DLL for carregada, ocorrerá um bipe de mensagem. } begin if not Assigned(TestThread) then begin GoThread := True; TestThread := TTestThread.Create(False); end; end; procedure TfrmPrincipal.btnFreeLibraryClick(Sender: TObject); { Este procedimento libera a biblioteca } begin if not (LibHandle = 0) then begin FreeLibrary(LibHandle); LibHandle := 0; end; end; procedure TfrmPrincipal.btnFreeThreadClick(Sender: TObject); { Na liberação da TThread, um bipe de mensagem ocorrerá, se a DLL for carregada. } begin if Assigned(TestThread) then begin GoThread := False; while TestThread.Suspended do TestThread.Resume; TestThread.WaitFor; FreeAndNil(TestThread); Counter := 0; end; end; procedure TfrmPrincipal.btnLoadLibraryClick(Sender: TObject); { Este procedimento carrega a biblioteca DllEntryLib.dll } begin if LibHandle = 0 then begin LibHandle := LoadLibrary('DllEntry.dll'); if LibHandle = 0 then raise Exception.Create('Erro no carregar DLL'); end else begin MessageDlg('DLL ja carregada!', mtWarning, [mbOK], 0); end; end; procedure TfrmPrincipal.FormCreate(Sender: TObject); begin LibHandle := 0; TestThread := nil; end; end.
É um exemplo simples de como controlar o eventos básicos de uma DLL, mas como o desenvolvimento de uma DLL requer um bom estudo e cuidado com as pequenas coisas (isso também servira de base para os novos posts sobre serviços windows).
Download do exemplo.
Espero que tenham gostado, até próxima!
Att,
Mello.