Você está na página 1de 8

Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?

id=189

segunda-feira, 3 de maio de 2010 Busca

Artigo

Criando um DALHelper (Data Application Layer - Camada de Dados)


Por: Israel Ace
[Entre em contato com o autor ]
Especialista em tecnologias de desenvolvimento Microsoft, atua como desenvolvedor de aplicaes
para o mercado financeiro utilizando a plataforma .NET. Como instrutor Microsoft, leciona sobre o
desenvolvimento de aplicaes .NET. palestrante em diversos eventos Microsoft no Brasil e autor
de diversos artigos que podem ser lidos a partir de seu site http://www.israelaece.com/. Possui as
seguintes credenciais: MVP (Connected System Developer), MCP, MCAD, MCTS (Web, Windows,
Distributed, ASP.NET 3.5, ADO.NET 3.5, Windows Forms 3.5 e WCF), MCPD (Web, Windows,
Enterprise, ASP.NET 3.5 e Windows 3.5) e MCT.

Feed de artigos.

Feed de artigos deste autor.

Gere seu feed personalizado

Criando um DALHelper (Data Application Layer - Camada de Dados)


Publicado em: 29/12/2003

Como a maioria dos sistemas atuais necessitam de Base de Dados, sempre quando precisamos
acessar, inserir, alterar ou excluir um determinado registro, precisamos criar a conexo com a
Base de Dados, definir a query, os parmetros e escolher a opo para execut-la
(ExecuteNonQuery, ExecuteScalar ou ExecuteReader).

Para no ficarmos fazendo a todo momento todos esses passos, ou seja, criar conexo,
parmetros, etc., explicarei nesse artigo como criar um DALHelper. DALHelper quer dizer:
Data Application Layer (Camada de Dados) e Helper (Ajudante), que auxiliar no acesso aos
dados, reduzindo assim a quantidade de cdigo em nossa Aplicao.

Para isso criaremos uma Classe onde encapsularemos cdigo ADO.NET. S para recapitular,
Encapsulamento quando as funes internas de um determinado objeto no interessa ao
utilizador do mesmo, ou seja, temos a descrio das operaes que o objeto executa que
acessvel ao cliente, a implementao de tais operaes fica encapsulada e s visvel ao
prprio objeto.

Criaremos uma Windows Application chamada DALHelper e nela criaremos tambm um arquivo
chamado "DB.vb" onde ficar a nossa Classe chamada "DB" que ser responsvel pelo Acesso
aos Dados.

Devemos importar as seguintes Namespaces:

Imports System.Data
Imports System.Data.SqlClient

Cdigo 1 - Importando Namespaces necessrios.

Agora criaremos a nossa Classe "DB":

Imports System.Data
Imports System.Data.SqlClient

Public Class DB

End Class

Cdigo 2 - Criando a Classe que controlar o acesso Base de Dados.

Devemos declarar os seguintes membros:

Public Class DB

Protected m_connectionString As String


Private m_manterConexao As Boolean
Private conexao As SqlConnection

End Class

1 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Cdigo 3 - Declarando os membros da Classe.

A propriedade ConnectionString ser responsvel para receber a conexo com a Base de Dados
que dever ser informada pela Aplicao.

Public Property ConnectionString() As String


Get
Return Me.m_connectionString
End Get
Set(ByVal Value As String)
Me.m_connectionString = Value
End Set
End Property

Cdigo 4 - ConnectionString.

E a propriedade ManterConexo ser responsvel para sabermos se aps executarmos um


determinada ao na Base de Dados deixaremos ou no a conexo aberta.

Public Property ManterConexao() As Boolean


Get
Return Me.m_manterConexao
End Get
Set(ByVal Value As Boolean)
Me.m_manterConexao = Value
End Set
End Property

Cdigo 5 - Manter ou no a conexo aberta.

OBS.: Devemos tomar muito cuidado para no deixarmos a conexo aberta


desnecessariamente.

