João Mello

June 27, 2009

Dll - rotinas de início e término do processo/thread

Filed under: Cotidiano, Delphi, Dica, Karmas — Tags: , , , — joaomello @ 12:34 pm

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.

January 25, 2009

IsWindow – Verificando se handle existe

Filed under: Delphi, Dica, Karmas — joaomello @ 12:25 pm

Tudo certo delpheiros?!

O assunto que vou tratar hoje, é sobre um pequeno problema que me ocorreu estes dias… Eu tinha um handle de uma janela, mas queria saber se ela ainda existia.
Muito bem, muitos devem estar pensando nessa hora, por que não usa o FindWindow?! É simples! No FindWindow você passa como parâmetro o nome da classe e o caption dela – eis meu problema – mas a possibilidade de vir uma outra janela com os mesmo parâmetros era muito grande… E eu queria a quela, que eu já havia pego. Pois bem, foi aí que encontrei o FindWindow.
O método FIndWindow é simples de usa veja a sintax a baixo:

BOOL IsWindow(HWND hWnd);

Você só precisa passar o handle, que retornará um true ou false.
Vamos colocar a mão na massa!

Crie um novo projeto VCL Forms Application:

E no form que ja vem criado, coloque dois SpeedButton(ou qualquer outro tipo de botão):

E crie outro form com um Label no meio, com caption “Hello World!”:

E adicione o seguinte código no Form1:

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, Unit2;
 
type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
  private
    hHandle: HWND;
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  frm.Show;
  hHandle := frm.Handle;
end;
 
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  if hHandle > 0 then
  begin
    if IsWindow(hHandle) then
      ShowMessage('Janela existe!')
    else
      ShowMessage('Janela não existe.');
  end;
end;
 
end.

Analisando o código do Form1:
Na procedure SpeedButton1Click, estamos criando um novo form e colocando o seu handle em uma váriavel local.
E na procedure SpeedButton2Click, estamos implementando o IsHandle.

Coloque o seguinte código no Form2:

unit Unit2;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm2 = class(TForm)
    Label1: TLabel;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;
 
end.

Analisando o código do Form2:
A única coisa que foi feita no Form2, foi mudar o Action para caFree(para que quando o formulário for fechado ele também seja destruído, e não persista) no evento FormClose.

Resultado:
Quando você for executar o exemplo vera que quando o Form2 estiver a aberto o IsWindow voltara com True e quando estiver fechado(e destruído) voltara com False.

Você até pode pensar que o exemplo foi simples, mas agora imagine que você automatizou o processo de download(exemplo no IE), e quer pegar a janela de progresso para saber em quantos porcentos esta e se o download ja acabou? O úsuario pode dar mais downloads, e novas janelas virem com mesmo nome e classe, mas você quer aquela em especifica… [É... acho que falei muito...  mas em um próximo artigo demonstro como fazer download automatico pelo IE ;) ]

Enfim… era isso. E um bom final de semana á todos!

Abraço,
Mello.

January 5, 2009

‘Indiguinação’ com Claro 3G - RS Parte 1

Filed under: Cotidiano, Dica, Karmas, Ponto de vista — joaomello @ 10:26 pm

Cara leitor, a idéia era manter um um blog aonde um pudesse compartilhar exemplos e pontos de vista, em meus horários vagos. Porém, nem isso me é permitido. No Meio de 3 posts, a internet cai e não reconecta mais, ou quando cai, volta mais fica caindo toda hora. Isso sem falar da velocidade, pago por 1Mb mas acesso 100kb no máximo! (eles deveriam de me dar no minimo 300kb). Isso não é o pior, ja que estou á mais de três messes pagando uma conta de R$99,00 para ter uma coisa que me da dor de cabeça ao conecetar a internet.

No ínicio foi bem diferente, minha conexão baseava-se em 800kb (poxa isso pra mim é d+), mas passou alguns messes e a coisa não foi bem assim… E nem adianta alegar tráfego maior que 1GB para ter cortado a internet, pois mais consigo acessa a página principal do Google(isso mesmo).

Enfim, delculpas por esse desabafo… Mas isso ta irritante já! A Claro fez uma propaganda, sobre carregou o sistema, piorou a qualidade e nada fez(aliás enquanto isso minha conexão ja caiu mais de 5x).
Se você esta pensando em adquirir digo, guarde seu money ou veja as da concorrente.

Essa é a primeira parte de uma série, amanhã estarei ligando para eles do trabalho… E começei a escrever colunas por lá mesmo. Ja chega disso como desculpas.

Abraço,
Mello.

Update: Sou cliente Vivo hoje, e 3G no Brasil ainda ta mau.

September 8, 2008

Consultar CEP direto pelo site dos correios

Filed under: Delphi, Karmas, Open Source — joaomello @ 12:32 am

Olá pessoal!
Como muitas ja devem saber, o correios bloqueou o a consulta de CEP direto pelo site. Eu como um jovem aprendiz, descobri um caminho de como fazer a consulta direto pelo site no Delphi. É simples, não dei uma bela implementada…

Baixar o exemplo.

[ No exemplo a ordem dos botões deve ser clicada cada vez que a página for carregada. ] 

Enfim, que der um encrementada no código (por que to sem tempo), diz ai que eu posto aqui ;]
Bom proveito!

Abraço,
Mello.

Powered by WordPress