Recursos ocultos do VBA

Quais resources do idioma do VBA estão mal documentados ou simplesmente não são usados ​​com frequência?

Esse truque só funciona no Access VBA, o Excel e outros não permitem isso. Mas você pode fazer um Módulo Padrão escondido do navegador de objects prefixando o nome do Módulo com um sublinhado. O módulo só ficará visível se você alterar o navegador de objects para mostrar objects ocultos.

Esse truque funciona com Enums em todas as versões baseadas em vb6 do VBA. Você pode criar um membro oculto de um Enum colocando o nome entre colchetes e prefixando-o com um sublinhado. Exemplo:

Public Enum MyEnum meDefault = 0 meThing1 = 1 meThing2 = 2 meThing3 = 3 [_Min] = meDefault [_Max] = meThing3 End Enum Public Function IsValidOption(ByVal myOption As MyEnum) As Boolean If myOption >= MyEnum.[_Min] Then IsValidOption myOption < = MyEnum.[_Max] End Function 

No Excel-VBA você pode referenciar as células colocando-as entre parênteses, os parênteses também funcionam como um comando de avaliação, permitindo que você avalie a syntax da fórmula:

 Public Sub Example() [A1] = "Foo" MsgBox [VLOOKUP(A1,A1,1,0)] End Sub 

Além disso, você pode passar dados brutos sem usar MemCopy (RtlMoveMemory) combinando LSet com tipos definidos pelo usuário do mesmo tamanho:

 Public Sub Example() Dim b() As Byte b = LongToByteArray(8675309) MsgBox b(1) End Sub Private Function LongToByteArray(ByVal value As Long) As Byte() Dim tl As TypedLong Dim bl As ByteLong tl.value = value LSet bl = tl LongToByteArray = bl.value End Function 

Octal & Hex Literals são na verdade tipos não assinados, ambos serão produzidos em -32768:

 Public Sub Example() Debug.Print &H8000 Debug.Print &O100000 End Sub 

Como mencionado, passar uma variável entre parênteses faz com que seja passado ByVal:

 Sub PredictTheOutput() Dim i&, j&, k& i = 10: j = i: k = i MySub (i) MySub j MySub k + 20 MsgBox Join(Array(i, j, k), vbNewLine), vbQuestion, "Did You Get It Right?" End Sub Public Sub MySub(ByRef foo As Long) foo = 5 End Sub 

Você pode atribuir uma string diretamente a uma matriz de bytes e vice-versa:

 Public Sub Example() Dim myString As String Dim myBytArr() As Byte myBytArr = "I am a string." myString = myBytArr MsgBox myString End Sub 

"Mid" também é um operador. Ao usá-lo, você sobrescreve partes específicas de strings sem a concatenação de strings notoriamente lenta do VBA:

 Public Sub Example1() ''// This takes about 47% of time Example2 does: Dim myString As String myString = "I liek pie." Mid(myString, 5, 2) = "ke" Mid(myString, 11, 1) = "!" MsgBox myString End Sub Public Sub Example2() Dim myString As String myString = "I liek pie." myString = "I li" & "ke" & " pie" & "!" MsgBox myString End Sub 

Há um recurso importante, mas quase sempre ausente da instrução Mid (). É aí que Mid () aparece no lado esquerdo de uma atribuição, em oposição à function Mid () que aparece no lado direito ou em uma expressão.

A regra é que, se a cadeia de destino não for uma cadeia literal, e essa for a única referência à cadeia de destino, e o comprimento do segmento que estiver sendo inserido corresponder ao comprimento do segmento que está sendo substituído, a cadeia será tratada como mutável para a operação.

O que isso significa? Isso significa que, se você criar um relatório grande ou uma lista enorme de strings em um único valor de string, explorar isso fará com que o processamento da string seja muito mais rápido.

