🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA CallByName en Excel — Obtenga o asigne una propiedad, o ejecute un método, por su nombre

|

VBA CallByName en Excel — Obtenga o asigne una propiedad, o ejecute un método, por su nombre

TL;DR — CallByName(object, "MemberName", callType, args) lee una propiedad, escribe una propiedad o ejecuta un método sobre un objeto usando el nombre del miembro como una cadena. El callType —VbGet, VbLet, VbSet o VbMethod— le dice a VBA cuál de esas cuatro cosas quiere, y elegir el equivocado es la causa número uno del error 438. Solo alcanza miembros Public. Úselo cuando el nombre de la propiedad o del método se decide en tiempo de ejecución —un formulario gobernado por datos, una tabla de ajustes—, no cuando ya conoce el miembro y puede escribir obj.Member directamente.

Sub SetByName()
    Dim ctl As Object
    Set ctl = Me.Controls("txtName")
    ' Escribir una propiedad cuyo nombre es una cadena:
    CallByName ctl, "Value", VbLet, "Ada Lovelace"
    ' Leer una propiedad cuyo nombre es una cadena:
    MsgBox CallByName(ctl, "Value", VbGet)
End Sub

Normalmente usted llega a un miembro de un objeto escribiéndolo: range.Value, sheet.Name, form.Hide. Eso funciona porque conoce el miembro al escribir el código. CallByName es para el caso en que no lo conoce: el nombre de la propiedad o del método llega como texto, desde una tabla, una hoja de configuración o un bucle. Es la segunda de tres herramientas que comparten una misma idea. Application.Run convierte una cadena en una macro en ejecución; CallByName convierte una cadena en una llamada a un miembro de un objeto; y Evaluate convierte una cadena en una expresión de Excel calculada. Las tres cambian el compilador por flexibilidad en tiempo de ejecución: como el nombre del miembro es texto, un error de escritura ya no es un subrayado rojo, sino un error en tiempo de ejecución. Así que se aplica la misma regla: nunca le dé a CallByName un nombre de miembro que usted mismo no haya construido o validado.

Lo que aprenderá

  • Dónde se sitúa CallByName junto a Application.Run y Evaluate
  • Los cuatro tipos de llamada —VbGet, VbLet, VbSet, VbMethod— y qué significa cada uno
  • Por qué el tipo de llamada equivocado provoca el error 438, y cómo leer el mensaje
  • Cómo pasar argumentos a un método o a una propiedad indexada
  • La regla de solo Public que hace que algunas llamadas fallen en silencio
  • El patrón para el que existe: aplicar una tabla de nombres y valores a un objeto

El modelo mental: reflexión dirigida a los miembros de un objeto

Application.Run busca una macro por su nombre. CallByName hace el mismo truco un nivel más abajo: busca un miembro de un objeto concreto por su nombre. Usted le entrega el objeto, el nombre del miembro como una cadena y una cosa más que la sintaxis directa le oculta: qué tipo de acceso quiere. obj.Value = 5, x = obj.Value y obj.Refresh se ven distintos en el código normal, pero para CallByName son la misma llamada con un callType diferente.

x = obj.Caption            ' directo: lectura
CallByName obj, "Caption", VbGet          ' la misma lectura, nombre del miembro como una cadena

Ese argumento extra, callType, es toda la razón por la que CallByName resulta poco familiar. En cuanto lo ve como «cuál de los cuatro tipos de acceso a miembros», la función deja de ser un misterio.

Los cuatro tipos de llamada

VBA distingue cuatro cosas que puede hacer con un miembro, y usted debe decirle a CallByName cuál:

CallByName obj, "Value",   VbGet                 ' leer una propiedad  -> devuelve el valor
CallByName obj, "Value",   VbLet, "New text"     ' escribir una propiedad de valor
CallByName obj, "Range",   VbSet, someRange      ' escribir una propiedad de OBJETO (necesita Set)
CallByName obj, "Refresh", VbMethod              ' ejecutar un metodo

La división entre VbLet y VbSet refleja el propio Let frente a Set de VBA: use VbLet para un valor simple (un número, una cadena, un booleano) y VbSet para una referencia a un objeto (asignar un Range u otro objeto a una propiedad). VbGet lee; VbMethod llama. Casi todos los errores con CallByName consisten en elegir el equivocado de estos cuatro.

La trampa: el tipo de llamada equivocado provoca el error 438

Esta es la línea que hay que recordar. Si el miembro no existe, o usted pide el tipo de acceso equivocado, VBA no puede avisarle en tiempo de compilación —el nombre es una cadena—, así que obtiene el error en tiempo de ejecución 438, «Object doesn't support this property or method»:

' Incorrecto: Caption es una propiedad, no un metodo
CallByName lbl, "Caption", VbMethod        ' -> error 438

' Correcto: leerla con VbGet
Dim text As String
text = CallByName(lbl, "Caption", VbGet)

El mensaje engaña un poco: a menudo el objeto sí admite el miembro; usted simplemente lo pidió de forma equivocada (un VbMethod sobre una propiedad, o un VbGet sobre un método que necesita VbMethod). Cuando vea un 438 procedente de CallByName, revise el tipo de llamada antes de dudar del nombre del miembro. Y como el nombre viene de datos, envuelva las llamadas de origen dinámico en un control On Error para que un nombre inesperado sea un resultado controlado, no un fallo.

