Por Ken Getz
Agosto de 2005
Resumo: Ken Getz mostra como migrar seu aplicativo orientado a dados do Visual Basic 6.0 para o Visual Basic 2005. (22 páginas impressas)
Nesta página
Introdução
Converter ou reescrever?
Ferramentas de conversão
Iniciando
Examinando a solução existente
Preparando para converter o aplicativo
Examinando os problemas
Convertendo o aplicativo
Conclusão
Introdução
(OBSERVAÇÃO: este artigo foi escrito usando o Visual Studio 2005 Beta 2. As imagens e os recursos do produto podem ser alterados ao longo do tempo.)
De uma forma ou de outra, a maioria dos aplicativos em Visual Basic 6 envolve dados, e a maioria dos desenvolvedores de Visual Basic 6 sente-se confortável usando o ADO para solucionar suas tarefas de manuseio de dados. É provável que, sendo um desenvolvedor experiente em Visual Basic 6, você tenha interesse em migrar suas habilidades para o mundo do .NET, usando o Visual Basic 2005 como linguagem de desenvolvimento. A transferência de habilidades não é, absolutamente, tão simples quanto se poderia desejar e, sinceramente, você tem muito trabalho a fazer.
Precisa migrar para o .NET? O objetivo desta série de três artigos é tornar essa transição um pouco menos estressante. Ao ser orientado quanto à conversão e às modificações envolvidas na migração de um aplicativo simples orientado a dados do Visual Basic 6 para o Visual Basic 2005, você conhecerá as tarefas de movimentação de seus aplicativos, e de suas habilidades, para o Visual Studio 2005 e o Visual Basic 2005.
Qual é o público-alvo desta série de artigos? Se você é um desenvolvedor de Visual Basic 6 de nível intermediário a experiente e está interessado em mudar para o .NET, mas ainda não usou muito o Visual Studio 2003 ou o Visual Studio 2005, pode se beneficiar muito ao seguir as etapas destes artigos. Se você é um desenvolvedor de .NET experiente, é provável que haja outros recursos mais úteis para você. Por outro lado, se você é novo no Visual Basic .NET, no ADO.NET e no .NET em geral, provavelmente encontrará aqui uma série de técnicas úteis.
Esta série de artigos o orientará na conversão de um aplicativo Visual Basic 6 existente, escrito originalmente como parte de um curso de Visual Basic 6 para a AppDev. Esse aplicativo será utilizado com o consentimento explícito da AppDev. Neste primeiro artigo, você examinará o aplicativo, verá como ele funciona e percorrerá as etapas da conversão do aplicativo para que ele seja executado no Visual Studio 2005. No segundo artigo, você converterá o aplicativo para que ele use o ADO.NET, o mecanismo preferencial de acesso a dados no ambiente .NET. Por fim, no terceiro artigo, você recriará o aplicativo usando os recursos de ligação de dados do Visual Studio 2005, escrevendo o mínimo possível de código. Ou seja, você simulará as etapas que atravessaria se estivesse escrevendo, a partir do zero, um aplicativo semelhante usando o Visual Studio 2005.
Se você acompanhar integralmente os três artigos, estará apto a iniciar a conversão de seus aplicativos existentes do Visual Basic 6 para o Visual Basic 2005. Você entenderá os fundamentos do ADO.NET e terá interagido com os novos cenários de ligação de dados para os quais há suporte na última versão do Visual Studio. O objetivo destes artigos é que você possa trabalhar com independência, ou seja, você começará com o aplicativo em Visual Basic 6 preparado e percorrerá as etapas da conversão, ou da criação do novo aplicativo, de modo independente.
Naturalmente, é importante mencionar que o aplicativo de exemplo mostrado aqui é incrivelmente simples. Ele usa muitos recursos do ADO e exibe muitas etapas úteis no processo de conversão e reescrita, mas qualquer projeto real em Visual Basic 6/ADO será necessariamente muito mais complexo. Além disso, para manter o aplicativo simples e compreensível, ele talvez inclua alguns recursos e estilos de desenvolvimento que não são aceitos como práticas recomendadas, o que não reflete o nosso objetivo aqui. Embora o aplicativo tente usar as melhores práticas estilísticas possíveis, o objetivo principal ao escrever este aplicativo foi manter a simplicidade.
Converter ou reescrever?
Se você pesquisar na Internet, encontrará muitos artigos, entradas de blog e conversas em grupos de discussão sobre a conveniência de converter para o .NET aplicativos criados no Visual Basic 6. Este artigo não pode nem mesmo sugerir a resposta correta à questão sobre converter ou reescrever, mas, em geral, a conversão do Visual Basic 6 para o .NET funciona em alguns casos e não funciona em outros. Não há uma solução simples nem uma resposta correta. O MSDN contém vários artigos que exaltam os benefícios da conversão do Visual Basic 6 para o Visual Basic .NET, por exemplo, mas você não encontrará facilmente um documento que informe, em termos simples, quando se deve atualizar e quando se deve reescrever aplicativos existentes. Este artigo o orienta no processo de conversão de um aplicativo de três camadas e, com pequenas modificações, o aplicativo funciona perfeitamente bem no Visual Studio 2005. Outros aplicativos não se comportarão tão bem. Uma alternativa popular é migrar partes do aplicativo e usar a interoperabilidade COM para criar a comunicação entre as partes do aplicativo em Visual Basic 6 e em .NET. De qualquer forma, este artigo não tomará partido nessa questão. Ele apenas converterá um aplicativo existente e, depois, demonstrará como reescrevê-lo. Para obter informações sobre a migração de habilidades existentes e de aplicativos do Visual Basic 6, visite Visual Basic Developer Center ou VBRun: The Visual Basic 6.0 Resource Center (ambos em inglês).
Ferramentas de conversão
Para tornar o processo de conversão o mais simples possível, a Microsoft oferece duas ferramentas que serão utilizadas ao longo das etapas deste artigo. A primeira ferramenta, o Visual Basic 6.0 Code Advisor, exige que você baixe um suplemento do Visual Basic 6. Essa ferramenta, embora escrita para o Visual Basic 2003, funciona bem com o Visual Basic 2005. Ela examina o aplicativo existente, escrito em Visual Basic 6, e oferece sugestões que podem ajudar a tornar o processo de migração mais suave. Você usará essa ferramenta antes de atualizar o aplicativo de exemplo. Além disso, o Visual Studio 2005 contém um assistente que tenta converter para o Visual Basic 2005 aplicativos criados no Visual Basic 6. Você executará esse assistente ao carregar o projeto no Visual Studio 2005.
Iniciando
Antes de começar o processo de percorrer as etapas deste artigo, baixe o Visual Basic 6.0 Code Advisor e instale-o em sua máquina de teste. Além disso, você precisará obter e instalar a versão Beta 2 ou posterior do Visual Studio 2005. Naturalmente, você também precisará ter uma cópia do Visual Basic 6 com SP6 instalada em seu computador de teste. Os dados de exemplo provêm de um arquivo .MDB do Access, embora nada no aplicativo de exemplo ou no processo de sua conversão seja afetado se os dados tiverem sido armazenados no SQL Server, exceto pela alteração necessária na seqüência de caracteres de conexão. Por fim, baixe e instale o exemplo de Visual Basic 6 contido neste artigo usando o link fornecido.
Examinando a solução existente
O exemplo no qual você vai trabalhar como parte da demonstração do processo de conversão controla informações simples sobre clientes com nomes comuns, conforme mostrado na Figura 1. O aplicativo usa arquitetura simples de três camadas, embora todas as camadas existam no mesmo projeto para simplificar. A Figura 2 mostra o formulário de exemplo único, juntamente com a janela Project, do projeto de demonstração.
Figura 1. O aplicativo de exemplo controla as informações de contato desses clientes.
Figura 2. O formulário de exemplo e a janela Project do projeto de exemplo mostram as partes importantes do projeto.
A execução do aplicativo de exemplo exibe o formulário único, permitindo que você execute operações padrão de banco de dados nos dados de exemplo (inserir, atualizar, excluir e selecionar linhas) usando a classe DataLayer da camada intermediária para fornecer acesso aos dados e a classe CustomerHandler para manipular os clientes. A Figura 3 mostra o formulário de exemplo em ação. (Observe que a seqüência de caracteres de conexão existente espera encontrar o banco de dados VB6Demo.mdb na mesma pasta do programa executável.)
Figura 3. Use o formulário de exemplo para navegar, inserir novas linhas e excluir ou modificar linhas existentes.
O projeto de exemplo inclui a classe DataLayer, que age como uma camada de dados genérica — essa classe contém o código necessário para abrir as conexões e fornecer as instâncias de RecordSet do ADO. A camada comercial do aplicativo pode chamar o método GetRecordset para recuperar um objeto Recordset do ADO e o método CloseRecordser para liberar o Recordset e sua conexão. A classe contém o seguinte código (assim como em todos os exemplos de código mostrados aqui, a menos que o código de manipulação de erros seja pertinente à discussão, ele foi removido do artigo para simplificar o máximo possível):
' From DataLayer.vb
Private Function OpenConnection( _
ConnectionString As String) As ADODB.Connection
' Open the connection.
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.ConnectionString = ConnectionString
cnn.Open
Set OpenConnection = cnn
End Function
Public Function GetRecordset( _
ConnectionString As String, SQL As String) As ADODB.Recordset
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Set cnn = OpenConnection(ConnectionString)
If Not cnn Is Nothing Then
If cnn.State = adStateOpen Then
' Build updateable keyset.
Set rst = New ADODB.Recordset
rst.CursorType = adOpenKeyset
rst.LockType = adLockOptimistic
rst.Source = SQL
Set rst.ActiveConnection = cnn
rst.Open Options:=adCmdText
End If
End If
Set GetRecordset = rst
End Function
Public Sub CloseRecordset(rst As ADODB.Recordset)
Dim cnn As ADODB.Connection
If Not rst Is Nothing Then
Set cnn = rst.ActiveConnection
If Not cnn Is Nothing Then
If cnn.State = adStateOpen Then
cnn.Close
End If
End If
If rst.State = adStateOpen Then
rst.Close
End If
End If
Set rst = Nothing
End Sub
Um dos objetivos de um aplicativo de três camadas é construir a interface do usuário de forma que ela não precise se comunicar diretamente com a camada de dados, e este aplicativo tenta simular esse comportamento. Nesse caso, a camada intermediária (CustomerHandler.vb) contém todo o código chamado pela interface do usuário. No exemplo, a classe da camada intermediária contém o seguinte código:
' From CustomerHandler.vb
Private Function GetConnectionString() As String
GetConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & App.Path & "\VB6Demo.MDB"
End Function
Public Function GetCustomers() As ADODB.Recordset
Dim dl As DataLayer
Set dl = New DataLayer
Set GetCustomers = dl.GetRecordset( _
GetConnectionString(), _
"SELECT * FROM tblCustomer ORDER BY LastName")
Set dl = Nothing
End Function
Public Function GetStates() As ADODB.Recordset
Dim dl As DataLayer
Set dl = New DataLayer
Set GetStates = dl.GetRecordset( _
GetConnectionString(), _
"SELECT State FROM tblStates")
Set dl = Nothing
End Function
Public Function CloseRecordset(rst As ADODB.Recordset)
Dim dl As DataLayer
Set dl = New DataLayer
dl.CloseRecordset rst
End Function
A classe CustomerHandler contém os procedimentos que retornam os conjuntos de registros que contêm as informações de clientes ou de estado, juntamente com um método para fechar um conjunto de registros. É discutível se o procedimento que recupera a seqüência de caracteres de conexão deve estar nesta classe ou na camada de dados, mas essa é uma decisão que você mesmo pode tomar sem que esta demonstração do processo de atualização seja afetada.
O módulo denominado basUtility oferece alguns procedimentos utilitários simples:
-
HandleUnexpectedError exibe um alerta com uma mensagem e um número de erro:
Public Sub HandleUnexpectedError( _
lngError As Long, strDescription As String)
MsgBox "Error: " & strDescription & _
" (" & lngError & ")"
End Sub
-
AddQuotes delimita com apóstrofos uma seqüência de caracteres e duplica todos os apóstrofos dentro da seqüência de caracteres, tornando possível executar uma pesquisa em qualquer seqüência de caracteres delimitada:
Public Function AddQuotes(strValue As String) As String
' If a string to be quoted contains
' an apostrophe, then simply replace
' it with two. VBA will see the two
' apostrophes as a single apostrophe,
' and all will be well.
AddQuotes = _
"'" & Replace(strValue, "'", "''") & "'"
End Function
-
FindString tenta localizar uma seqüência de caracteres em um controle ComboBox ou ListBox:
Public Sub FindString( _
ctl As Control, strFind As String)
' Find strFind in ctl, which must be either
' a list box or a combo box.
On Error Resume Next
' Attempt to set the value of the control
' to be the specified text.
ctl.Text = strFind
If Err.Number <> 0 Then
ctl.ListIndex = -1
End If
End Sub
-
FixBoolean converte um valor booleano de um Recordset do ADO para que ele seja exibido em um controle CheckBox:
Public Function FixBoolean(fld As ADODB.Field) _
As CheckBoxConstants
' Convert a Yes/No/Null field value
' into a checkbox value.
If CBool(fld.Value) Then
FixBoolean = vbChecked
Else
FixBoolean = vbUnchecked
End If
End Function
-
As funções NullToText e TextToNull convertem seqüências vazias de e em valores nulos. Os controles do Visual Basic 6 não têm como indicar um valor nulo, ainda que, em um banco de dados, uma seqüência de caracteres vazia seja diferente de um valor nulo. Estes procedimentos manipulam a conversão:
Public Function NullToText(fld As ADODB.Field) _
As String
' Append an empty string, forcing a conversion
' of a Null value to a string, leaving normal
' strings as is.
NullToText = fld.Value & ""
'
' Or, you can use:
' If IsNull(fld.Value) Then
' NullToText = ""
' Else
' NullToText = fld.Value
' End If
End Function
Public Function TextToNull(strValue As String) As Variant
' Convert a text string to Null, if
' the string has no characters. ADO appears
' to require this, at least with the Jet
' provider.
If Len(strValue) = 0 Then
TextToNull = Null
Else
TextToNull = strValue
End If
End Function
Por fim, o formulário de demonstração, frmADO, contém o código que manipula a interface do usuário. O formulário contém essas declarações, que incluem variáveis no nível de classe para controlar a instância CustomerHandler que gerencia os dados, e outras para se referir ao Recordset que contém os dados de clientes:
' Keep track of the customer handler, and
' the customer recordset:
Private customer As CustomerHandler
Private customerRecordset As ADODB.Recordset
' The name of the field to use for searching.
Private Const conFindField = "LastName"
' Constants indicating the current data state.
Private Enum DataState
Loading = 0
Adding = 1
Editing = 2
NoRows = 3
Normal = 4
End Enum
Private currentDataState As DataState
O manipulador de eventos Load do formulário recupera as informações de clientes, inicializa o formulário e exibe os dados:
Private Sub Form_Load()
Set customer = New CustomerHandler
' Open the connection and the
' recordset, and then initialize
' the form.
Set customerRecordset = customer.GetCustomers
If Not customerRecordset Is Nothing Then
Call InitForm
' Display the form.
Call ShowData
Else
MsgBox "Unable to load the requested data."
Unload Me
End If
End Sub
O procedimento InitForm simplesmente carrega a lista de estados:
Private Sub InitForm()
' Put any code here that you want
' to run once for your form.
' Load the combo box with state values.
Call LoadStates
End Sub
Private Sub LoadStates()
' Load cboStates from tblStates.
Dim states As ADODB.Recordset
Set states = customer.GetStates()
Do Until states.EOF
cboState.AddItem states("State")
states.MoveNext
Loop
End Sub
O procedimento ShowData move para o formulário dados do Recordset subjacente, mantendo o controle da linha atual. Observe que esse exemplo usa uma matriz de controle (txtArray) para exibir todos os dados de texto do Recordset. As matrizes de controle não têm suporte direto no .NET, portanto, essa é uma área que você deve investigar. Os procedimentos HandleButtonState e GotoFirstControl simplesmente manipulam o gerenciamento da interface do usuário. Você pode examiná-los diretamente no código-fonte:
Private Sub ShowData()
' Set this flag so event procedures
' don't do anything during this
' process.
currentDataState = DataState.Loading
If customerRecordset.RecordCount = 0 Then
Call AddNewRow
Else
txtData(0).Text = NullToText(customerRecordset("CustomerID"))
txtData(1).Text = NullToText(customerRecordset("FirstName"))
txtData(2).Text = NullToText(customerRecordset("LastName"))
txtData(3).Text = NullToText(customerRecordset("Address"))
txtData(4).Text = NullToText(customerRecordset("City"))
txtData(5).Text = NullToText(customerRecordset("ZipCode"))
Call FindString(cboState, _
NullToText(customerRecordset("State")))
chkActive.Value = FixBoolean(customerRecordset("Active"))
Call HandleButtonState
currentDataState = DataState.Normal
End If
Call GotoFirstControl
End Sub
Os botões de navegação do formulário alteram a linha atual no Recordset subjacente do formulário. Por exemplo, um clique no botão que move a linha atual para a primeira linha do Recordset executa este código:
Private Sub cmdFirst_Click()
customerRecordset.MoveFirst
Call ShowData
End Sub
Um clique no botão que adiciona uma nova linha chama o procedimento AddNewRow, que simplesmente limpa o formulário e configura adequadamente o estado do botão:
Private Sub AddNewRow()
' Add a new row.
' Clear the form, and manage the navigation
' buttons. Set the focus to the
' correct text box.
Call ClearForm
Call HandleButtonState
Call GotoFirstControl
End Sub
O formulário trata quase da mesma forma a adição e a edição. Em ambos os casos, os botões alteram seu estado habilitado. Para executar a ação solicitada, durante o modo de edição ou adição, você pode clicar em Save (Salvar) ou Cancel (Cancelar). Se você tiver adicionado uma nova linha ou modificado uma linha existente, um clique no botão Save chama o procedimento SaveData, que manipula as adições e modificações, usando a variável de nível de classe currentDataState (que é mantida atualizada por todos os manipuladores de eventos) para determinar a ação a ser executada. Observe que esse código se beneficia do fato de que um Variant não inicializado contém o valor especial Empty. O Visual Basic 2005 não tem suporte a valores Variant e, por isso, esse mecanismo precisará ser alterado na conversão.
Private Function SaveData() As Boolean
Dim currentBookmark As Variant
Dim isOK As Boolean
isOK = True
' Retrieving a bookmark would trigger an
' error if there are no rows, so just
' disregard the error. If there are no rows,
' currentBookmark will just contain Empty.
On Error Resume Next
currentBookmark = customerRecordset.Bookmark
On Error GoTo ErrorHandler
If currentDataState = DataState.Adding Then
customerRecordset.AddNew
End If
' Whether adding or editing,
' you need to save fields and update
' the recordset.
Call SaveFields
customerRecordset.Update
If currentDataState = DataState.Adding Then
' Display the newly added key.
Call GetID
End If
' Reset buttons.
currentDataState = DataState.Normal
Call HandleButtonState
ExitHere:
If Not isOK Then
' If something went wrong, then go back
' to the original row.
If Not IsEmpty(currentBookmark) Then
customerRecordset.Bookmark = currentBookmark
End If
End If
SaveData = isOK
Exit Function
ErrorHandler:
isOK = False
Select Case Err.Number
Case Else
Call HandleUnexpectedError(Err.Number, Err.Description)
End Select
Call GotoFirstControl
Resume ExitHere
End Function
O procedimento GetID simplesmente encapsula a ação de recuperar o novo valor de CustomerID:
Private Sub GetID()
' Get the newly added customer ID.
txtData(0).Text = customerRecordset("CustomerID")
End Sub
O procedimento SaveFields executa a tarefa de salvar cada valor individual, colocando-o de volta no campo adequado do banco de dados:
Private Sub SaveFields()
' The ADO/Jet provider will not allow
' empty strings in fields that don't
' explicitly allow empty strings (as
' opposed to Nulls). Convert empty
' text boxes back to Null, for storage
' in the table.
customerRecordset("FirstName") = TextToNull(txtData(1).Text)
customerRecordset("LastName") = TextToNull(txtData(2).Text)
customerRecordset("Address") = TextToNull(txtData(3).Text)
customerRecordset("City") = TextToNull(txtData(4).Text)
customerRecordset("ZipCode") = TextToNull(txtData(5).Text)
customerRecordset("State") = TextToNull(cboState.Text)
customerRecordset("Active") = CBool(chkActive.Value)
End Sub
Um clique em Cancel no meio de uma edição ou adição simplesmente coloca os dados originais de volta no formulário:
Private Sub cmdCancel_Click()
Call ShowData
End Sub
O formulário de exemplo contém outros procedimentos, mas a maior parte deles lida apenas com a interface do usuário. Sinta-se à vontade para examinar o exemplo e percorrer todos os recursos da interface do usuário. Neste ponto, reserve alguns momentos para experimentar o aplicativo de exemplo em Visual Basic 6 e se familiarizar com sua operação e seu comportamento.
Preparando para converter o aplicativo
Quando se converte um aplicativo, é necessário levar em conta não só as alterações de linguagem (se você é novo no Visual Basic .NET, deve iniciar aqui para começar a examinar as diferenças entre as linguagens), mas também as alterações ocorridas nos controles e em outros recursos de ambiente. Para facilitar o gerenciamento da transição, você pode usar o Visual Basic 6.0 Code Advisor para procurar no aplicativo locais em que provavelmente haverá falha na conversão.
Seu primeiro objetivo, depois de examinar o aplicativo de exemplo, é determinar que problemas haverá na conversão e corrigir o máximo possível dentro do Visual Basic 6.0. Essa é a finalidade do Visual Basic 6.0 Code Advisor. Se você ainda não instalou a ferramenta, faça isso agora. Quando tiver instalado, siga estas etapas para executar o exame do projeto de exemplo:
-
Com o projeto de exemplo carregado no Visual Basic 6.0, selecione Add-Ins | Code Advisor e assegure-se de que o escopo da pesquisa seja o Projeto Ativo, como mostrado na Figura 4.
Figura 4. Assegure-se de ter escolhido examinar todo o projeto.
-
No mesmo menu, selecione Add FixIts para iniciar o processo de exame.
-
Quando o processo de exame estiver concluído, você poderá exibir os resultados: selecione Add-Ins | Code Advisor | View FixIt Report para ver o relatório mostrado na Figura 5. Esse relatório contém uma lista de todos os problemas encontrados durante o exame e inclui também uma lista de todas as regras que o Code Advisor usou no exame.
Figura 5. O relatório FixIt mostra todos os problemas com os quais você terá de lidar antes de tentar a conversão para o Visual Basic 2005.
Este é o momento de examinar em detalhes cada um desses problemas. Um aplicativo diferente teria, é claro, um conjunto diferente de problemas e, na verdade, este aplicativo foi escrito originalmente de forma simples. Como um exemplo para um curso de treinamento, ele não tinha muitas "trivialidades". É muito provável que a execução do Code Advisor em seu próprio aplicativo resulte em uma lista de problemas muito maior.
Examinando os problemas
Antes de tentar carregar o aplicativo no Visual Studio 2005, será necessário interromper e examinar cada um dos problemas listados no relatório Issues. Como você verá, vários dos problemas listados no relatório, pelo menos neste aplicativo específico, são residuais e não exigem ação de sua parte. Os parágrafos a seguir descrevem soluções para cada problema apontado no relatório.
O primeiro problema, "txtData.LinkTimeout has no Visual Basic .NET equivalent and will not be upgraded", na verdade não se aplica a este aplicativo. Você pode ignorar esse problema sem nenhum dano. No entanto, se quiser gerar um relatório sem problemas, você precisará definir a propriedade LinkTimeOut da caixa de texto Street (txtData(3)) como 50 (em vez de seu valor atual, 35). Não está claro como esse valor foi definido como não-padrão, mas, independentemente de você corrigi-lo ou não, essa alteração não afetará a conversão.
Para corrigir os quatro problemas, "cmdXXX.UseMaskColor has no Visual Basic .NET equivalent and will not be upgraded", você pode definir o UseMaskColor dos quatro botões (cmdFirst, cmdPrevious, cmdNext, cmdLast) como False. Infelizmente, essa alteração afeta a aparência dos bitmaps nos botões. Você precisará resolver esse comportamento assim que executar a conversão.
Para resolver os dois problemas seguintes, "'Value' is not a property of the generic 'Control' object in Visual Basic .NET. To access 'Value' declare 'ctl' using its actual type instead of 'Control'" (e o mesmo problema, exceto pelo uso da propriedade ListIndex), é de fato necessário algum cuidado. O procedimento ClearForm contém um código que usa uma variável genérica do tipo Control para executar um loop em todos os controles do formulário. Nos controles TextBox, CheckBox e ComboBox, o código executa etapas especiais:
Dim ctl As Control
For Each ctl In Me.Controls
If TypeOf ctl Is TextBox Then
ctl.Text = ""
ElseIf TypeOf ctl Is CheckBox Then
ctl.Value = vbChecked
ElseIf TypeOf ctl Is ComboBox Then
ctl.ListIndex = -1
' TODO:
' Add more control types, if necessary.
End If
Next ctl
O problema aqui é que, embora o Visual Basic 6.0 permita a ligação tardia, o Visual Basic 2005 não permite. Isto é, embora o tipo Control forneça uma propriedade Text, as classes específicas que são herdeiras de Control (ListBox, TextBox e assim por diante) fornecem várias outras propriedades, como Value e ListIndex. O Visual Basic 6.0 permite escrever código que faça referência à propriedade de uma classe usando um tipo genérico, mas isso é mais difícil de fazer (e não é o comportamento padrão) no Visual Basic 2005. Para solucionar o problema, modifique o bloco For Each de forma que ele se pareça com este:
For Each ctl In Me.Controls
If TypeOf ctl Is TextBox Then
ctl.Text = ""
ElseIf TypeOf ctl Is CheckBox Then
Dim chk As CheckBox
Set chk = ctl
chk.Value = vbChecked
ElseIf TypeOf ctl Is ComboBox Then
Dim cbo As ComboBox
Set cbo = ctl
cbo.ListIndex = -1
' TODO:
' Add more control types, if necessary.
End If
Next ctl
Embora isso seja mais trabalhoso, o código não usa mais a ligação tardia, e a conversão para o Visual Basic 2005 transcorrerá mais suavemente.
Solucionar os dois problemas seguintes ("Declare 'currentBookmark' with an early-bound data type") é fácil. Neste ponto, o código utiliza o que já foi uma prática comum: o uso de um Variant para conter o valor de indicador do ADO. Essa prática já pode ter sido deturpada, e o raciocínio certamente foi esquecido (ao menos por este autor). De qualquer maneira, o armazenamento correto de um indicador é em um valor Double e, por isso, a solução é simples: substitua ambas as declarações da variável currentBookmark:
' In frmADO.SaveData, replace this:
Dim currentBookmark As Variant
'with this:
Dim currentBookmark As Double
' In frmADO.FindRow, replace this:
Dim currentBookmark As Variant
'with this:
Dim currentBookmark As Double
O problema seguinte, "'ListIndex' is not a property of the generic 'Control' object in Visual Basic .NET. To access 'ListIndex', declare 'ctl' using its actual type instead of 'Control'", é o mesmo que você já viu anteriormente. Desta vez, o procedimento basUtility.FindString usa um tipo Control genérico porque a intenção é que ele funcione tanto com um controle ListBox quanto com um controle ComboBox. Fornecer o tipo correto de controle depende do chamador, e a ligação tardia do Visual Basic 6.0 cuida dos detalhes:
Public Sub FindString( _
ctl As Control, strFind As String)
' Find strFind in ctl, which must be either
' a list box or a combo box.
On Error Resume Next
' Attempt to set the value of the control
' to be the specified text.
ctl.Text = strFind
If Err.Number <> 0 Then
ctl.ListIndex = -1
End If
End Sub
Para corrigir o problema, modifique o procedimento de forma que ele seja semelhante ao seguinte, usando controles de tipo seguro, em vez de controles genéricos:
Public Sub FindString( _
ctl As Control, strFind As String)
' Find strFind in ctl, which must be either
' a list box or a combo box.
On Error Resume Next
' Attempt to set the value of the control
' to be the specified text.
ctl.Text = strFind
If Err.Number <> 0 Then
If TypeOf ctl Is ListBox Then
Dim lst As ListBox
Set lst = ctl
lst.ListIndex = -1
ElseIf TypeOf ctl Is ComboBox Then
Dim cbo As ComboBox
Set cbo = ctl
cbo.ListIndex = -1
End If
End If
End Sub
O próximo erro, "Declare 'TextToNull' with an early-bound data type", não pode ser corrigido. Se você examinar o procedimento basUtility.TextToNull, verá que o código precisa retornar um valor nulo ou uma seqüência de caracteres. No Visual Basic 6.0, a única forma de fazer isso é retornar um valor Variant. Assim, neste ponto, sua única opção é desconsiderar o aviso e deixar o código como está:
Public Function TextToNull(strValue As String) As Variant
' Convert a text string to Null, if
' the string has no characters. ADO appears
' to require this, at least with the Jet
' provider.
If Len(strValue) = 0 Then
TextToNull = Null
Else
TextToNull = strValue
End If
End Function
O problema final, "Declare 'CloseRecordset' with an early-bound data type", é fácil de corrigir, pois é simplesmente uma falha do código original. O método CustomerHandler.CloseRecordset não retorna um tipo específico (o que significa que ele está retornando um Variant). Mas, na verdade, o procedimento não está retornando valor algum, portanto, pode ser convertido em um Sub. Para corrigir esse problema, modifique o procedimento CustomerHandler.CloseRecordset para que ele seja semelhante ao seguinte:
Public Sub CloseRecordset(rst As ADODB.Recordset) As
Dim dl As DataLayer
Set dl = New DataLayer
dl.CloseRecordset rst
End Sub
Quando tiver feito todas as alterações, selecione novamente Add-Ins | Code Advisor | Add FixIts e, desta vez, o relatório deve mostrar apenas o único item não alterado. (Antes de sair do relatório do Advisor, dedique uns momentos para examinar as regras listadas na parte inferior do relatório. Isso dará a você uma idéia do tipo de problemas que poderá enfrentar ao converter outros aplicativos.)
Por fim, execute o aplicativo pela última vez e verifique se a única alteração de comportamento é que os botões de navegação não parecem tão bonitos quanto eram quando o Visual Basic 6.0 ocultava as cores do plano de fundo. Afora isso, o aplicativo continua a funcionar exatamente como funcionava e está pronto para ser convertido.
Convertendo o aplicativo
Chegou a hora: você fez a preparação, e o aplicativo de exemplo está pronto para ser convertido para o Visual Basic 2005. Siga estas etapas para executar a conversão:
-
No menu Iniciar do Windows, abra o Visual Studio 2005.
-
No Visual Studio 2005, selecione File | Open | Project/Solution e navegue até o local em que você armazenou seu projeto criado no Visual Basic 6.0. Selecione ADOForm.vbp e clique em Open.
-
Na página Welcome to the Visual Basic Upgrade Wizard, clique em OK para continuar.
-
Na página Choose a Project Type, apenas o tipo de projeto EXE estará disponível, portanto, clique em Next para continuar.
-
Na página Specify a Location for Your New Project, insira o caminho para o local em que você gostaria de colocar o novo projeto ou aceite o padrão. De qualquer forma, seu projeto original não é alterado. Clique em Next para continuar.
-
Na página Ready to Upgrade, clique em Next, permitindo que o assistente de atualização execute sua função. Tome um cafezinho enquanto ele trabalha (isso significa que você não deve esperar uma conversão imediata).
-
Quando o Visual Studio conclui a conversão, ele carrega o projeto recém-convertido. Coragem: pressione F5 para executar o projeto e descobrirá que ele falha. Ele não falha por causa de um problema de conversão, mas porque o código espera encontrar o banco de dados, VB6Demo.mdb, na mesma pasta do executável. Para solucionar esse problema, copie o mesmo banco de dados para a pasta bin, sob a pasta de projeto que você acabou de criar. Tente executar o aplicativo novamente e verá que ele funciona, exatamente como no Visual Basic 6.0.
Se você examinar o relatório de atualização (na janela Solution Explorer, clique duas vezes em _UpgradeReport.htm), descobrirá que a maioria dos módulos foi atualizada sem erros e sem avisos. O formulário da interface do usuário, ADO.vb, contém uma série de erros, a maioria ligada a problemas de layout e de propriedade. O problema que mais aparece, entretanto, está rotulado como "Couldn't resolve default property of object TextToNull()". Se você examinar o código, descobrirá que essa função, que costumava retornar um Variant, agora retorna um tipo Object. O Visual Basic 2005 não consegue determinar qual propriedade do Object retornado você pretende usar ao chamar TextToNull; por isso, o compilador emite esse aviso. Neste ponto, no entanto, o código parece funcionar — você atingiu o objetivo original deste artigo. (Para fins de aprendizado, você deve examinar o código convertido para ver o que o Visual Studio 2005 fez ao carregar seu projeto existente. Algumas alterações são óbvias, como converter Variant em tipos Object, mas outras usam engenhosamente o Visual Basic 2005 para simular o comportamento do Visual Basic 6 no ambiente .NET.)
A pergunta mais importante é: "Como o novo aplicativo se comunica com o banco de dados existente sem reescrever nenhum código ADO?". A resposta é simples: a interoperabilidade COM permite que o aplicativo .NET continue a usar a infra-estrutura COM existente à medida que você converte seus aplicativos. Originalmente, você estava usando a interoperabilidade COM entre o Visual Basic 6 e o ADO, e seu aplicativo ainda funciona da mesma forma. Para confirmar a referência ao COM, na janela Solution Explorer, clique com o botão direito do mouse no projeto ADOForm (não no nó superior, a solução ADOForm). No menu de contexto, selecione Properties e, na página Properties, selecione a guia References. Lá você encontrará a referência Microsoft ActiveX Data Objects, e o código usa essa referência para dar suporte ao ADO.
Embora você possa conseguir que um aplicativo Visual Basic 6 convertido funcione no Visual Studio 2005, como fez aqui, você deve considerar a hipótese de fazer alterações futuras, além de adições aos aplicativos, usando os objetos recém-criados e o código criado especificamente no e para o Visual Studio 2005. Isto é, é preferível isolar o código e os formulários atualizados e, com o tempo, substituí-los pelos objetos recém-criados. Na segunda parte desta série, recriaremos o formulário de exemplo, dessa vez com ferramentas e controles do Windows Forms e usando o ADO.NET para a comunicação com a fonte de dados. Na terceira parte, você revisitará o novo formulário, dessa vez usando as ferramentas incorporadas de ligação de dados fornecidas pelo Visual Studio 2005.
Conclusão
Este aplicativo simples ilustra apenas alguns dos problemas envolvidos na atualização, e este artigo aborda somente alguns tópicos específicos da atualização. Convém examinar cada comentário na fonte convertida, procurando por UPGRADE_WARNING no texto do comentário. Você pode concentrar seus estudos em alguns problemas específicos, incluindo:
-
O que acontece aos objetos quando você os define como 'Nothing'? O Visual Basic .NET não lida com isso da mesma forma que o Visual Basic 6. Observe este aviso de atualização: "Object <xx> may not be destroyed until it is garbage collected".
-
TypeOf tem um comportamento um pouco diferente no Visual Basic 2005. Siga o link do aviso de atualização para ler sobre essa alteração, mas ela não afeta este aplicativo específico.
-
O significado do valor Null foi alterado. Observe o aviso "Use of Null/IsNull() detected" e siga o link do aviso para aprender mais sobre esse problema.
A próxima parte desta série de artigos demonstrará como criar o mesmo aplicativo de exemplo usando diretamente os recursos do ADO.NET e do Windows Forms.
Sobre o autor
Ken Getz é consultor sênior da MCW Technologies. Ele é co-autor de ASP .NET Developers Jumpstart (Addison-Wesley, 2002), Access Developer's Handbook (Sybex, 2001) e VBA Developer's Handbook, 2nd Edition (Sybex, 2001).
© 2005 Microsoft Corporation. Todos os direitos reservados. Termos de uso.