domingo, 3 de abril de 2011

Como Consultar entre Datas no Delphi/Interbase.


Bom, estou aqui novamente para esclarecer algumas coisas sobre o artigo que escrevi anteriormente, após o artigo “Como Trabalhar com Data e Moeda no Delphi/Interbase”, recebi vários email´s e conheci muitas pessoas no MSN, por isso estou aqui novamente para dar mais uma pequena contribuição à comunidade Delphi e lembrando que é para iniciantes, programadores avançados talvez achem até sem importância para eles mas para mim foi crucial e deve ser também para outras pessoas.
Eu sei que esse assunto é no mínimo chato, mas mesmo assim vamos lá. Dessa vez vou abordar apenas datas que dão uma grande dor de cabeça no Interbase, acabo de desenvolver dois programas, um de controle de membros e colaboradores de uma Igreja e o outro para Tabelionato de Notas, apesar de serem completamente diferentes, consegui ao desenvolver os dois tirar muitas dúvidas sobre datas, por exemplo, Cartórios de Notas, todas as autenticações e demais atos que são feitos são recolhidos para o Estado (SecFaz, IPESP, etc.) e isso gera uma guia conhecida como GARE, que o cartório é obrigado a preencher diariamente, e para isso é preciso contar todos os atos realizados no dia, pegar o valor correspondente e multiplicar, além disso, escrever todo o conteúdo no campo de descrição da guia.

Com o software que eu desenvolvi, isso ficou muito fácil, pois todos esses dados estão em apenas uma tabela, é só dar um select, jogar os valores encontrados em campos pré-definidos (tipo EditQAut.text, EditvlAut.text) ou também em variáveis do tipo double fazendo as contas usando as velhas equações de 1º e 2º grau, aí é só pegar os dados encontrados e jogados nos edits correspondentes e mandar escrever em um campo qualquer:


Exemplo:


Na tabela DIARIO, existem os campos: Q_Aut Integer, Vl_Aut Numeric(9,2) e Data Date: (o campo “Q_aut”, serve para guardar a quantidade total de autenticações realizadas no dia; o campo “Vl_Aut”, para guardar a multiplicação dessas autenticações pelo preço unitário, que por sua vez é armazenado em uma outra tabela que chamei de CUSTAS, mas não vem ao caso, e o campo Data para guardar o dia que foi realizado as autenticações).

Em tempo: esses valores são encontrados previamente pelo cliente através de cálculos e opções fornecidas pelo software, entenda que estamos trabalhando já com o valor final, e não unitário tipo PDV que registra um-a-um, é como se já se tivesse fechado o caixa e estivesse querendo gerar um relatório com os dados finais.

Primeiro passo, dar um select para saber os dados do dia:


Var

