Funzionalità nascoste di VBA

Quali caratteristiche del linguaggio VBA sono scarsamente documentate o semplicemente non usate spesso?

Questo trucco funziona solo in Access VBA, Excel e altri non lo consentono. Ma puoi rendere un modulo standard nascosto dal browser degli oggetti aggiungendo il prefisso al nome del modulo con un trattino basso. Il modulo sarà quindi visibile solo se cambi il browser degli oggetti per mostrare oggetti nascosti.

Questo trucco funziona con Enums in tutte le versioni VBA basate su VB6. Puoi creare un membro nascosto di un Enum racchiudendolo tra parentesi, quindi aggiungendolo come prefisso. Esempio:

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 

In Excel-VBA è ansible fare riferimento alle celle racchiudendole tra parentesi, le parentesi fungono anche da comando di valutazione che consente di valutare la syntax della formula:

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

Inoltre è ansible passare i dati grezzi senza utilizzare MemCopy (RtlMoveMemory) combinando LSet con tipi definiti dall'utente della stessa dimensione:

 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 

I letterali ottali e esadecimali sono in realtà tipi non firmati, entrambi restituiscono l'output -32768:

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

Come accennato, il passaggio di una variabile all'interno di una parentesi provoca il superamento di 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 

È ansible assegnare una stringa direttamente a un array di byte e viceversa:

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

"Mid" è anche un operatore. Usandolo si sovrascrivono porzioni specifiche di stringhe senza la concatenazione di stringhe notoriamente lenta di 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 

C’è una caratteristica importante ma quasi sempre mancata dell’istruzione Mid (). È qui che Mid () appare sul lato sinistro di un compito in contrasto con la funzione Mid () che appare nel lato destro o in un’espressione.

La regola è che se la stringa di destinazione non è una stringa letterale e questo è l’unico riferimento alla stringa di destinazione e la lunghezza del segmento che viene inserita corrisponde alla lunghezza del segmento che viene sostituito, la stringa verrà considerata come mutabile per l’operazione.

Cosa significa? Significa che se si crea un report di grandi dimensioni o un enorme elenco di stringhe in un singolo valore di stringa, lo sfruttamento renderà l’elaborazione delle stringhe molto più veloce.

Ecco una class semplice che beneficia di questo. Fornisce al tuo VBA la stessa capacità di StringBuilder di .Net.

 ' 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 

Ed ecco un esempio su come usarlo:

  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 

Lo stesso VBA sembra essere una caratteristica nascosta. Gente che conosco che ha usato per anni i prodotti Office non ha idea che faccia parte della suite.

Ho postato questo su più domande qui, ma l’Object Browser è la mia arma segreta. Se ho bisogno di codice ninja qualcosa di veramente veloce, ma non ho familiarità con la DLL, Object Browser mi salva la vita. Rende molto più semplice l’apprendimento delle strutture di class rispetto a MSDN.

La finestra dei locali è ottima anche per il debug. Metti una pausa nel tuo codice e ti mostrerà tutte le variabili, i loro nomi e i loro valori e tipi correnti all’interno dello spazio dei nomi corrente.

E chi potrebbe dimenticare il nostro buon amico Finestra Immediata? Non solo è ottimo per l’output standard di Debug.Print, ma puoi anche inserire comandi in esso. Hai bisogno di sapere cosa è VariableX?

 ?VariableX 

Hai bisogno di sapere di che colore è quella cella?

 ?Application.ActiveCell.Interior.Color 

In realtà tutte quelle windows sono ottimi strumenti per essere produttivi con VBA.

Non è una funzionalità, ma una cosa che ho visto in modo errato così tante volte in VBA (e VB6): Parentesi aggiunta alle chiamate di metodo dove cambierà la semantica:

 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 

Caratteristiche nascoste

  1. Sebbene sia “Base”, puoi usare OOP – classi e oggetti
  2. Puoi effettuare chiamate API

Probabilmente le funzionalità meno documentate in VBA sono quelle che puoi esporre solo selezionando “Mostra membri nascosti” nel Visualizzatore oggetti VBA. I membri nascosti sono quelle funzioni che sono in VBA, ma non sono supportate. Puoi usarli, ma Microsoft potrebbe eliminarli in qualsiasi momento. Nessuno di loro ha alcuna documentazione fornita, ma è ansible trovarne alcuni sul web. Probabilmente il più parlato di queste funzionalità nascoste fornisce l’accesso ai puntatori in VBA. Per una buona risposta, controlla; Non così leggero – Shlwapi.dll