O prximo passo criarmos os construtores da Classe. Aqui chamo a ateno para um detalhe:
criaremos duas opes para os contrutores (Overload ou Sobrecarga), para que j possamos
preencher as propriedades ConnectionString e ManterConexao.

Public Sub New(ByVal connectionString As String)


Me.m_connectionString = connectionString
End Sub

Public Sub New(ByVal connectionString As String, ByVal manterConexao As Boolean)


Me.m_connectionString = connectionString
Me.m_manterConexao = manterConexao
End Sub

Cdigo 6 - Construtores Sobrecarregados.

Podemos reparar que no primeiro construtor, onde h apenas um nico parmetro, que nesse
caso a String de conexo com a Base de Dados. J no segundo construtor passada a String
de conexo e um valor Booelano que indicar se a conexo com a Base de Dados permanecer
aberta aps a execuo do comando.

Vamos criar uma Sub-Rotina para podermos fechar a conexo com a Base de Dados. Mas antes
de chamarmos o mtodo Close() da SqlConnection, devemos verificar se a varivel "conexao"
ainda encontra-se ativa.

Public Sub Fechar()


If Not (conexao Is Nothing) Then
conexao.Close()
End If
End Sub

Cdigo 7 - Sub-Rotina para fechar o acesso Base de Dados.

Vamos iniciar pelo ExecuteNonQuery. O ExecuteNonQuery retorna o nmero de registros


afetados pela instruo SQL.

Criaremos para o ExecuteNonQuery, ExecuteReader e ExecuteScalar dois mtodos


sobrecarregados (Overloads). Um deles receber como parmetro: o tipo do comando
(CommandType, (Text ou Stored Procedure)) e o nome da Stored Procedure ou a Query SQL. E
o outro alm desses parmetros, receber um terceiro parmetro ParamArray do tipo
SqlParameter que conter um Array com os parmetros que sero passados para a Stored
Procedure ou Query.

Nesse primeiro mtodo do ExecuteNonQuery ser apenas passado o comando (CommandText) e


seu tipo (CommandType), j a Query ou Stored Procedure no necessitam parmetros.

Public Overloads Function ExecuteNonQuery(ByVal cmdText As String, ByVal cmdType As CommandType) As


Integer
Return ExecuteNonQuery(cmdText, cmdType, Nothing)
End Function

Cdigo 8 - Executa o ExecuteNonQuery e retorna o quantidade de registros afetados.

Agora, veremos o mesmo mtodo (sobrecarregado) com mais um parmetro, que como
explicado acima, ser um Array contendo os parmetros que sero utilizados na Query ou

2 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Stored Procedure:

Public Overloads Function ExecuteNonQuery(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal
ParamArray parameters() As SqlParameter) As Integer
Dim cmd As SqlCommand = CriarCommando(cmdText, cmdType, parameters)
Dim retVal As Integer
Try
If ManterConexao = False Then
retVal = cmd.ExecuteNonQuery()
Me.Fechar()
Else
retVal = cmd.ExecuteNonQuery()
End If
Return retVal
Catch e As Exception
Me.Fechar()
Throw e
End Try
End Function

Cdigo 9 - Criamos um objeto do tipo SqlCommand que ser responsvel pela execuo da Query ou Stored
Procedure e atribuimos a ele o retorno da Funo CriarCommando(), qual veremos mais adiante a sua utilidade e
funcionamento. Atente-se tambm condicional que feita para verificar se devemos ou no mantermos a
conexo com a Base de Dados aberta. E retornamos um inteiro que o nmero de registros afetados pela
instruo SQL.

OBS.: Mas o utilize somente quando a instruo SQL necessite de parmetros.

Devemos fazer o mesmo para os que restaram: ExecuteScalar e ExecuteReader, mas temos que
prestar ateno no valor retorno dos mesmos. Vamos ento ver como funciona o ExecuteScalar:

Public Overloads Function ExecuteScalar(ByVal cmdText As String, ByVal cmdType As CommandType) As Object
Return ExecuteScalar(cmdText, cmdType, Nothing)
End Function

Cdigo 10 - Executa o ExecuteScalar e seu retorno do tipo Object.