Aqui está uma class simples que se beneficia disso. Ele dá ao seu VBA o mesmo recurso StringBuilder que o .Net possui.

 ' Class: StringBuilder Option Explicit Private Const initialLength As Long = 32 Private totalLength As Long ' Length of the buffer Private curLength As Long ' Length of the string value within the buffer Private buffer As String ' The buffer Private Sub Class_Initialize() ' We set the buffer up to it's initial size and the string value "" totalLength = initialLength buffer = Space(totalLength) curLength = 0 End Sub Public Sub Append(Text As String) Dim incLen As Long ' The length that the value will be increased by Dim newLen As Long ' The length of the value after being appended incLen = Len(Text) newLen = curLength + incLen ' Will the new value fit in the remaining free space within the current buffer If newLen < = totalLength Then ' Buffer has room so just insert the new value Mid(buffer, curLength + 1, incLen) = Text Else ' Buffer does not have enough room so ' first calculate the new buffer size by doubling until its big enough ' then build the new buffer While totalLength < newLen totalLength = totalLength + totalLength Wend buffer = Left(buffer, curLength) & Text & Space(totalLength - newLen) End If curLength = newLen End Sub Public Property Get Length() As Integer Length = curLength End Property Public Property Get Text() As String Text = Left(buffer, curLength) End Property Public Sub Clear() totalLength = initialLength buffer = Space(totalLength) curLength = 0 End Sub 

E aqui está um exemplo de como usá-lo:

  Dim i As Long Dim sb As StringBuilder Dim result As String Set sb = New StringBuilder For i = 1 to 100000 sb.Append CStr( i) Next i result = sb.Text 

O próprio VBA parece ser um recurso oculto. As pessoas que conheço e que usaram produtos do Office há anos não fazem a menor ideia de que fazem parte da suíte.

Eu postei isso em várias perguntas aqui, mas o Navegador de Objetos é minha arma secreta. Se eu precisar ninja código algo muito rápido, mas não estou familiarizado com a dll, object Browser salva minha vida. Isso torna muito mais fácil aprender as estruturas de classs do que o MSDN.

A janela Locals é ótima para debugging também. Coloque uma pausa em seu código e ele mostrará todas as variables, seus nomes e seus valores e tipos atuais no namespace atual.

E quem poderia esquecer o nosso bom amigo Immediate Window? Não só é ótimo para a saída padrão do Debug.Print, mas também é possível inserir comandos nele. Precisa saber o que é VariableX?

 ?VariableX 

Precisa saber de que cor é essa célula?

 ?Application.ActiveCell.Interior.Color 

Na verdade, todas essas janelas são ótimas ferramentas para serem produtivas com o VBA.

Não é um recurso, mas uma coisa que eu vi errado tantas vezes em VBA (e VB6): Parêntese adicionado em chamadas de método onde ele irá mudar a semântica:

 Sub Foo() Dim str As String str = "Hello" Bar (str) Debug.Print str 'prints "Hello" because str is evaluated and a copy is passed Bar str 'or Call Bar(str) Debug.Print str 'prints "Hello World" End Sub Sub Bar(ByRef param As String) param = param + " World" End Sub 

Recursos ocultos

  1. Embora seja “Básico”, você pode usar OOP – classs e objects
  2. Você pode fazer chamadas de API

Possivelmente, os resources menos documentados no VBA são aqueles que você pode expor apenas selecionando “Mostrar Membros Ocultos” no Navegador de Objetos VBA. Membros ocultos são aquelas funções que estão no VBA, mas não são suportadas. Você pode usá-los, mas a Microsoft pode eliminá-los a qualquer momento. Nenhum deles tem documentação fornecida, mas você pode encontrar alguns na web. Possivelmente, o mais falado desses resources ocultos fornece access a pointers no VBA. Para um writeup decente, confira; Não tão leve – Shlwapi.dll

Documentado, mas talvez mais obscuro (no excel de qualquer maneira) está usando ExecuteExcel4Macro para acessar um namespace global oculto que pertença a toda a instância do aplicativo do Excel, em oposição a uma pasta de trabalho específica.

Você pode implementar interfaces com a palavra-chave Implements .

Dicionários VBA é praticamente inútil sem eles!

Consulte o Microsoft Scripting Runtime, use Scripting.Dictionary para qualquer tarefa suficientemente complicada e viva feliz para sempre.

O Scripting Runtime também fornece o FileSystemObject, que também é altamente recomendado.

Comece aqui, depois cave um pouco …

http://msdn.microsoft.com/pt-br/library/aa164509%28office.10%29.aspx

