srceensaver
Transcrição
srceensaver
LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho CRIANDO UM SCREEN SAVER (Protetor de tela) Introdução: ScreenSaver são programas que possuem algumas características especiais: 1. 2. 3. 4. devem ter a extensão (*.SCR) devem ocupar toda a tela e o formulário não poderá ter bordas. devem poder reconhecer parâmetros de entrada devem ser executados apenas uma vez (uma única instância), isto é, não podem ser chamados novamente se já estiverem em execução 5. devem interromper a execução depois de que alguma tecla seja acionada, ou botão do mouse ou movimento do mesmo 6. devem chamar rotinas de senha quando tiver alguma senha habilitada Extensão SCR: Para que o programa, depois de compilado, receba a extensão SCR ao invés de EXE, use a diretiva de compilação {$E SCR} no programa principal. program ScreenSaver; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$E SCR} {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. Cobrir toda a tela: Altere as propriedades do formulário: • BorderStyle bsNone • WindowState wsMaximized • BorderIcons (todos false) Protetor de tela (ScreenSaver) - Página 1 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Parâmetros de entrada: Parâmetros de entrada são aqueles que se colocam ao lado do programa executável quando o mesmo é acionado. Para explicar melhor, vamos imaginar que você esteja no modo DOS e deseja formatar um disquete com o sistema operacional. Para fazer isto você digita: C:/> FORMAT A: /S No comando acima, o programa FORMAT.COM é acionado passando-se 2 parâmetros: o primeiro é “A:” (nome do drive) e o segundo é “/S” (transfere o sistema operacional). Se você quiser colocar parâmetros em programas “for windows” deverá utilizar o atalho para o mesmo e aí acrescentar na propriedade do mesmo os valores pretendidos: Programas do tipo “Screen Saver” são chamados pelo Windows passando parâmetros, que dependem do serviço solicitado pelo usuário: amostra, senha, configuração, etc... Enumeramos, a seguir, estes parâmetros com seu significado: • /s ou –s ou S • • /c ou –c ou C /p ou –p ou P • • /A ou –a ou A sem parâmetros quando o programa é ativado automaticamente pelo Windows quando é acionado o botão de configuração quando é acionado na janela de Preview. Possui um segundo parâmetro: que é um manipulador de janela onde o preview será apresentado. quando o usuário pede para alterar a senha quando o usuário dá um duplo clique no programa. O programa deverá prever cada um destes parâmetros, chamando a rotina de tratamento de cada caso. Faça assim: Protetor de tela (ScreenSaver) - Página 2 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho No programa principal, acrescente as linhas em destaque: program ScreenSaver; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$E SCR} {$R *.RES} function PegaParam(p: string): char; begin P:= UpperCase(P); While NOT (P[1] in ['S','A','P','C']) do delete(p,1,1); Result:= p[1]; end; begin Application.Initialize; If ParamCount > 0 then Case PegaParam(ParamStr(1)) of 'S': If FindWindow('TForm1','Protetor de tela') = 0 then Application.CreateForm(TForm1, Form1); // 'C': Chama configuração; // 'A': Configura a Senha // 'P': Mostra o Preview else begin Application.terminate; Halt; Form1.free; end; end; Application.Run; end. Executar apenas uma instância: Uma das formas é procurar pelo aplicativo no ambiente do Windows. Esta procura pode ser feita através de um comando da API que localiza o formulário de um aplicativo que esteja rodando. Este comando é FindWindow, que tem a seguinte sintaxe: FindWindow(nome da classe, caption do objeto) Retorna o valor da instância se encontrar, ou ZERO caso contrário. Protetor de tela (ScreenSaver) - Página 3 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Testando a senha: Existe no registro do Windows, exatamente em: HKEY_CURRENT_USER\Control Panel\Desktop\ a chave ScreenSaveUsePassword, cujo valor, se for diferente de zero, indica que existe uma senha para o ScreenSaver. Para testarmos se a senha está correta, fazemos uso da função GetProcAddress, que compara a senha digitada com a guardada no arquivo PASSWORD.CPL, através da rotina VerifyScreenSavePwd. Para você entender o que é uma chave de registro do Windows, vamos acessar o registro do Windows MANUALMENTE: • • • • Clique no botão INICIAR Escolha a opção Executar Agora digite o nome do programa que edita o registro do Windows. Este programa chama-se REGEDIT. Esta operação é perigosa, pois, o registro é a alma de todo o Windows; qualquer alteração mal feita pode fazer com que o Sistema pare de funcionar. É prudente fazer uma cópia deste registro antes de fazer qualquer alteração. No Windows 98, o registro fica gravado em dois arquivos localizados na pasta \Windows: System.Dat e User.Dat. Depois de mandar executar o REGEDIT você verá a seguinte tela: • Agora clique na chave HKEY_CURRENT_USER e localize a seqüência de pastas: Control Panel \ Desktop. • Dentro desta última, você poderá verificar, do lado direito, a chave: ScreenSaveUsePassword. Se o valor que estiver na sua frente for zero, significa que não existe senha para o ScreenSave que está ativo no momento: Protetor de tela (ScreenSaver) - Página 4 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho A senha deverá ser testada toda vez que tentarmos encerrar o programa, isto é: quando movermos o mouse ou quando clicarmos em qualquer tecla do teclado. Portanto, vamos criar os métodos para estes dois eventos: procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if i > 1 then Verifica_senha //Termina else Inc(i); end; è Declarar a variável I como integer, globalmente. procedure TForm1.Termina; begin Form1.windowstate:= wsNormal; Application.terminate; end; procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin Verifica_senha; //Termina; end; Protetor de tela (ScreenSaver) - Página 5 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Você pode notar que criamos uma rotina chamada “Termina”. Não esqueça de declará-la na cláusula “public” do objeto TForm1. Agora vamos também criar a rotina que testa a senha, que da mesma forma, deverá ser declarada na cláusula “public” de TForm1: procedure TForm1.Verifica_senha; Var Reg: TRegistry; SysDir: string; TamDir: integer; LibSenha: THandle; FuncSenha: function(ParentWnd: THandle): boolean; stdcall; Begin Reg:= TRegistry.Create; // cria o objeto Reg Reg.RootKey:= HKEY_CURRENT_USER; // especifica qual é a chave-raiz do registro If Reg.OpenKey('Control Panel\Desktop',false) then // abre a pasta “Desktop” que está // em "Control panel" // Se existir a chave ... If Reg.KeyExists('ScreenSaveUsePassword') then If Reg.ReadInteger('ScreenSaveUsePassword') <> 0 then // verifica se a constante // ScreenSaveUsePassword é diferente de zero. // Se for, é porque foi especificada uma senha para o // Screen Saver ativo. Begin SetLength(SysDir,MAX_PATH); // modifica o tamanho máximo da variável SysDir // de acordo com a constante MAX_PATH que // informa o total máximo de caracteres admitido // para caminhos de arquivo (path). TamDir:= GetSystemDirectory(PChar(SysDir),MAX_PATH); // agora // pega o nome do caminho do // diretório System, colocando// o na variável SysDir, assim // como conta o número de // caracteres que possui, // colocando em TamDir. SetLength(SysDir,TamDir); // Agora, corrige o tamanho de SysDir para o verdadeiro // tamanho utilizado. If (SysDir <> '') and (SysDir[Length(SysDir)] <> '\') then SysDir:= SysDir + '\'; // Testa se nesta versão do Windows ele coloca como // último caractere do caminho a barra invertida. Se ela não // estiver lá, acrescenta. LibSenha:= LoadLibrary(PChar(SysDir+'PASSWORD.CPL')); // A // variável LibSenha guarda o "Handle" da // biblioteca "Password.cpl" quando a mesma é // carregada na memória pela função LoadLibrary. If LibSenha <> 0 then // Se o valor do Handle for diferente de zero é porque o arquivo foi // encontrado. Begin FuncSenha:= GetProcAddress(LibSenha,'VerifyScreenSavePwd'); // A variável FuncSenha, do tipo FUNCTION, recebe o endereço da rotina // "VerifyScreenSavePwd" que se encontra na bibliotec Password.cpl Protetor de tela (ScreenSaver) - Página 6 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho If Assigned(FuncSenha) and not FuncSenha(Handle) // A função Assigned executa a função através de // seu endereço. Se retornar "true" é porque tudo // correu bem. then // se a função FuncSenha retornar "False" é // porque o usuário clicou em cancela ou // errou a senha. begin FreeLibrary(LibSenha); // se cancelou ou errou a senha, a biblioteca é // descarregada da memória ... Exit; // ... e saímos da rotina end; FreeLibrary(LibSenha); end; end; Reg.Free; // liberamos o objeto Reg Termina; // executamos a rotina de término do programa a rotina Termina só será chamada se a // senha tiver sido acertada ou não tiver senha. end; Mostrando Preview: Um manipulador (Handle) de janela é passado quando um preview é mostrado. Portanto, temos que “pegar” este manipulador e direcionar a nossa rotina de preview para a respectiva janela. Para que a rotina seja chamada, você deverá colocar no programa principal a linha correspondente ao parâmetro de preview: “/P”. begin Application.Initialize; If ParamCount > 0 then Case PegaParam(ParamStr(1)) of 'S': If FindWindow('TForm1','Protetor de tela') = 0 then Application.CreateForm(TForm1, Form1); // 'C': Chama configuração; // 'A': Altera a senha; 'P': MostraPreview(StrToInt(ParamStr(2))); else begin Application.terminate; Halt; Form1.free; end; end; Application.Run; end. Protetor de tela (ScreenSaver) - Página 7 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Outra providência será a de acrescentar ao projeto (arquivo do programa) as bibliotecas: SysUtils, Types, Graphics, Windows e Dialogs. program screensaver; uses Forms, SysUtils, Types, Graphics, Windows, Dialogs, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; Já na Unit1 acrescente a biblioteca Registry. unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Registry; A rotina Mostra Preview será escrita no projeto e não na Unit. Portanto, passe para o projeto e digite: procedure MostraPreview(HandJan: integer); var R: TRect; Canvas: TCanvas; LargJan, AltJan, I: integer; procedure Desenha; begin // cabeça Canvas.Ellipse(LargJan-i-10,AltJan-50,LargJan-i-20,AltJan-60); // corpo Canvas.MoveTo(LargJan-115,AltJan-50); Canvas.LineTo(LargJan-115,AltJan-20); // pernas Canvas.LineTo(LargJan-120,AltJan-10); Canvas.MoveTo(LargJan-115,AltJan-20); Canvas.LineTo(LargJan-110,AltJan-10); // braços Canvas.MoveTo(LargJan-115,AltJan-40); Canvas.LineTo(LargJan-125,AltJan-30); Canvas.MoveTo(LargJan-115,AltJan-40); Canvas.LineTo(LargJan-105,AltJan-30); Application.processmessages; end; Protetor de tela (ScreenSaver) - Página 8 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho begin // a janela de preview pode demorar a aparecer ... while not IsWindowVisible(HandJan) do Application.processmessages; // determina as dimensões da janela GetWindowRect(HandJan,R); LargJan:= R.Right - R.Left; AltJan:= R.Bottom - R.Top; // cria um canvas para a janelinha Canvas:= TCanvas.create; // coloca o canvas no mesmo local da janelinha Canvas.Handle:= GetDC(HandJan); // executa o preview enquanto a janelinha for visível I:= 0; While IsWindowVisible(HandJan) do Begin /////////// rotina que executa a animação do preview ///////////// If i < 100 then Inc(i,10) else i:= 10; Canvas.Brush.Color:= clWhite; Canvas.Ellipse(LargJan-i-10,AltJan-10,LargJan-i-20,AltJan-20); Application.processmessages; Sleep(200); Canvas.Brush.Color:= clBlack; Canvas.Ellipse(LargJan-i-10,AltJan-10,LargJan-i-20,AltJan-20); Application.processmessages; If i = 100 then begin Canvas.Brush.Color:= clWhite; Canvas.pen.Color:= clWhite; Desenha; Sleep(1000); // apagando desenho Canvas.Brush.Color:= clBlack; Canvas.pen.Color:= clBlack; Desenha; end; //////// Final da rotina que executa a animação //////////// end; // retira-se o objeto Canvas da janelinha ReleaseDC(HandJan,Canvas.handle); // destruímos o objeto Canvas Canvas.free; end; Protetor de tela (ScreenSaver) - Página 9 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Configuração: Para termos a possibilidade de configurar o nosso ScreenSaver, podemos inserir um novo formulário, e nele programarmos a configuração. Poderíamos programar aqui a velocidade com que as figuras serão mostradas, etc... Não se pode esquecer de ativar o parâmetro “/C” no programa principal. Para isto, depois de ter inserido o novo formulário (Form2), você perceberá a criação automática da linha: Application.CreateForm(TForm2, Form2); Você deverá, então, transportá-la para o local correto, isto é, diante da verificação do parâmetro “/C” (veja a linha em negrito abaixo): begin Application.Initialize; If ParamCount > 0 then Case PegaParam(ParamStr(1)) of 'S': If FindWindow('TForm1','Protetor de tela') = 0 then Application.CreateForm(TForm1, Form1); 'C': Application.CreateForm(TForm2, Form2); // 'A': Altera a senha; 'P': MostraPreview(StrToInt(ParamStr(2))); else begin Application.terminate; Halt; Form1.free; end; end; Application.Run; end. ♦ Agora, volte ao formulário “Form2” e acrescente ao mesmo um objeto “SpinEdit” (encontrado na aba “Samples”), um “Label” (aba Standard), e dois “SpeedButton” (aba “Additional”): ♦ Acrescente ao Método “OnCreate” do formulário “Form2” os comandos que aparecem em negrito, cuja função é a de ler/criar um arquivo-texto contendo o tempo de exposição dos quadros da animação, fizemos isto, criando uma rotina que é chamada pelo método. Observe as variáveis locais declaradas. Protetor de tela (ScreenSaver) - Página 10 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho unit Unit2; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Spin, Buttons; type TForm2 = class(TForm) SpeedButton1: TSpeedButton; SpeedButton2: TSpeedButton; SpinEdit1: TSpinEdit; Label1: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public procedure Valor_do_Tempo(var tempo: integer; grava: boolean); end; var Form2: TForm2; implementation Para tentar ler o arquivo. Quando “true” a rotina somente grava. {$R *.DFM} Uses Unit1; procedure TForm2.FormCreate(Sender: TObject); begin tempo:= 400; Valor_do_Tempo(tempo,false); SpinEdit1.value:= tempo; end; L? procedure TForm2.Valor_do_Tempo(var tempo: integer; grava: boolean); var DirProg, Arquivo: string; Arq: TextFile; begin DirProg:= ExtractFilePath(Application.ExeName); Arquivo:= DirProg+'ScreenSaver.cfg'; AssignFile(arq,Arquivo); If not grava then begin If not FileExists(arquivo) then begin Protetor de tela (ScreenSaver) - Página 11 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho Rewrite(arq); Writeln(arq,tempo); CloseFile(arq); end; Reset(arq); Readln(arq,tempo); end else begin Rewrite(arq); Writeln(arq,tempo); end; CloseFile(arq); end; end. Protetor de tela (ScreenSaver) - Página 12 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho ♦ Uma variável foi declarada GLOBALMENTE NA UNIT1: “Tempo”, do tipo integer. Foi declarada naquela Unit porque é necessária também nela. ♦ Tomamos o cuidado de criar uma declaração USES dentro da Unit2 referenciando a Unit1, justamente para que pudesse compartilhar a declaração da variável “Tempo”. ♦ Você pode estar estranhando a declaração da variável “tempo” ? ela foi declarada localmente como parâmetro da rotina “Valor_do_Tempo(var tempo: integer)”, só que utilizamos a palavra “var” colocada antes da mesma. Ao fazermos isto, a variável “tempo” ficou funcionando como parâmetro de entrada e como parâmetro de saída de dados, para que o valor de “tempo” que foi alterado dentro da rotina pudesse ser utilizado globalmente. ♦ Ao declararmos “tempo” globalmente dentro da Unit1, esta variável, na realidade não é a mesma variável que foi declarada como parâmetro na rotina “Valor_do_Tempo”, pois, elas ocupam lugares diferentes na memória. Elas são homônimas, mas não representam o mesmo local de armazenamento de dados na memória. ♦ Vamos agora a outros eventos, como por exemplo o botão Cancela: procedure TForm2.SpeedButton2Click(Sender: TObject); begin Form2.close; end; Usei “true” porque eu quero gravar o valor do tempo. ♦ Agora, o botão OK: procedure TForm2.SpeedButton1Click(Sender: TObject); begin tempo:= SpinEdit1.value; Valor_do_Tempo(tempo,true); Form2.close; end; Alterando a senha: É um pouco complicado realizar esta tarefa. Vamos tentar explicar: Existe uma DLL que contém a função que altera a senha, esta função é “PwdChangePasswordA” e a biblioteca dinâmica é MPR.DLL. Deve-se passar a constante “SCRSAVE” como primeiro parâmetro e o manipulador da janela (Handle) como segundo parâmetro. Manipulador de janela é uma variável utilizada pelo Windows para identificar as janelas que estão “rodando”. Ative o parâmetro “/A” do programa principal: begin Application.Initialize; If ParamCount > 0 then Case PegaParam(ParamStr(1)) of Protetor de tela (ScreenSaver) - Página 13 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho 'S': If FindWindow('TForm1','Protetor de tela') = 0 then Application.CreateForm(TForm1, Form1); 'C': Application.CreateForm(TForm2, Form2); 'A': Confsenha(StrToInt(ParamStr(2))); 'P': MostraPreview(StrToInt(ParamStr(2))); else begin Application.terminate; Halt; Form1.free; end; end; Application.Run; end. Agora, digite os comandos a seguir no programa principal (projeto): : : {$R *.RES} procedure ConfSenha(HandJan: integer); var SysDir: string; TamDir: integer; LibSenha: THandle; FuncSenha: function(lpProvider: LPCTSTR; hwndOwner: hWnd; dwFlags: DWord; Reserved: DWord): DWord; stdcall; // fizemos com que a função FuncSenha tenha as mesmas características de uma // função cujos parâmetros são os declarados (PwdChangePasswordA) begin // determina o caminho do diretório System SetLength(SysDir,MAX_PATH); TamDir:= GetSystemDirectory(PChar(SysDir), MAX_PATH); SetLength(SysDir,TamDir); If (SysDir <> '') and (SysDir[length(SysDir)] <> '\') then SysDir:= SysDir + '\'; // abre MPR.DLL LibSenha:= LoadLibrary(PChar(SysDir + 'MPR.DLL')); // se a DLL for encontrada e estiver tudo bem ... If LibSenha <> 0 then begin // determinando o endereço de PwdChangePasswordA FuncSenha:= GetProcAddress(LibSenha,'PwdChangePasswordA'); // chamamos a função através do seu endereço. Se ela existir ... If Assigned(FuncSenha) // chamamos a mesma passando os parâmetros exigidos then FuncSenha('SCRSAVE',HandJan,0,0) // se ela não existir, emitimos mensagem de erro else ShowMessage('Erro ao abrir a função'); // liberamos a biblioteca FreeLibrary(LibSenha); Protetor de tela (ScreenSaver) - Página 14 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho end else ShowMessage('Erro ao abrir a biblioteca MPR.DLL'); Halt; // saímos do programa end; O PROGRAMA PROTETOR DE TELA: Até o momento, nós mostramos como criar um protetor de tela geral, isto é, não incluímos ainda nenhum algoritmo que apareça quando o protetor de tela entra em ação. Este algoritmo ficará no método do evento OnCreate do Form1, onde também deverá estar incluída uma linha que informa o valor da propriedade caption do Form1. Este valor é importante, pois, a rotina que impede o programa de ter mais de uma instância testa o caption dos formulários que estão “rodando” no computador. Se ele encontrar algum caption com o texto “Protetor de tela” o programa considerará que ele já está no ar e portanto não carregará denovo. procedure TForm1.FormCreate(Sender: TObject); begin Form1.caption:= 'Protetor de tela'; // COLOQUE AQUI O SEU ALGORITMO DE PROTEÇÃO DE TELA end; Para o seu protetor de tela funcionar regularmente, inclua o código do mesmo aqui. Ok ? J J J J J J J J J J J J J J J J J J J J J J J J J J Protetor de tela (ScreenSaver) - Página 15 - LINGUAGEM DE PROGRAMAÇÃO DELPHI Prof. Alberto Cezar de Carvalho INCLUINDO UM PROGRAMA DE SCREENSAVER 1) Acrescente ao Form1 um objeto Timer. 2) No evento OnTimer deste objeto coloque os seguintes comandos: procedure TForm1.Timer1Timer(Sender: TObject); begin Case c of 0: Form1.color:= clRed; 1: Form1.color:= clGreen; 2: Form1.color:= clBlue; 3: Form1.color:= clYellow; 4: Form1.color:= clfuchsia; 5: Form1.color:= clPurple; 6: Form1.color:= clWhite; end; If c >= 6 then c:= 0 else inc(c); end; 3) Declare a variável “C” globalmente, do tipo integer. 4) Na rotina acima, o objetivo é ir mudando a cor do formulário a cada segundo. 5) No OnCreate do Form1, acrescente o comando “ShowCursor” para fazer o cursor desaparecer. procedure TForm1.FormCreate(Sender: TObject); begin Form1.caption:= 'Protetor de tela'; // COLOQUE AQUI O SEU ALGORITMO DE PROTEÇÃO DE TELA ShowCursor(false); end; 6) Pronto ! J J J J J J J J J J J J J J J J J J J J J Protetor de tela (ScreenSaver) - Página 16 -