E a da mesma forma que fizemos com o ExecuteNonQuery quando ele necessita passar
parmetros para a Query ou Stored Procedure ser feito para o ExecuteScalar:

Public Overloads Function ExecuteScalar(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal
ParamArray parameters() As SqlParameter) As Object
Dim cmd As SqlCommand = CriarCommando(cmdText, cmdType, parameters)
Dim retVal As Object
Try
If ManterConexao = False Then
retVal = cmd.ExecuteScalar()
Me.Fechar()
Else
retVal = cmd.ExecuteScalar()
End If
Return retVal
Catch e As Exception
Me.Fechar()
Throw e
End Try
End Function

Cdigo 11 - A nica diferena alm do mtodo ser executado, o retorno do mesmo. Nesse quase ser
retornado um Object.

Agora com o ExecuteReader dos dois metdos sobrecarregados (Overloads), precisaremos de


um mtodo adicional, qual chamaremos de GetDataReader que receber como parmetro o
SqlCommand e passar pela mesma condicional para verificar se deve ou no manter a conexo
com a Base de Dados.

Public Function GetDataReader(ByVal cmd As SqlCommand) As SqlDataReader


Try
If ManterConexao = False Then
Return cmd.ExecuteReader(CommandBehavior.CloseConnection)
Else
Return cmd.ExecuteReader()
End If
Return retVal
Catch e As Exception
Me.Fechar()
Throw e
End Try
End Function

Cdigo 12 - Executa o mtodo ExecuteReader.

Public Overloads Function ExecuteReader(ByVal cmdText As String, ByVal cmdType As CommandType) As


SqlDataReader
Dim cmd As SqlCommand = CriarComando(cmdText, cmdType, Nothing)
Return GetDataReader(cmd)
End Function

Public Overloads Function ExecuteReader(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal
ParamArray parameters() As SqlParameter) As SqlDataReader
Dim cmd As SqlCommand = CriarComando(cmdText, cmdType, parameters)
Return GetDataReader(cmd)
End Function

Cdigo 13 - A diferena entre esses dois mtodos so os parmetros que podem ou no serem necessrios para
a Query ou Stored Procedure. Reparem que feito da mesma forma que nos mtodos anteriores, ou seja,

3 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

criado um SqlCommand e chamamos a funo CriarComando. No retorno de ambas as funes, ele chama o
mtodo GetDataReader, passando o Command como parmetro.

Depois de todos esses passos devemos construir o mtodo CriarComando, que como o prprio
nome diz, cria e configura um SqlCommand informando o tipo (CommandType), a Query
(CommandText) e os parmetros (SqlParameter) quando necessrio.

Public Function CriarComando(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal ParamArray
parameters() As SqlParameter) As SqlCommand
Dim cmd As New SqlCommand(cmdText)
cmd.CommandType = cmdType
If Not (parameters Is Nothing) Then
Dim param As SqlParameter
For Each param In parameters
cmd.Parameters.Add(param)
Next param
End If
VerificarConexao(cmd)
Return cmd
End Function

Cdigo 14 - Atravs deste mtodo, definimos o Comando que ser executado (CommandText), o Tipo de
Comando (CommandType) e em seguida verificamos se h algum parmetro necessrio. Caso exista um ou mais
parmetros, realizado um lao For..Each atribuindo cada um coleo de parmetros do SqlCommand.

Podemos ver que ainda existe uma ltima Sub Rotina (VerificarConexao) para fecharmos essa
primeira parte, que tem por finalidade verificar e/ou criar a conexo com a Base de Dados.

Public Sub VerificarConexao(ByRef cmd As SqlCommand)


If conexao Is Nothing Then
conexao = New SqlConnection(Me.ConnectionString)
conexao.Open()
Else
If conexao.State <> ConnectionState.Open Then
conexao.Open()
End If
End If
cmd.Connection = conexao
Return
End Sub

Cdigo 15 - Aqui apenas fazemos a verificao com relao ao estado da conexo com a Base de Dados. Depois
apenas adicionamos propriedade Connection do objeto SqlCommand que vem como parmetro (ByRef).