C:string;
begin
C:=('select * from Diario where (Data = '#39+editdata.text+#39')');
IBQuery1.SQL.clear;
IBQuery1.sql.add(c);
IBQuery1.Open;
while IBQuery1.Eof = false do
begin
EditQAut.text:= IBQuery1.fieldbyname('Q_Aut').AsString;
EditVlAut.text:= IBQuery1.fieldbyname('Vl_Aut').AsString;
end;
end;

A declaração da variável “C: string” poderia ser de modo global, para não se repetir esse comando, dessa forma, o programa iria exibir nos edits em questão os valores contidos na tabela DIARIO. Aí logo após eu precisei escrever esses dados por extenso em um memo chamado “Mdescricao” e ficou desta forma:


MDescricao.text:= 'Hoje tiveram '+EditQAut.text+' Autenticações, que no total somou R$ '+EditvlAut.text;


Resolvi meu primeiro problema facilmente, bem simples, pois esta tudo na tabela chamada DIARIO, a Data, a Quantidade total do dia e o Valor Total, o “X” da questão foi quando me disseram que a guia que é gerada para instituição chamada IPESP não é diária, é semanal. Putz, como fazer um select entre duas datas e ainda por cima somando quantidades inteiras e valores monetários?????. Lí um e-mail que me fizeram essa mesma pergunta só que utilizando Acces, já havia lido vários artigos e dicas pela net e percebi que a resposta já estava lá, apenas precisava ser mais bem trabalhada, então achei uma solução:


Primeiro eu tinha que informar o dia inicial e o dia final, pois não encontrei funções para que o Interbase descobrisse isso pra mim, então adicionei ao form dois Maskedit´s (EditDataInicial.text e EditDataFinal.text), que serviram para informar no caso a Segunda-Feira e Sexta-Feira respectivamente, isso se não tiver feriado é claro, a partir daí criei um select com aquela função SUM, que serve para somar valores direto na base de dados, não esquecendo também de criar duas variáveis do tipo Tdate para armazenar as datas no formato americano ( D_inicial, D_Final).


Var

D_Inicial, D_Final : Tdate;
begin
{Guardar as datas nas variáveis}
D_Inicial:= StrtoDate(EditDataInicial.text);
D_Final:= StrtoDate(EditDataFinal.text);
{formatar para o formato americano}
ShorDateFormat:= ‘mm/dd/aaaa’;
{jogar as datas de volta nos Maskedits já formatadas}
EditDataInicial.text:= DatetoStr(D_Inicial);
EditDataFinal.text:= DatetoStr(D_Final);

C:=('select Sum(Q_Aut) AS Tot_Aut from Diario where (data >= '#39+EditDataInicial.Text+#39') and (data <= '#39+EditDataFinal.Text+#39')');

IBQuery1.SQL.clear;
IBQuery1.sql.add(c);
IBQuery1.Open;
while IBQuery1.Eof = false do
begin
EditTotal.text:= IBQuery1.fieldbyname('Tot_Aut').AsString;
{retornar para o formato brasileiro}
ShorDateFormat:= ‘dd/mm/aaaa’;
{joga o valor das datas novamente nos edits só que no formato dd/mm/aaaa}
EditDataInicial.text:= DatetoStr(D_Inicial);
EditDataFinal.text:= DatetoStr(D_Final);
end;
end;

Assim descobri a quantidade total de autenticações da semana, para descobrir a soma dos valores é só mudar o campo “Q_Aut” por “Vl_Aut”, assim ele irá somar os valores e não as quantidades. Claro que tudo isso pode ser feito em apenas um Select com declarações compostas utilizando aquela opção de Select-dentro-de-Select (SubSelect), aí é só quebrar a cabeça e resolver. Existem outras formas de fazer isso tudo que eu fiz diminuindo consideravelmente à quantidade de linhas de comandos, mas expliquei desse jeito passo-a-passo para entendermos melhor como funciona o Interbase com relação a datas.


Explicando o código:


Primeiro eu declarei duas variáveis do tipo “Tdate” [D_Inicial, D_Final] para armazenar as datas informadas nos MaskEdits [EditDataInicial.text e EditDataFinal.text], o que acontece, quando digitamos 13/12/2004 e 17/12/2004 respectivamente, isso é de Segunda a Sexta, ele vai pegar e alterar 13/12/2004 e 17/12/2004 por 12/13/2004 e 12/17/2004 respectivamente e jogar de volta no Maskedit, ai ele faz a comparação na base de dados já no formato que o Interbase entende mm/dd/aaaa (Mês/Dia/Ano), após isso é feito o select somando a quantidade encontrada [SUM(Q_Aut)] verificando as datas e retornando somente os registros que forem maiores ou iguais que 12/13/2004 e menores ou igual que 12/17/2004 [where (Data >= '#39+EditDataInicial.text+#39') and (Data <= '#39+EditDataFinal.text+#39'], assim ele vai verificar todos e trazer para os edits indicados, após isso, mudei novamente o formato da data para o formato brasileiro [ShorDateFormat:= ‘dd/mm/aaaa’] e mandei jogar os valores das respectivas datas nos Maskedits de novo, aí ele desfaz 12/13/2004 e 12/17/2004 por 13/12/2004 e 17/12/2004 respectivamente, ou seja, assim o delphi faz todo o trabalho de conversão para você sem maiores preocupações com o formato que foi digitado Dia/Mês/Ano, ou seja, o cliente digita Dia/Mês/Ano, o programa muda para Mês/Dia/Ano, faz todo o trabalho de recuperação dos dados e depois muda de novo para Dia/Mês/Ano.

Alguns devem pensar, pô.....engraçado, o cara do artigo fala que o formato da data é alterada pelo Interbase mas quando eu abro o IBConsole e dou um select * from Nome_da_Tabela, a data [campo do tipo Tdate] vem no formato dd/mm/aaaa, e não como ele diz que é...... Simples, é que ao fazer esse select no IBConsole, o Interbase verifica as configurações regionais do Windows e já retorna no formato correto, só que se você colocar um dbgrid no seu aplicativo para testar e der o mesmo select, irá ver que a data virá invertida, da forma que eu estou dizendo.

sábado, 2 de abril de 2011

Destacando título da coluna ativa no DBGrid


Alterar as cores do título de um DBGrid em tempo execução dará mais vida ao seu programa e trará uma aparência mais profissional ao sistema. Para que última coluna clicada tenha o título com um estilo diferente, faça no evento onTitleClick do DBGrid:

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
  i: integer;
begin
  //para todas as colunas
  for i:=0 to DBGrid1.Columns.count-1 do
  begin
    DBGrid1.Columns[i].Title.Color := clBtnFace; //fundo padrão
    DBGrid1.Columns[i].Title.Font.Color := clBlack; //texto preto
    DBGrid1.Columns[i].Title.Font.Style := []; //sem efeito
  end;

  //para a coluna atual
  Column.Title.color := ClYellow; //fundo amarelo
  Column.Title.Font.Color := clRed; //texto vermelho
  Column.Title.Font.Style := [fsBold, fsItalic]; //negrito e itálico
end;

sexta-feira, 1 de abril de 2011

Formatando a visualização do tamanho de um arquivo

Fonte: www.activedelphi.com.br

Quando se trabalha com arquivos no Delphi pode ser necessário exibir o tamanho de um arquivo, como é feito no Explorer, onde o valor não é mostrado em bytes, mas sim de acordo com o seu tamanho atual. Para a maioria, "45.678.123 Bytes" é confuso, mas "43,56 MB" não!
A seguir, temos uma função chamada FormatByteSize, que converte um valor em bytes para uma String que representa o número expressado em Bytes, Kilobytes Megabytes ou Gigabytes, dependendo do seu tamanho:

//Formata o tamanho de um arquivo
function FormatByteSize(const bytes: Longint): string;
const
  B = 1; //byte
  KB = 1024 * B; //kilobyte
  MB = 1024 * KB; //megabyte
  GB = 1024 * MB; //gigabyte
begin
  if bytes > GB then
    result := FormatFloat('#.## GB', bytes / GB)
  else
    if bytes > MB then
      result := FormatFloat('#.## MB', bytes / MB)
    else
      if bytes > KB then
        result := FormatFloat('#.## KB', bytes / KB)
      else
        result := FormatFloat('#.## bytes', bytes) ;
end;
Para usá-la, basta fazer no evento onClick de um button, por exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  TamanhoEmBytes: Longint;
begin
  with TFileStream.Create(
    'C:\Windows\System32\calc.exe',
    fmOpenRead or fmShareExclusive)
  do try
    TamanhoEmBytes := Size;
  finally
    Free;
  end;

  ShowMessage( FormatByteSize(TamanhoEmBytes) );
end;

terça-feira, 29 de março de 2011

Ajustando a Data e a Hora do Computador

Fonte: www.activedelphi.com.br


Esta dica apresenta uma função simples, porém útil, para ajustar a data e a hora do sistema operacional. Ela foi postada pelo membro Rubem Rocha, na lista de discussão lista-delphi (link no final da dica). Fiz os testes e agora compartilho com vocês.
Segue o código da função:


function SetComputerDateTime(ADateTime: TDateTime): boolean;
const
  SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege';
var
  hToken: THandle;
  ReturnLength: DWORD;
  tkp, PrevTokenPriv: TTokenPrivileges;
  luid: TLargeInteger;
  dSysTime: TSystemTime;
begin
  Result := False;
  if Win32Platform = VER_PLATFORM_WIN32_NT then
    if OpenProcessToken(GetCurrentProcess,
      TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
    try
      if not LookupPrivilegeValue(nil, SE_SYSTEMTIME_NAME, luid) then
        Exit;

      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].luid := luid;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;

      if not AdjustTokenPrivileges(hToken, False, tkp,
        SizeOf(TTOKENPRIVILEGES), PrevTokenPriv, ReturnLength) then
        Exit;

      if GetLastError <> ERROR_SUCCESS then
      begin
        raise Exception.Create(SysErrorMessage(GetLastError));
        Exit;
      end;
    finally
      CloseHandle(hToken);
    end;

  DateTimeToSystemTime(ADateTime, dSysTime);
  Result := SetLocalTime(dSysTime);
  if Result then
    PostMessage(HWND_BROADCAST, WM_TIMECHANGE, 0, 0);
end;
Para testá-la, faça no onClick de um Button, por exemplo, o seguinte código:


procedure TForm1.Button1Click(Sender: TObject);
var
  Correta, Nova: TDateTime;
begin
  Correta := Now; //recupera a hora correta
  Nova := StrToDateTime('01/01/2011 12:34:56'); //gera uma nova data qualquer
  SetComputerDateTime(Nova); //altera a data
  ShowMessage('Clique em OK para voltar a data correta!'); //alerta o usuário
  SetComputerDateTime(Correta); //volta a data correta
end;

segunda-feira, 21 de março de 2011

De Enum para String e de String para Enum


Há algum tempo atrás precisei criar um enumerado e depois carregar este enumerado em um ComboBox. Toda vez que surgia essa necessidade eu criava o enum e criava um array de string com todas as opções do enum, aí com um loop no array eu populava o ComoboBox. Só que toda vez que precisava acrescentar um nova opção no enum eu tinha que atualizar o array.

Isso começou me incomodar! Foi aí que lembrei que quando desenvolvemos componentes e criamos uma property do tipo de um enum na seção published, o Delphi exibe esse enum no ObjectInspector com um ComboBox, e ele faz isso automaticamente! Aí pensei: “isso deve ser possível” já que o Delphi faz. Então entrei em contato com um amigo meu muito fera em Delphi, “Adriano Santos”, e ele conseguiu a solução que eu gostaria de publicar.

Vamos lá, vou dar o exemplo referente a minha necessidade na época que estava desenvolvendo uma comunicação com uma balança através da porta COM.

Criando o enum:

type
  TPorta = (COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9);

Criando a property do tipo do enum:

  private
    FPort: TPort;
  public
    property Port: TPort read FPort write FPort;
  end;

Criando um método que vai popular uma lista do Tipo TStrings, assim, com esse método posso popular objetos como: TComboBox, TMemo, TListBox ou até mesmo uma variável do Tipo TStrings. Primeiro deve ser declarado na seção uses a unit: TypInfo.

class procedure TSerialComunication.PopulateListPort(AList: TStrings);
var
  i: Integer;
Begin
  for i := Ord(Low(TPort)) to Ord(High(TPort)) do
    AList.Add(GetEnumName(TypeInfo(TPort), i));
end;

Agora basta chamar o método e popular o ComboBox:

procedure TfrmPrincipal.btnPopulatePortClick(Sender: TObject);
Begin
  TSerialComunication.PopulateListPort(cbbPort.Items);
end;

Essa foi a solução que meu amigão Adriano Santos meu passou, achei genial.

Agora imagina se precisar pegar um item do ComboBox que é uma string e passar pra uma variável do tipo do Enum? Antigamente eu usaria um case pra saber qual foi o item selecionado e passar a opção do enum correta, mas agora posso usar a mesma idéia e converter automaticamente enum para string ou vice-versa! Então criei dois overload de um método Convert:

class function TSerialComunication.Convert(const APort: string): TPort;
begin
  Result := TPort(GetEnumValue(TypeInfo(TPort), APort)) ;
end;

class function TSerialComunication.Convert(const APort: TPort): string;
begin
  Result := GetEnumName(TypeInfo(TPort), Integer(APort)) ;
end;

Agora ficou facil, basta chamar os métodos de conversão!

Convertendo o item do combobox para o enum:

procedure TfrmPrincipal.btnStringToEnumClick(Sender: TObject);
var
  vPort: TPort;
begin
  vPort := TSerialComunication.Convert(cbbPort.Text);
end;

Convertendo de Enum para uma string:

procedure TfrmPrincipal.btnEnumToStringClick(Sender: TObject);
var
  vPort: TPort;
begin
  vPort := COM1;
  ShowMessage(TSerialComunication.Convert(vPort));
end;

domingo, 20 de março de 2011

Justificação e Entre-linhas em RichEdit


A partir do RichEdit 3.0, é possível justificar parágrafo/texto em um RichEdit. Entretanto, no componente TRichEdit (ao menos até a versão 7), não há esta opção de alinhamento (existem apenas, taLeftJustify, taRightJustify e taCenter). Logo, temos que fazer uso de chamadas à API do Windows para que consigamos esta formatação.
Além do "Marcador de Texto", um outro recurso que pode ser aproveitado por quem utilizar TRichEdit em pequenos editores de texto é a variação do entre-linhas.

Abaixo, seguem duas funções para os recursos mencionados:

// AllText: True = todo o texto; False = parágrafo atual
procedure JustifyRichEdit(RichEdit :TRichEdit; AllText :Boolean);
const
  TO_ADVANCEDTYPOGRAPHY   = $1;
  EM_SETTYPOGRAPHYOPTIONS = (WM_USER + 202);
  EM_GETTYPOGRAPHYOPTIONS = (WM_USER + 203);
var
  ParaFormat :TParaFormat;
  SelStart,
  SelLength :Integer;
begin
  ParaFormat.cbSize := SizeOf(ParaFormat);
  if SendMessage(RichEdit.handle,
              EM_SETTYPOGRAPHYOPTIONS,
              TO_ADVANCEDTYPOGRAPHY,
              TO_ADVANCEDTYPOGRAPHY) = 1 then
  begin
    SelStart := RichEdit.SelStart;
    SelLength := RichEdit.SelLength;
    if AllText then
      RichEdit.SelectAll;
    ParaFormat.dwMask := PFM_ALIGNMENT;
    ParaFormat.wAlignment := PFA_JUSTIFY;
    SendMessage(RichEdit.handle, EM_SETPARAFORMAT, 0, LongInt(@ParaFormat));
    // Restaura seleção caso tenhamos mudado para All
    RichEdit.SelStart := SelStart;
    RichEdit.SelLength := SelLength;
  end;
end;


// Espaçamento: 0 = simples; 1 = 1,5; 2 = duplo
procedure LineSpaceRichEdit(RichEdit :TRichEdit; Espacamento :Integer; AllText :Boolean);
var
  ParaFormat :TParaFormat2;
begin
  if AllText then
    RichEdit.SelectAll;
  ParaFormat.cbSize := SizeOf(ParaFormat);
  ParaFormat.dwMask := PFM_LINESPACING or PFM_SPACEAFTER;
  ParaFormat.dyLineSpacing := Espacamento;
  ParaFormat.bLineSpacingRule := Espacamento;
  SendMessage(RichEdit.handle, EM_SETPARAFORMAT, 0, LongInt(@ParaFormat));
  // Restaura seleção caso tenhamos mudado para All
  RichEdit.SelStart := SelStart;
  RichEdit.SelLength := SelLength;
end;

Para usá-las, você possui 2 alternativas:

1) Todo o texto:

  JustifyRichEdit(RichEdit1, True); // justifica todo o texto
  LineSpaceRichEdit(RichEdit1, 2, True); // espaçamento duplo em todo o texto

2) Parâgrafo atual ou selecionado(s):

  JustifyRichEdit(RichEdit1, False); // justifica parágrafo(s)
  LineSpaceRichEdit(RichEdit1, 1, False); // espaçamento 1,5 no(s) paragrafo(s)

Obs: É necessário declarar a unit RichEdit na cláusula USES do seu form.

Criptografando Arquivos com Letras e Números


Esta dica vem para complementar a dica "Criptografia de Arquivos", onde o autor implementa uma camada a mais de criptografia utilizando o conceito de CRC (Cyclic Redundancy Check - Verificação Cíclica de Redundância).
Chega de se criptografar senhas com somente numeros! Tenho uma solução e é bem Simples!
Asseguir, criaremos um cálculo de CRC atravéz de String:

function StringCrc(const Data: string): longword;
const
  CRCtable: array[0..255] of DWORD = (
    $00000000, $77073096, $EE0E612C, $990951BA, $076DC419, $706AF48F, $E963A535,
    $9E6495A3, $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988, $09B64C2B, $7EB17CBD,
    $E7B82D07, $90BF1D91, $1DB71064, $6AB020F2, $F3B97148, $84BE41DE, $1ADAD47D,
    $6DDDE4EB, $F4D4B551, $83D385C7, $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC,
    $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5, $3B6E20C8, $4C69105E, $D56041E4,
    $A2677172, $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B, $35B5A8FA, $42B2986C,
    $DBBBC9D6, $ACBCF940, $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59, $26D930AC,
    $51DE003A, $C8D75180, $BFD06116, $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F,
    $2802B89E, $5F058808, $C60CD9B2, $B10BE924, $2F6F7C87, $58684C11, $C1611DAB,
    $B6662D3D, $76DC4190, $01DB7106, $98D220BC, $EFD5102A, $71B18589, $06B6B51F,
    $9FBFE4A5, $E8B8D433, $7807C9A2, $0F00F934, $9609A88E, $E10E9818, $7F6A0DBB,
    $086D3D2D, $91646C97, $E6635C01, $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
    $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457, $65B0D9C6, $12B7E950, $8BBEB8EA,
    $FCB9887C, $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65, $4DB26158, $3AB551CE,
    $A3BC0074, $D4BB30E2, $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB, $4369E96A,
    $346ED9FC, $AD678846, $DA60B8D0, $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9,
    $5005713C, $270241AA, $BE0B1010, $C90C2086, $5768B525, $206F85B3, $B966D409,
    $CE61E49F, $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, $59B33D17, $2EB40D81,
    $B7BD5C3B, $C0BA6CAD, $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A, $EAD54739,
    $9DD277AF, $04DB2615, $73DC1683, $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8,
    $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1, $F00F9344, $8708A3D2, $1E01F268,
    $6906C2FE, $F762575D, $806567CB, $196C3671, $6E6B06E7, $FED41B76, $89D32BE0,
    $10DA7A5A, $67DD4ACC, $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5, $D6D6A3E8,
    $A1D1937E, $38D8C2C4, $4FDFF252, $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
    $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60, $DF60EFC3, $A867DF55, $316E8EEF,
    $4669BE79, $CB61B38C, $BC66831A, $256FD2A0, $5268E236, $CC0C7795, $BB0B4703,
    $220216B9, $5505262F, $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04, $C2D7FFA7,
    $B5D0CF31, $2CD99E8B, $5BDEAE1D, $9B64C2B0, $EC63F226, $756AA39C, $026D930A,
    $9C0906A9, $EB0E363F, $72076785, $05005713, $95BF4A82, $E2B87A14, $7BB12BAE,
    $0CB61B38, $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21, $86D3D2D4, $F1D4E242,
    $68DDB3F8, $1FDA836E, $81BE16CD, $F6B9265B, $6FB077E1, $18B74777, $88085AE6,
    $FF0F6A70, $66063BCA, $11010B5C, $8F659EFF, $F862AE69, $616BFFD3, $166CCF45,
    $A00AE278, $D70DD2EE, $4E048354, $3903B3C2, $A7672661, $D06016F7, $4969474D,
    $3E6E77DB, $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0, $A9BCAE53, $DEBB9EC5,
    $47B2CF7F, $30B5FFE9, $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, $BAD03605,
    $CDD70693, $54DE5729, $23D967BF, $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
    $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);
var
  i: integer;
begin
  result := $FFFFFFFF;
  for i := 0 to length(Data) - 1 do
    result := (result shr 8) xor (CRCtable[byte(result) xor Ord(Data[i + 1])]);
  result := result xor $FFFFFFFF;
end;
Criaremos agora um codigo que criptografa textos atravéz de somente números:

function EnDecryptString(StrValue : String; Chave: Word) : String;
var
  I: Integer;
  OutValue : String;
begin
  OutValue := '';
  for I := 1 to Length(StrValue) do
    OutValue := OutValue + char(Not(ord(StrValue[I])-Chave));
  Result := OutValue;
end;
E finalmente, usaremos os dois:

procedure EndeCriptFile(FileName, Saida, Key: String);
var
  F: TFileStream;
  S: TStringStream;
  C: String;
begin
  F:=TFileStream.Create(FileName,FmOpenRead);
  S:=TStringStream.Create('');
  S.CopyFrom(F,F.Size);
  F.Free;
  C:=EnDecryptString(S.DataString, {*} StringCrc(Key) {*} ); //eis o X da questão
  S.free;
  S:=TStringStream.Create(C);
  F:=TFileStream.Create(Saida,FmCreate);
  F.CopyFrom(S,S.Size);
  S.Free;
  F.Free;
End;

Curso de Delphi: 7.Consultas SQL