Digitando o VBA. trará uma listview intellisense de todas as funções e constantes internas.

Com um pouco de trabalho, você pode fazer iterações em collections personalizadas como esta:

 ' Write some text in Word first.' Sub test() Dim c As New clsMyCollection c.AddItems ActiveDocument.Characters(1), _ ActiveDocument.Characters(2), _ ActiveDocument.Characters(3), _ ActiveDocument.Characters(4) Dim el As Range For Each el In c Debug.Print el.Text Next Set c = Nothing End Sub 

Seu código de coleção personalizado (em uma class chamada clsMyCollection ):

 Option Explicit Dim m_myCollection As Collection Public Property Get NewEnum() As IUnknown ' This property allows you to enumerate ' this collection with the For...Each syntax ' Put the following line in the exported module ' file (.cls)!' 'Attribute NewEnum.VB_UserMemId = -4 Set NewEnum = m_myCollection.[_NewEnum] End Property Public Sub AddItems(ParamArray items() As Variant) Dim i As Variant On Error Resume Next For Each i In items m_myCollection.Add i Next On Error GoTo 0 End Sub Private Sub Class_Initialize() Set m_myCollection = New Collection End Sub 
  • Salvar 4 pressionamentos de teclas inteiras digitando debug.? xxx debug.? xxx vez de debug.print xxx .
  • Crash it sumndo: enum foo: me=0: end enum para o topo de um módulo contendo qualquer outro código.

Suporte para versões localizadas, que (pelo menos no século anterior) suportavam expressões usando valores localizados. Como Pravda para True e Fałszywy (não muito certo, mas pelo menos tinha o engraçado L) para False em polonês … Na verdade, a versão em inglês seria capaz de ler macros em qualquer idioma e converter em tempo real. Outras versões localizadas não lidariam com isso.

FALHOU.

O modelo de object VBE (Extensibilidade do Visual Basic) é um recurso menos conhecido e / ou subutilizado. Ele permite que você escreva código VBA para manipular código, módulos e projetos do VBA. Certa vez, escrevi um projeto do Excel que reunia outros projetos do Excel de um grupo de arquivos de módulo.

O modelo de object também funciona em VBScript e HTAs. Escrevi um HTA de uma só vez para me ajudar a acompanhar um grande número de projetos do Word, Excel e Access. Muitos dos projetos usariam módulos de código comuns, e era fácil para os módulos “crescerem” em um sistema e, em seguida, precisam ser migrados para outros sistemas. Meu HTA me permitiria exportar todos os módulos em um projeto, compará-los a versões em uma pasta comum e mesclar rotinas atualizadas (usando BeyondCompare), em seguida, reimportar os módulos atualizados.

O modelo de object VBE funciona de forma ligeiramente diferente entre o Word, o Excel e o Access e, infelizmente, não funciona com o Outlook, mas ainda fornece uma excelente capacidade de gerenciamento de código.

IsDate("13.50") retorna True mas IsDate("12.25.2010") retorna False

Isso ocorre porque o IsDate poderia ser mais precisamente denominado IsDateTime . E porque o ponto ( . ) É tratado como um separador de hora e não como um separador de data. Veja aqui uma explicação completa .

O VBA suporta operadores bit a bit para comparar os dígitos binários (bits) de dois valores. Por exemplo, a expressão 4 And 7 avalia os valores de bit de 4 (0100) e 7 (0111) e retorna 4 (o bit que está em ambos os números). Similarmente a expressão 4 ou 8 avalia os valores de bit em 4 (0100 ) e 8 (1000) e retorna 12 (1100), ou seja, os bits em que qualquer um é verdadeiro.

Infelizmente, os operadores bit a bit possuem os mesmos nomes nos operadores de comparação lógica: E, Eqv, Imp, Not, Or e Xor. Isso pode levar a ambiguidades e até a resultados contraditórios.

Como exemplo, abra a janela Immediate (Ctrl + G) e digite:? (2 e 4) Isso retorna zero, pois não há bits em comum entre 2 (0010) e 4 (0100).

Declarações de Defype

Esse recurso existe presumivelmente para compatibilidade com versões anteriores. Ou para escrever código de espaguete irremediavelmente ofuscado. Sua escolha.