multiple - Funciones ocultas de VBA
vba excel comment (16)
¿Qué características del lenguaje VBA están mal documentadas o simplemente no se usan con frecuencia?
Con un poco de trabajo, puede iterar sobre colecciones 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
Su código de colección personalizado (en una clase llamada 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
Diccionarios. ¡VBA es prácticamente inútil sin ellos!
Consulte Microsoft Scripting Runtime, use Scripting.Dictionary
para cualquier tarea suficientemente complicada y viva feliz para siempre.
El Scripting Runtime también le proporciona el FileSystemObject, que también viene muy recomendado.
Comienza aquí, luego excava un poco ...
http://msdn.microsoft.com/en-us/library/aa164509%28office.10%29.aspx
El modelo de objetos VBE (Extensibilidad Visual Basic) es una característica menos conocida y / o infrautilizada. Le permite escribir código VBA para manipular códigos, módulos y proyectos de VBA. Una vez escribí un proyecto de Excel que reuniría otros proyectos de Excel de un grupo de archivos de módulos.
El modelo de objetos también funciona desde VBScript y HTA. Escribí una HTA a la vez para ayudarme a hacer un seguimiento de una gran cantidad de proyectos de Word, Excel y Access. Muchos de los proyectos utilizarían módulos de código comunes, y era fácil que los módulos "crecieran" en un sistema y luego se migraran a otros sistemas. Mi HTA me permite exportar todos los módulos en un proyecto, compararlos con las versiones en una carpeta común y fusionar rutinas actualizadas (usando BeyondCompare), y luego volver a importar los módulos actualizados.
El modelo de objetos VBE funciona de forma ligeramente diferente entre Word, Excel y Access, y desafortunadamente no funciona con Outlook en absoluto, pero aún ofrece una gran capacidad para administrar el código.
Escribiendo VBA.
aparecerá una lista intellisense de todas las funciones y constantes incorporadas.
Este truco solo funciona en Access VBA, Excel y otros no lo permitirán. Pero puede hacer que un Módulo estándar esté oculto desde el navegador de objetos al agregar el nombre del Módulo con un guión bajo. El módulo solo será visible si cambia el navegador de objetos para mostrar objetos ocultos.
Este truco funciona con Enums en todas las versiones basadas en vb6 de VBA. Puede crear un miembro oculto de un Enum al incluir su nombre entre corchetes, y luego ponerle un guión bajo. Ejemplo:
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
En Excel-VBA puede hacer referencia a las celdas encerrándolas entre paréntesis, los paréntesis también funcionan como un comando de evaluación que le permite evaluar la sintaxis de la fórmula:
Public Sub Example()
[A1] = "Foo"
MsgBox [VLOOKUP(A1,A1,1,0)]
End Sub
También puede pasar datos sin procesar sin utilizar MemCopy (RtlMoveMemory) combinando LSet con tipos definidos por el usuario del mismo tamaño:
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
Los literales octales y hexadecimales son en realidad tipos sin firmar, ambos tendrán una salida -32768:
Public Sub Example()
Debug.Print &H8000
Debug.Print &O100000
End Sub
Como se mencionó, pasar una variable dentro de paréntesis hace que sea pasada 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
Puede asignar una cadena directamente en una matriz de bytes y viceversa:
Public Sub Example()
Dim myString As String
Dim myBytArr() As Byte
myBytArr = "I am a string."
myString = myBytArr
MsgBox myString
End Sub
"Mid" también es un operador. Utilizándolo sobrescribe partes específicas de cadenas sin la concatenación de cadenas notoriamente lenta de 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
Funciones ocultas
- Aunque es "Básico", puede usar OOP - clases y objetos
- Puedes hacer llamadas a la API
Hay una característica importante pero casi siempre perdida de la declaración Mid (). Aquí es donde aparece Mid () en el lado izquierdo de una tarea en oposición a la función Mid () que aparece en el lado derecho o en una expresión.
La regla es que si la cadena de destino no es una cadena literal, y esta es la única referencia a la cadena de destino, y la longitud del segmento que se inserta coincide con la longitud del segmento que se reemplaza, entonces la cadena se tratará como mutable para la operación.
Qué significa eso? Significa que si construyes un gran informe o una enorme lista de cadenas en un solo valor de cadena, explotar esto hará que tu cadena de procesamiento sea mucho más rápida.
Aquí hay una clase simple que se beneficia de esto. Le da a su VBA la misma capacidad de StringBuilder que tiene .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
Y aquí hay un ejemplo sobre cómo 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
No es una característica, pero una cosa que he visto tantas veces en VBA (y VB6): paréntesis agregado en llamadas a métodos donde cambiará la 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
Posiblemente las características menos documentadas en VBA son aquellas que solo puede exponer al seleccionar "Mostrar miembros ocultos" en el navegador de objetos VBA. Los miembros ocultos son aquellas funciones que están en VBA, pero no son compatibles. Puede usarlos, pero Microsoft podría eliminarlos en cualquier momento. Ninguno de ellos tiene documentación provista, pero puede encontrar algunos en la web. Posiblemente, la característica más comentada de estas funciones ocultas proporcione acceso a punteros en VBA. Para un comentario decente, echa un vistazo; No tan ligero - Shlwapi.dll
Documentado, pero tal vez más oscuro (en cualquier caso, Excel) está utilizando ExecuteExcel4Macro para acceder a un espacio de nombres global oculto que pertenece a la instancia de la aplicación de Excel en lugar de un libro de trabajo específico.
Puede implementar interfaces con la palabra clave Implements
.
Soporte para versiones localizadas, que (al menos en el siglo anterior) soportaban expresiones que usaban valores localizados. Como Pravda para True y FaĆszywy (no estoy seguro, pero al menos tenía la divertida L) para False en polaco ... En realidad, la versión en inglés podría leer macros en cualquier idioma y convertir sobre la marcha. Sin embargo, otras versiones localizadas no manejarían eso.
FALLAR.
VBA admite operadores bit a bit para comparar los dígitos binarios (bits) de dos valores. Por ejemplo, la expresión 4 y 7 evalúa los valores de bit de 4 (0100) y 7 (0111) y devuelve 4 (el bit que está activado en ambos números). De forma similar, la expresión 4 u 8 evalúa los valores de bit en 4 (0100 ) y 8 (1000) y devuelve 12 (1100), es decir, los bits donde cualquiera de ellos es verdadero.
Desafortunadamente, los operadores bit a bit tienen los mismos nombres en los operadores lógicos de comparación: E, Eqv, Imp, Not, Or y Xor. Esto puede generar ambigüedades e incluso resultados contradictorios.
Como ejemplo, abra la Ventana Inmediata (Ctrl + G) e ingrese:? (2 y 4) Esto devuelve cero, ya que no hay bits en común entre 2 (0010) y 4 (0100).
VBA en sí parece ser una característica oculta. Las personas que conozco que han usado productos de Office durante años no tienen idea de que son parte de la suite.
He publicado esto en varias preguntas aquí, pero el navegador de objetos es mi arma secreta. Si necesito código ninja algo muy rápido, pero no estoy familiarizado con el dll, Object Browser me salva la vida. Hace que sea mucho más fácil aprender las estructuras de clase que MSDN.
La ventana Locals es ideal para la depuración también. Ponga una pausa en su código y le mostrará todas las variables, sus nombres y sus valores y tipos actuales dentro del espacio de nombres actual.
¿Y quién podría olvidar a nuestro buen amigo Ventana Inmediata? No solo es excelente para la salida estándar de Debug.Print, sino que también puede ingresar comandos en ella. ¿Necesita saber qué es VariableX?
?VariableX
¿Necesitas saber de qué color es esa celda?
?Application.ActiveCell.Interior.Color
De hecho, todas esas ventanas son excelentes herramientas para ser productivo con VBA.
Esta característica existe presumiblemente por compatibilidad con versiones anteriores. O para escribir un código de espagueti irremediablemente ofuscado. Tu selección.
IsDate("13.50")
devuelve True
pero IsDate("12.25.2010")
devuelve False
Esto se debe a que IsDate
podría IsDateTime
mayor precisión IsDateTime
. Y porque el período ( .
) Se trata como un separador de tiempo y no como un separador de fecha. Vea aquí para una explicación completa .
- Guarde 4 pulsaciones de teclas enteras escribiendo
debug.? xxx
debug.? xxx
lugar dedebug.print xxx
. - Crash it agregando:
enum foo: me=0: end enum
a la parte superior de un módulo que contiene cualquier otro código.