Bem, depois de tudo isso, parece ser algo completamente complicado. Mas tentarei mostrar o
processo atravs de imagens.

1. Caso: Abrir a conexo, executar apenas UM determinado mtodo e fech-la logo em


seguida:

Figura 1 - Mantendo a conexo aberta durante a execuo de apenas um mtodo.

2. Caso: Abrir a conexo, executar MAIS DE UM mtodo e fech-la logo em seguida:

4 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Figura 2 - Neste caso, podemos ver que a conexo se mantm durante a execuo de vrias mtodos.

Ainda faltam trs funes que sero acessadas fora da Classe: CriarParametro, GetString e
GetInt32.

A funo CriarParametro servir para que possamos criar os parmetros que sero passados
para os mtodos que vimos anteriormente (ExecuteNonQuery, ExecuteScalar ou
ExecuteReader). Lembrando que os parmetros so passados como ParamArray.

Public Function CriarParametro(ByVal name As String, ByVal type As SqlDbType, ByVal value As Object) As
SqlParameter
Dim param As New SqlParameter()
param.ParameterName = name
param.SqlDbType = type
If value Is Nothing Then
param.Value = DBNull.Value
Else
If type = SqlDbType.VarChar And value.ToString().Length = 0 Then
param.Value = DBNull.Value
Else
param.Value = value
End If
End If
Return param
End Function

Cdigo 16 - A funo recebe o nome, tipo e valor do parmetro. Trata esses dados para que eles possam ser
adicionados coleo de parmetros do comando (SqlCommand).

Para finalizar temos apenas mais dois mtodos: GetString e GetInt32. Funes quais retornaro
valores em Strings e Inteiros, respectivamente do SqlDataReader. Ambas funes recebem
como parmetro o SqlDataReader e um nmero inteiro que representar o campo que ser
resgatado desse mesmo SqlDataReader:

Public Shared Function GetString(ByRef dr As SqlDataReader, ByVal ordinal As Integer) As String


If Not dr.IsDBNull(ordinal) Then
Return dr.GetString(ordinal)
Else
Return Nothing
End If
End Function

Public Shared Function GetInt32(ByRef dr As SqlDataReader, ByVal ordinal As Integer) As Integer


If Not dr.IsDBNull(ordinal) Then
Return dr.GetInt32(ordinal)
Else
Return Nothing
End If
End Function

Cdigo 17 - Tanto para o mtodo GetString quanto para o mtodo GetInt32 verificado se o campo solicitado
ou no nulo. Se no for, seu valor retornado, caso contrrio, no ser retornado nada.

OBS.: Podemos tambm criarmos os mtodos GetBoolean, GetDateTime, etc., mas nesse artigo
apenas usaremos os dois mtodos citados acima.

Enfim, nosso DALHelper pronto para ser colocado em ao. Criaremos ento duas Tabelas na
Base de Dados para test-lo. Abaixo a estrutura das Tabelas:

5 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Figura 3 - Estrutura das Tabelas de Exemplo.

Temos tambm que criarmos um Formulrio para que possamos interagir com o Usurio. Abaixo
o formulrio que usaremos como exemplo:

Figura 4 - Usando 2 TextBox, 1 Button e 1 ListBox.

Abaixo as Stored Procedures que utilizaremos no decorrer do nosso exemplo. Em um dos casos
utilizarei o cdigo SQL diretamente.

CREATE PROCEDURE BuscarClientes

AS

SELECT
ClienteID,
Nome + ' - ' + Email AS DadosCliente
FROM
Clientes
ORDER BY
ClienteID ASC

GO

CREATE PROCEDURE AdicionarCliente

@Nome AS Varchar(50),
@Email AS Varchar(50)

AS

INSERT INTO Clientes (Nome, Email)


VALUES (@Nome, @Email)

GO

Cdigo 18 - A primeira Stored Procedure retorna todos os Clientes. J a segunda ser utilizada para adicionarmos
um novo cliente.