Pasar argumentos a un método o a una propiedad indexada

Los argumentos van después del tipo de llamada, en orden:

' Un metodo con argumentos:
CallByName ws, "Protect", VbMethod, "password123"

' Una propiedad indexada (Cells(2, 3)) mediante CallByName:
Dim v As Variant
v = CallByName(ws, "Cells", VbGet, 2, 3)     ' igual que ws.Cells(2, 3)

Los argumentos son posicionales, igual que con Application.Run. Si un método toma varios, enumérelos en el orden de la firma. Así es también como llega a propiedades indexadas como Cells(row, col) cuando el propio nombre de la propiedad es dinámico.

La regla de solo Public

CallByName solo puede alcanzar miembros Public. Una propiedad o un método Private dentro de un módulo de clase le resulta invisible y —como el nombre es una cadena— usted obtiene el mismo 438 en tiempo de ejecución que obtendría por un error de escritura, sin ninguna pista de que el verdadero problema es la visibilidad. Si una llamada falla sobre un miembro que está seguro de que existe, confirme que esté declarado Public en la clase del objeto. Este es un tropiezo común cuando maneja por su nombre sus propios objetos de clase en lugar de objetos integrados de Excel.

El patrón para el que existe: una tabla de nombres y valores

CallByName se gana su lugar cuando tiene muchos miembros que tocar y sus nombres viven en datos. El caso de manual: aplicar una tabla de nombres y valores de propiedad a un control, una forma o un gráfico, sin escribir una línea de asignación por propiedad.

' Los ajustes podrian venir de una hoja: columna A = propiedad, columna B = valor
Dim props As Variant, vals As Variant, i As Long
props = Array("Caption", "Width", "Visible")
vals  = Array("Total", 120, True)
For i = LBound(props) To UBound(props)
    CallByName btn, props(i), VbLet, vals(i)      ' un bucle en lugar de tres asignaciones
Next i

Tres propiedades es un juguete; treinta es un formulario de verdad, y ahí es donde el bucle sustituye a un muro de líneas btn.Caption = ... : btn.Width = .... El criterio es el mismo que con el resto de esta familia: si los nombres de los miembros son constantes que usted escribe una vez, use la sintaxis directa —btn.Caption = "Total" es más claro y el compilador lo comprueba—. Solo cuando los nombres son genuinamente datos compensa CallByName la pérdida de seguridad en tiempo de compilación.

Cómo ayuda ExcelMaster

Los errores aquí son silenciosos: un VbMethod donde correspondía un VbGet, un miembro Private que no puede alcanzar, un nombre de una hoja de ajustes que ya no coincide con el objeto. Cada uno aflora como el mismo error 438, difícil de ubicar.

ExcelMaster le permite describir la intención —«asigna estas propiedades a este control a partir de una tabla y avísame si un nombre no encaja»— y escribe el bucle de CallByName con los tipos de llamada correctos y una protección de errores ya en su sitio. Usted se queda con el libro y con el código, y se ahorra la cacería del 438.

Preguntas frecuentes

¿Qué hace CallByName en VBA?

Obtiene una propiedad, asigna una propiedad o ejecuta un método sobre un objeto usando el nombre del miembro como una cadena en lugar de código escrito a mano. La sintaxis es CallByName(object, "MemberName", callType, args), donde callType es VbGet, VbLet, VbSet o VbMethod. Úselo cuando el nombre del miembro se decide en tiempo de ejecución; cuando lo conoce al escribir el código, object.Member es más claro.

¿Cuál es la diferencia entre VbGet, VbLet, VbSet y VbMethod?

VbGet lee una propiedad y devuelve su valor. VbLet escribe una propiedad de valor simple (número, cadena, booleano). VbSet escribe una propiedad de objeto, reflejando el Set de VBA. VbMethod ejecuta un método. Elegir el equivocado es la causa habitual del error 438, porque el objeto admite el miembro pero no de la forma en que usted lo pidió.

¿Por qué CallByName provoca el error 438?

Porque el miembro que nombró no puede accederse de la manera en que lo pidió: el nombre está mal escrito, el miembro es Private (CallByName solo alcanza miembros Public), o el tipo de llamada es incorrecto —por ejemplo, un VbMethod sobre una propiedad—. Como el nombre es una cadena, VBA no puede detectarlo hasta que la línea se ejecuta. Revise el tipo de llamada y la visibilidad del miembro.

¿Puede CallByName llamar a un método privado?

No. CallByName solo alcanza miembros Public. Una propiedad o un método Private en un módulo de clase provoca el error 438, el mismo error que obtiene de un nombre mal escrito, así que puede resultar confuso de diagnosticar. Haga Public el miembro si necesita alcanzarlo por su nombre.

¿Cuándo debo usar CallByName en lugar de object.Member?

Solo cuando el nombre del miembro es dinámico: viene de una tabla, una hoja de configuración o un bucle sobre nombres de propiedad. Si conoce el miembro mientras escribe el código, use object.Member: es más claro y el compilador detecta los errores de escritura. Para ejecutar una macro independiente por su nombre, use Application.Run en su lugar.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación 27/09/2026.

Guías relacionadas: VBA Application.Run · VBA Evaluate · VBA Class Module · VBA With · VBA On Error · VBA CreateObject · VBA Dictionary