Archive for the 'VBA' Category
Esta foi uma pergunta feita num fórum e como é uma informação interessante, resolvi postar aqui.
Muita gente, aliás, todo mundo que trabalha com planilhas no dia a dia costuma proteger os arquivos mais crÃticos com senha de abertura do arquivo.
Até aà a coisa é simples meso para usuários básicos. Mas quando se quer automatizar este tipo de arquivo com VBA, por exemplo, abrindo-o através de outro arquivo, fica ou pouco complicado. Mas nem tanto.
Se reparar bem, ao ativar no próprio VBA o método Open da coleção Workbooks, será possÃvel ver que um dos parâmetros da função é a senha de abertura do arquivo. O exemplo abaixo abre um arquivo de Excel via VBA:
Sub AbreArquivo()
Call Workbooks.Open(FileName:="C:\arquivo.xls")
End Sub
Porém, caso o arquivo contenha senha de abertura, bastaria adicionar o seguinte argumento:
Sub AbreArquivoComSenha()
Call Workbooks.Open(FileName:="C:\arquivo.xls", Password:="1234")
End Sub
Para informação, o método devolve um objeto do tipo Workbook que pode ser manipulado depois de aberto.
Isso resolve o problema. Claro, é preciso tomar os devidos cuidados para proteger o projeto VBA e não expor indevidamente a senha para o usuário. Recomenda-se também adicionar um tratamento de erros para inibir ainda mais as mensagens.
Em tempo, a mesma informação é válida para o Word/VBA, porém a coleção utilizada é a Documents e o nome do parâmetro é PasswordDocument. O código abaixo mostra um exemplo da aplicação.
Sub AbreDocumentoComSenha()
Call Documents.Open(FileName:="C:\Documento.doc", _
PasswordDocument:="1234")
End Sub
Abraços
Tomás
O que é?
A função MsgBox exibe uma caixa de mensagem ao usuário e aguarda com que o
usuário clique em um de seus botões para que esta seja fechada.
A estrutura de chamada à função MsgBox se faz da seguinte forma:
MsgBox([prompt][, buttons] [, title] [, helpfile, context]) As VbMsgBoxResult
Prompt
Obrigatória. Expressão de seqüência de
caracteres exibida como mensagem na caixa de
diálogo. O comprimento máximo de prompt é de aproximadamente 1.024
caracteres, dependendo da largura dos caracteres utilizados. Se prompt consistir em mais de uma linha, você poderá separar as linhas utilizando um
caractere de retorno de carro (Chr(13)), um caractere de
alimentação de linha (Chr(10)) ou uma combinação de caracteres
de retorno de carro e alimentação de linha (Chr(13) & Chr(10)) entre cada linha.
Buttons
Opcional. Expressão
numérica que é a soma de valores que especifica o
número e o tipo de botões a exibir, o estilo de Ãcone a utilizar, a identidade
do botão padrão e a modalidade da caixa de mensagem. Se omitido, o valor
padrão para buttons é 0.
Title
Opcional. Expressão de seqüência de caracteres exibida
na barra de tÃtulo da caixa de diálogo. Se você omitir title, o nome do
aplicativo será inserido na barra de tÃtulo.
Helpfile
Opcional. Expressão de seqüência de caracteres que
identifica o arquivo de Ajuda a ser utilizado para fornecer ajuda
sensÃvel ao contexto relativa à caixa de diálogo. Se helpfile for
fornecido, context também deverá ser fornecido.
Context
Opcional. Expressão numérica que é o número de
contexto da Ajuda atribuÃdo ao tópico da Ajuda apropriado por
seu autor. Se context for fornecido, helpfile também deverá ser
fornecido.
Definições
As definições do argumento buttons são as seguintes:
| Constante |
Valor |
Descrição |
| VbOKOnly |
0 |
Exibe somente o botão OK. |
| VbOKCancel |
1 |
Exibe os botões OK e Cancelar. |
| VbAbortRetryIgnore |
2 |
Exibe os botões Abortar, Repetir e Ignorar. |
| VbYesNoCancel |
3 |
Exibe os botões Sim, Não e Cancelar. |
| VbYesNo |
4 |
Exibe os botões Sim e Não. |
| VbRetryCancel |
5 |
Exibe os botões Repetir e Cancelar. |
| vbCritical |
16 |
Exibe o Ãcone Mensagem crÃtica. |
| vbQuestion |
32 |
Exibe o Ãcone Consulta de aviso. |
| vbExclamation |
48 |
Exibe o Ãcone Mensagem de aviso. |
| vbInformation |
64 |
Exibe o Ãcone Mensagem de informação. |
| vbDefaultButton1 |
0 |
O primeiro botão é o padrão. |
| vbDefaultButton2 |
256 |
O segundo botão é o padrão. |
| vbDefaultButton3 |
512 |
O terceiro botão é o padrão. |
| vbDefaultButton4 |
768 |
O quarto botão é o padrão. |
| vbApplicationModal |
0 |
Janela restrita do aplicativo; o usuário deve responder à caixa de
mensagem antes de continuar o trabalho no aplicativo atual. |
| vbSystemModal |
4096 |
Janela restrita de sistema; todos os aplicativos são suspensos até que o
usuário responda à caixa de mensagem. |
| vbMsgBoxHelpButton |
16384 |
Adiciona o botão ‘Ajuda’ à caixa de mensagens |
| VbMsgBoxSetForeground |
65536 |
Especifica a janela da caixa de mensagens como a janela de primeiro
plano |
| vbMsgBoxRight |
524288 |
O texto é alinhado à direita |
| vbMsgBoxRtlReading |
1048576 |
Especifica que o texto deve aparecer como leitura da direita para a
esquerda em sistemas hebraico e árabe |
O primeiro grupo de valores (0 a 5) descreve o número e o tipo de botões
exibidos na caixa de diálogo; o segundo grupo (16, 32, 48, 64) descreve o
estilo de Ãcone; o terceiro grupo (0, 256, 512) determina qual botão é o
padrão e o quarto grupo (0, 4.096) determina a modalidade da caixa de
mensagem. Quando estiver somando números para criar um valor final para o
argumento buttons, utilize somente um número de cada grupo.
Observação Essas constantes são especificadas pelo
Visual Basic for Applications. Como resultado, os nomes podem ser utilizados
em qualquer lugar do seu código em vez dos valores reais.
Como o MsgBox é uma Função (Function), é possÃvel capturar o
valor retornado conforme a ação do usuário.
Valores retornados
| Constante |
Valor |
Descrição |
| vbOK |
1 |
OK |
| vbCancel |
2 |
Cancelar |
| vbAbort |
3 |
Abortar |
| vbRetry |
4 |
Repetir |
| vbIgnore |
5 |
Ignorar |
| vbYes |
6 |
Sim |
| vbNo |
7 |
Não |
Exemplo
Apesar do grande número de opções e parâmetro oferecidos pelo MsgBox,
vamos nos concentrar em sua funcionalidade mais simples neste momento, que é
emitir mensagens ao usuários. Veja este exemplo de código abaixo:
|
1
2
3
|
Public Sub TesteMsgBox()
MsgBox “Seja bem vindo ao
Microsoft Excel!”
End Sub
|
Execute a função e terá o seguinte resultado:
Na código de exemplo, apenas o primeiro parâmetro é informado, o suficiente
para fazer uso de mensagens simples. Porém é possÃvel personalizar ainda mais
a caixa de mensagem conforme mostra o próximo código de exemplo:
|
1
2
3
|
Public Sub TesteMsgBox()
MsgBox “Seja bem vindo ao
Microsoft Excel!”, vbInformation, “Testando o MsgBox”
End Sub
|
Note que mais dois parâmetros foram informados, o parâmetro Button e Title. Execute a função e terá o seguinte resultado:
O parâmetro Title permitiu alterar o tÃtulo da MsgBox, enquanto
o parâmetro Button alterou o contexto da informação. Como foi informado
que o botão a ser mostrado seria do tipo vbInformation, um Ãcone de
informação foi adicionado ao caixa e mensagem. Outro tipos de Buttons podem
ser utilizadas, que geraram diferentes Ãcones, conjunto de botões, alterando
inclusive o som que é executado ao mostrar a caixa. Claro que o ideal é sempre
colocar uma mensagem que esteja de acordo com o contexto. Veja a diferença da
aparência se mudar o parâmetro para o seguinte:
|
1
2
3
|
Public Sub TesteMsgBox()
MsgBox “Ocorreu algum
erro!”, vbCritical, “Testando o MsgBox”
End Sub
|
O resultado da execução do código será a seguinte:
Note a mudança do Ãcone e do som emitido pelo aplicativo. A mensagem também
foi alterada para refletir a contexto do Ãcone utilizado.
Comentários
Como o MsgBox é uma função (Function), sua execução retorna um
valor que é do tipo VbMsgBoxResult. Quando se utiliza alguns tipos
especiais de parâmetros Button, este retorna nos dá uma alternativa de
analisar a decisão do usuário com base no retorno do MsgBox.
Quando helpfile e context são fornecidos, o
usuário pode pressionar F1 (Windows) ou AJUDA (Macintosh) para visualizar o
tópico de Ajuda que corresponde ao context. Alguns
aplicativos host, por exemplo, o Microsoft Excel, também adicionam
automaticamente um botão Ajuda à caixa de diálogo. Se o usuário clicar
em OK ou pressionar , a função InputBox retornará o que estiver
na caixa de texto. Se o usuário clicar em Cancelar, a função retornará
uma seqüência de caracteres de comprimento zero (”").
Observação Para especificar mais que o primeiro
argumento nomeado, você deve utilizar InputBox em uma expressão. Para
omitir alguns argumentos posicionais, você deve incluir o delimitador de
vÃrgula correspondente.
Pratique!
Caso não consiga abrir os arquivos, clique nos links com o botão direito do
mouse e escolha “salvar como”.
Baixe a planilha para praticar.
É uma necessidade básica para quem está começando a programar em VBA.
Depois da criação das primeiras macros e formulários, é preciso alguma forma de executá-los sem precisar ir direto ao VBA ou simplesmente acionando o menu de macros.
Os caminhos mais tradicionais são:
- Associar a execução de uma macro a um botão de comando ou outro componente qualquer
- Colocar a execução de determinada macro na abertura do arquivo
Vamos tratar aqui da segundo item.
Usando o Auto_Open
Existe uma forma geral de executar esta tarefa no VBA, idenpendente de qual seja o aplicativo hospedeiro. Basta dar ao nome da macro, ou seja, o cabeçalho da função como Auto_Open.
Suponha a macro abaixo:
Public Sub MostraMensagem()
MsgBox "Seja bem vindo"
End Sub
Clicar em F5 para testar o código. O resultado deve ser uma caixa de mensagem com a mensagem “Seja bem vindo”. Para mostrar esta macro na abrir um arquivo, bastaria que esta fosse renomeada para Auto_Open ao invés do nome original. Para não estragar o código, poderÃamos criar uma macro de nome Auto_Open que chama a nossa macro, por exemplo:
Public Sub Auto_Open()
Call MostraMensagem
End Sub
O único requisito para o funcionamento desta macro é que ela não tenha parâmetros, podendo ser um Function ou Sub e ser chamada após esta execução.
Mapeando o evento de abertura do arquivo
Este é outro método também largamente utilizado. Praticamente todos os aplicativos dotados do VBA possuem um evento que representa a abertura de um arquivo. Abaixo segue alguns exemplos do Microsoft Office:
| Aplicativo |
Evento |
| Excel |
Workbook_Open |
| Word |
Document_Open |
Alguns aplicativos são excessão, como o PowerPoint que suporta somente eventos em nÃvel de Aplicativo, assunto não abordado aqui.
Como exemplo, usarei o Excel para mapear o evento Workbook_Open.
- Abra o Excel
- Acione o VBA em Ferramentas->Macro->VBA ou simplesmente Alt+F11
- Na janela de projeto, procure o item EstaPasta_de_trabalho
- Clique duas vezes para abrir a tela de código
- Na caixa de listagem à esquerda superior da tela de código, selecione o item Workbook
- Caso nada aconteça, selecio a caixa de listagem à direto superior da tela de código e selecione o item Opem
- Isso fará com que o evento Workbook_Open seja criado automaticamente
O código gerado é parecido com este:
Public Sub Workbook_Open()
End Sub
Qualquer código colocado dentro deste procedimento será executado na abertura da pasta de trabalho.
Conclusão
Como no VBA não existe um contexto de aplicativo, onde existe um método principal de inÃcio de execução, estas rotinas auxiliam bastante quando profissionalizamos programas feitos nesta linguagem.
Bom proveito!
Essa é uma informação um pouco perigosa, devo admitir. Ela compromete uma série de desenvolvedores de aplicativos baseados em VBA, principalmente no contexto de produto.
Mas como considero isso mais uma “falha” do que um “macete”, publicarei aqui a informação para registro e possÃveis providências.
O lado bom
Os desenvolvedores VBA recorrem geralmente à proteção de seus projetos pelo mecanismo de proteção padrão oferecido pelo editor. Clicando com o botão direito sobre o projeto, selecione o opção VBAProject Properties (Propriedades do Projeto VBA):

Ativando a janela de Propriedades do Projeto
A seguinte janela será mostrada após a seleção da aba Protection (Proteção):

Janela de Propriedades do Projeto no VBA
Até aqui é o tradicional. Basta informar a senha nos dois campos e travar o projeto para visualização (lock project for viewing) que teremos nosso projeto VBA bloqueado para visualização e edição na próxima vez em que o arquivo for aberto.
O lado mau
Qualquer veterano na linguagem VBA sabe que existem uma série de programas que “quebram” as senhas destes projetos. Na verdade eles a sobrescrevem de alguma forma. O resultado é que os projetos, mesmo protegidos por senha ficam vulneráveis.
Geralmente estes softwares usam de artimanhas que vão desde a força bruta (tentativa e erro) ou eles entram mesmo no âmago do arquivo mexem no que não devem, substituindo assim a o dado devido.
Esses softwares são pagos na maioria das vezes, o que pelo menos caracteriza um pouco de profissionalismo por parte de seus fabricantes.
Concordo que em alguns casos existe o esquecimento por parte do autor, mas diria que este são a minoria. Geralmente alguém que tem conhecimento em VBA suficiente para construir um projeto que precisa ser protegido por senha, costuma ser organizado com este tipo de coisa. Temos uma outra situação onde empresas geralmente sofrem com funcionários de má fé que vão embora e largam arquivos bloqueados.
Estes são os únicos casos em que vejo necessidade da existência deste tipo de aplicativo, pois trata-se de cuidar da propriedade intectual do proprietário do código fonte.
Tirando isso, o resto pode ser caracterizado como violação de propriedade.
Bom, posto isso, vem aà a má notÃcia.
Quebrando o projeto VBA
É um pouco assustador, mas vamos lá.
Para ter acesso ao código de um projeto VBA, é fácil e barato. Basta baixar o Open Office neste endereço:
http://www.broffice.org/download
Para quem não sabe, o Open Office é uma suÃte de aplicativos de escritório concorrente do Microsoft Office, assim como o Star Office. Não vou discutir as capacidades do Open Office, além da importante caracterÃstica que ele possui de também ter disponÃvel um suÃte de programação muito semelhante ao VBA, também baseada no Visual Basic, capaz de construir aplicações da mesma forma.
Quando você abre um arquivo do Excel ou Word no aplicativos respectivos no Open Office (Calc e Writer), você tem acesso a todo o conteúdo do arquivo da mesma forma, bem como a todo o projeto VBA, incluindo módulos e formulários.
Muito bem, isso tudo é muito bom pois significa uma compatibilidade quase que universal entre arquivos e aplicativos. Com isso não seria necessário conversões na hora de trocar arquivos com outros sistemas.
O problema é que o Open Office abre o projeto em VBA, mesmo que ele esteja protegido por senha.
isso dá a qualquer um acesso completo a todo o código do projeto.
Não há como demonstrar isso aqui, mas para testar:
- crie um novo arquivo no Excel ou Word
- abra o VBA
- adicione alguns módulos e formulários
- adicione alguns controles a estes formulários e alguns códigos simples
- depois disso, proteja o projeto com senha e bloqueie-o para visualização (como mostrado acima)
- salve e feche o arquivo
- abra-o novamente no Microsoft Office para certificar-se de que o projeto está mesmo bloqueado para visualização
- após certificar-se, abra o Open Office Calc para abrir o arquivo de Excel ou o Open Office Calc para o abrir o arquivo do Word
- através do menu ferramentas, abra a tela de macros e selecione um objeto do projeto VBA e clique em editar para visualizar o código
Seguindo estes passos fica provado o fato do acesso extremamente facilitado ao projeto VBA através de um software livre e gratuito.
Conclusões e comentários
Contra a tecnologia não há nada que se possa fazer. Pelo menos com aquilo que veio da tecnologia.
Não dá para saber de quem é a culpa, se é que há algum culpado nesta história.
Da Microsoft por não promover um esquema de segurança mais eficaz?
Da fundação Open Office por não respeitar o esquema de segurança promovido pelo Microsoft Office?
Eu tenho minha opinião. Fica aqui o protesto pelo fato e o agradecimento a blogosfera por permitir descobrir e divulgar a informação.
Abraços
Tomás
Uma funcionalidade não nativa do VBA é a ordenação, seja lá ela qual for.
Ela comumente é necessária em Arrays e controles de lista, como ListBox e ComboBox. Métodos de ordenação existem aos montes. Neste caso, usarei o QuickSort, escrito pelo camarada Frederik do http://users.skynet.be/am044448/Programmeren/. O código abaixo faz a ordenação de um Array passado por parâmetro.
Private Sub QuickSort(strArray() As String, intBottom As Integer, intTop As Integer)
Dim strPivot As String, strTemp As String
Dim intBottomTemp As Integer, intTopTemp As Integer
intBottomTemp = intBottom
intTopTemp = intTop
strPivot = strArray((intBottom + intTop) \ 2)
While (intBottomTemp <= intTopTemp)
While (strArray(intBottomTemp) < strPivot And intBottomTemp < intTop)
intBottomTemp = intBottomTemp + 1
Wend
While (strPivot < strArray(intTopTemp) And intTopTemp > intBottom)
intTopTemp = intTopTemp - 1
Wend
If intBottomTemp < intTopTemp Then
strTemp = strArray(intBottomTemp)
strArray(intBottomTemp) = strArray(intTopTemp)
strArray(intTopTemp) = strTemp
End If
If intBottomTemp <= intTopTemp Then
intBottomTemp = intBottomTemp + 1
intTopTemp = intTopTemp - 1
End If
Wend
‘faz a chamada recursiva a si própria até que lista esteja preenchida
If (intBottom < intTopTemp) Then QuickSort strArray, intBottom, intTopTemp
If (intBottomTemp < intTop) Then QuickSort strArray, intBottomTemp, intTop
End Sub
A função não tem um retorno, mas como um array passado por parâmetro para um função é sempre por referência, após a execução desta seu Array estará ordenado em ordem crescente.
Para testar o funcionamento da função, crie um userForm no VBA. Coloque nele um ListBox e um CommandButton, sem se preocupar com alterar seus nomes. Coloque no código do Form a função QuickSort mostrada acima, mais o código abaixo.
Private Sub CommandButton1_Click()
Dim MyArray(12) As String
Dim i As Long
‘caso não haja itens na lista, não é necessário fazer ordenação
If ListBox1.ListCount <= 1 Then Exit Sub
‘alimenta o array
For i = 0 To ListBox1.ListCount - 1
MyArray(i) = ListBox1.List(i, 0)
Next i
‘ordena o array
QuickSort MyArray, LBound(MyArray), UBound(MyArray)
‘limpa o listbox
ListBox1.Clear
‘usa o array ordenado para preencher o listbox
For i = 1 To UBound(MyArray)
ListBox1.AddItem MyArray(i)
Next i
End Sub
Private Sub UserForm_Initialize()
‘preenche o listbox com os meses do ano
For i = 1 To 12
ListBox1.AddItem MonthName(i, False)
Next
End Sub
Ao executar o form da primeira vez, pode-se ver que o ListBox é preenchido com os meses do ano através da função MontName.

Listbox Carregado com os meses
O código colocado no evento click do botão cria um array de string de tamanho 12, preenche o array com a lista de valores presente no listbox, ordena o array através da função QuickSort e re-preenche o listbox.

ListBox Ordenado
Uma forma bem simples de fazer ordenação em listas sempre precisar ficar re-pensando no código sempre que precisar.
<< Download do Arquivo >>
Abraços
Tomás