Documentato, ma forse più oscuro (in ogni caso, excel) utilizza ExecuteExcel4Macro per accedere a uno spazio dei nomi globale nascosto che appartiene all’intera istanza dell’applicazione Excel anziché a una cartella di lavoro specifica.

È ansible implementare interfacce con la parola chiave Implements .

Dizionari. VBA è praticamente inutile senza di loro!

Fai riferimento a Microsoft Scripting Runtime, usa Scripting.Dictionary per qualsiasi compito sufficientemente complicato e vivi felice e contento.

Lo Scripting Runtime ti offre anche FileSystemObject, che viene anche altamente raccomandato.

Inizia qui, quindi scava un po ‘…

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

Digitando VBA. mostrerà un elenco intellisense di tutte le funzioni e costanti incorporate.

Con un po ‘di lavoro, puoi eseguire iterazioni su raccolte personalizzate come questa:

 ' 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 

Il tuo codice di raccolta personalizzato (in una class chiamata 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 
  • Salva 4 intere sequenze di tasti digitando debug.? xxx debug.? xxx invece di debug.print xxx .
  • Arrestalo aggiungendo: enum foo: me=0: end enum all’inizio di un modulo contenente qualsiasi altro codice.

Supporto per versioni localizzate, che (almeno nel secolo precedente) supportavano espressioni utilizzando valori localizzati. Come Pravda per True e Fałszywy (non troppo sicuro, ma almeno aveva la buffa L) per False in polacco … In realtà la versione inglese sarebbe in grado di leggere macro in qualsiasi lingua e convertire al volo. Tuttavia, altre versioni localizzate non lo gestiranno.

FALLIRE.

Il modello di oggetti VBE (Visual Basic Extensibility) è una funzionalità meno conosciuta e / o poco utilizzata. Permette di scrivere codice VBA per manipolare codice VBA, moduli e progetti. Una volta ho scritto un progetto Excel che avrebbe assemblato altri progetti Excel da un gruppo di file modulo.

Il modello a oggetti funziona anche da VBScript e HTA. Ho scritto un HTA in una volta per aiutarmi a tenere traccia di un gran numero di progetti Word, Excel e Access. Molti progetti usavano moduli di codice comuni, ed era facile che i moduli “crescessero” in un sistema e quindi dovevano essere migrati ad altri sistemi. Il mio HTA mi permetterebbe di esportare tutti i moduli in un progetto, confrontarli con le versioni in una cartella comune e unire le routine aggiornate (usando BeyondCompare), quindi reimportare i moduli aggiornati.

Il modello di oggetti VBE funziona in modo leggermente diverso tra Word, Excel e Access e, sfortunatamente, non funziona affatto con Outlook, ma offre comunque una grande capacità di gestione del codice.

IsDate("13.50") restituisce True ma IsDate("12.25.2010") restituisce False

Questo perché IsDate potrebbe essere più precisamente denominato IsDateTime . E poiché il punto ( . ) Viene considerato un separatore di orario e non un separatore di data. Vedi qui per una spiegazione completa .

VBA supporta operatori bit a bit per confrontare le cifre binarie (bit) di due valori. Ad esempio, l’espressione 4 e 7 valuta i valori di bit di 4 (0100) e 7 (0111) e restituisce 4 (il bit che si trova in entrambi i numeri.) Analogamente l’espressione 4 o 8 valuta i valori di bit in 4 (0100 ) e 8 (1000) e restituisce 12 (1100), ovvero i bit in cui uno dei due è vero.

Sfortunatamente, gli operatori bit a bit hanno gli stessi nomi negli operatori di confronto logico: E, Eqv, Imp, Not, Or e Xor. Ciò può portare a ambiguità e persino a risultati contraddittori.

Ad esempio, apri la Finestra Immediata (Ctrl + G) e inserisci:? (2 E 4) Restituisce zero, poiché non ci sono bit in comune tra 2 (0010) e 4 (0100).

Dichiarazioni di Deftype

Questa funzione esiste presumibilmente per la retrocompatibilità. O per scrivere un codice spaghetti irrimediabilmente offuscato. La tua scelta