Depois de nosso DALHelper pronto, as Tabelas da Base de Dados e das Stored Procedures
vamos comear a codificar o Front-End. Primeiramente incluirei mais dois WinForm ao Projeto
para que possamos entender os dois casos como vimos acima.

6 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Figura 5 - Temos dois WinForms para entendermos os dois casos.

1. Caso - Fechar a Conexo logo aps executar um determinado Comando.

Vamos analisar a Sub-Rotina CarregaListBox que ser responsvel por carregar os dados da
Base de Dados (Tabela Clientes) no ListBox:

Private Sub CarregaListBox()


Me.lstClientes.Items.Clear()
Dim dalHelper As New DalHelper.DB(strConexao, False)
Dim dr As SqlDataReader
Try
dr = dalHelper.ExecuteReader("BuscarClientes", CommandType.StoredProcedure)
While dr.Read()
Me.lstClientes.Items.Add(dalHelper.GetInt32(dr, 0) & " - " & dalHelper.GetString(dr, 1))
End While
Catch ex As Exception
MessageBox.Show("Ocorreu um erro ao tentar acessar a Base de Dados", "Base de Dados",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub

Cdigo 19 - No construtor da Classe DB passamos como parmetro a ConnectionString que est armazenada em
uma constante declarada no topo do WinForm e o segundo parmetro diz que aps efetuar o comando deve ser
fechada a conexo com a Base de Dados.

Podemos ver que aps instanciarmos a Classe DB, podemos utilizar seus mtodos e
propriedades. No cdigo acima, criamos um SqlDataReader e atribumos ele o retorno da
funo ExecuteReader que recebe como parmetro o Nome do Stored Procedure ou Query e o
CommandType, que por sua vez tambm retorna um SqlDataReader. Atravs de um lao While
percorremos o SqlDataReader e adicionamos cada registro ao ListBox. Utilizamos o GetInt32
quando o campo ser resgatado do SqlDataReader do tipo Inteiro, j o GetString o utilizamos
quando o campo do tipo Texto.

No evento Click do boto Adicionar devemos incluir um novo registro no Base de Dados e logo
aps fecharmos a conexo com a mesma. Veja o cdigo:

Private Sub btnCadastrar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles


btnCadastrar.Click
Dim dalHelper As New DalHelper.DB(strConexao, False)
Dim iRegistrosAfetados As Integer = 0
Try
Dim param() As SqlParameter = { _
dalHelper.CriarParametro("@Nome", SqlDbType.VarChar, Me.txtNome.Text.Trim), _
dalHelper.CriarParametro("@Email", SqlDbType.VarChar, Me.txtEmail.Text.Trim)}

iRegistrosAfetados = dalHelper.ExecuteNonQuery("AdicionarCliente", CommandType.StoredProcedure,


param)
Catch ex As Exception
MessageBox.Show("Ocorreu um erro ao tentar acessar a Base de Dados", "Base de Dados",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
If iRegistrosAfetados = 1 Then
Call Me.CarregaListBox()
MessageBox.Show("Registro includo com sucesso.") Else
MessageBox.Show("Ocorreu um erro ao tentar incluir o registro.")
End If
End Try
End Sub

Cdigo 20 - Ao clicarmos no boto para adicionarmos um novo registro na Base de Dados, instanciamos a Classe
DB e novamente informamos ela a ConnectionString e dizemos atravs do segundo parmetro que aps a
execuo, deve ser fechada a conexo com a Base de Dados, criamos uma varivel chamada param() que ser
um Array de SqlParameter e utilizamos o mtodo ExecuteNonQuery.

Com o Array podemos incluir quantos parmetros forem necessrios. Basta utilizar o mtodo
CriarParametro e informar o Nome, o Tipo de Dados e o Valor, separando cada um por uma
vrgula ( , ). No caso desse exemplo, os dois parmetros so do Tipo Varchar e recebem os
TextBox que esto no WinForm.

O mtodo ExecuteNonQuery retornar o nmero de registros afetados pela instruo SQL. No


bloco Finally verificamos se a varivel iRegistrosAfetados for igual a 1 porque o registro foi
includo com sucesso, caso contrrio houve uma falha.

2. Caso - Manter a Conexo Aberta durante a execuo de vrios Comandos.

Agora iremos alterar a rotina que adiciona um novo registro. Vamos manter a conexo aberta
durante a executao de duas instrues SQL. Para isso, aps a execuo da Stored Procedure
AdicionarCliente, vamos adicionar Tabela Logs um novo registro e para isso utilizaremos a
mesma conexo, apenas mudando o CommandType:

Private Sub btnCadastrar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles


btnCadastrar.Click
Dim dalHelper As New DalHelper.DB(strConexao, True)

7 de 8 03/05/2010 15:12
Linha de Cdigo - Criando um DALHelper (Data Application Layer - ... http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=189

Dim iRegistrosAfetados As Integer = 0


Try
Dim param() As SqlParameter = { _
dalHelper.CriarParametro("@Nome", SqlDbType.VarChar, Me.txtNome.Text.Trim), _
dalHelper.CriarParametro("@Email", SqlDbType.VarChar, Me.txtEmail.Text.Trim)}

iRegistrosAfetados = dalHelper.ExecuteNonQuery("AdicionarCliente", CommandType.StoredProcedure,


param)
dalHelper.ExecuteNonQuery("INSERT INTO Logs (Data) VALUES (GetDate())", CommandType.Text)
Catch ex As Exception
MessageBox.Show("Ocorreu um erro ao tentar acessar a Base de Dados", "Base de Dados",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
dalHelper.Fechar()
If iRegistrosAfetados = 1 Then
MessageBox.Show("Registro includo com sucesso.") Call Me.CarregaListBox()
Else
MessageBox.Show("Ocorreu um erro ao tentar incluir o registro.")
End If
End Try
End Sub

Cdigo 21 - A diferena aqui se encontra no segundo parmetro que informado ao construtor da Classe DB, que
nesse caso True, que diz que depois de executar o comando, a conexo deve permanecer aberta.

Chamo a ateno para a linha onde temos:

dalHelper.ExecuteNonQuery("INSERT INTO Logs (Data) VALUES (GetDate())", CommandType.Text)

Cdigo 22 - Utilizando instrues SQL diretamente.

Neste caso informamos a Query diretamente, ou seja, sem Stored Procedures. O procedimento
o mesmo, apenas temos que mudar o CommandType para CommandType.Text. A criao de
parmetros continua sendo da mesma forma das Stored Procedures, ou seja, utilizando o
mtodo CriarParametro.

Um dos principais cuidados que devemos ter quando mantermos a conexo aberta, que aps
finalizarmos todo o processo, devemos fechar a conexo com a Base de Dados explicitamente
atravs do mtodo Fechar().

OBS.: Procure no deixar a String de Conexo com a Base de Dados em Hard-Code, ou seja,
deix-la juntamente com o cdigo, pois isso implicaria em cada vez que mudar a Base de
Dados/String de Conexo, recompilar a aplicao.

Concluso: Utilizando o DALHelper escrevemos muito menos cdigo do que quando utilizamos
as declaraes de SqlCommand, SqlParameter, SqlCommand, etc. normalmente, pois todos
esses cdigos ADO.NET j esto encapsulados dentro do DALHelper. Podemos tambm definir o
Tipo de Comando (CommandType), manter a conexo aberta ou no aps a execuo de um
comando, entre outras funcionalidades/facilidades.

Artigo desenvolvido utilizando:

* Visual Studuo .NET 2002


* .NET Framework 1.0
* SQL Server 2000
* Windows XP Professional

Clique aqui para fazer Download do Cdigo.

Copyright 2001-2010 Codeline Editora, Comrcio e Tecnologia Ltda. | Poltica de privacidade e de uso | Anuncie | Fale conosco

Site hospedado na Porta 80 Web Hosting

8 de 8 03/05/2010 15:12

Você também pode gostar