Ocultar tablas en Access remoto – DB_HIDDENOBJECT y SetHiddenAttribute

Ocultar tablas

El otro día llegó a mis manos unas base de datos Access con las tablas ocultas y recordé una función que colgó el Búho en su día para ocultar y volver a mostrar tablas:

'Por el Buho

Function OcultaDesoculta(Ocultar As Boolean)
   Dim Tablas As TableDef
   For Each Tablas In CurrentDb.TableDefs
      If Ocultar = True Then
         If Not (Tablas.Attributes And DB_HIDDENOBJECT) Then
            Tablas.Attributes = Tablas.Attributes + DB_HIDDENOBJECT
         End If
      Else
         If (Tablas.Attributes And DB_HIDDENOBJECT) Then
            Tablas.Attributes = Tablas.Attributes - DB_HIDDENOBJECT
         End If
      End If
   Next
End Function

'Y llama a esta funcion con el parametro False/TRUE, es decir
'***********************
' OcultaDesoculta False
'***********************

'y no se verán las tablas de la base de datos ni de coña

Así que decidí probar el código ya que recordaba que en algún sitio había leído que nunca se utilizara (no hay mayor motivo que este para trastear) ya que al compactar la base de datos, la tabla era eliminada. Parece ser que había un bug en algunas versiones de Access que hacía que la tabla se marcara como temporal, procediendo a su borrado al compactar. Pero como se suponía que estaba arreglado, decidí probarlo tal cual.

En principio todo funcionaba correctamente, pasando TRUE a la función, las tablas se ocultaban y pasando FALSE, se volvían a mostrar. Entonces pasó algo muy curioso, al intentar cerrar la base de datos me apareció el siguiente cuadro de dialogo:

No se puede actualizar. Base de datos u objeto de sólo lectura

No se puede actualizar. Base de datos u objeto de sólo lectura

Y entonces se me encendió la luz…

¡Las tablas de sistema!

Pues sí, al recorrer todo el tabledef, también modificas las tablas de sistema y esto hace que después nuestra base de datos quede inservible. He intentado volver a modificar las tablas de sistema, pero inspeccionando las modificaciones (me he cargado 3 bases de datos) veo que no actúa como con el resto de tablas y no puedo volver a dejarlas igual.

El siguiente paso, lógicamente era intentar que sólo se modificaran las tablas que no son de sistema, comprobando antes de realizar las modificaciones. Así que volví a escribir el código (cambio las variables porque así me aclaro mejor):

Function ocultarTablas(ByVal Oculta As Boolean)

On Error GoTo mal

   Dim TablaDef As TableDef
   For Each TablaDef In CurrentDb.TableDefs
  If Left(TablaDef.name, 4) <> "MSys" Then
      If Oculta = True Then
         If Not (TablaDef.Attributes And DB_HIDDENOBJECT) Then

                TablaDef.Attributes = TablaDef.Attributes Or DB_HIDDENOBJECT

         End If
      Else
         If (TablaDef.Attributes And DB_HIDDENOBJECT) Then

                TablaDef.Attributes = TablaDef.Attributes - DB_HIDDENOBJECT

         End If
      End If
   End If
   Next

Exit Function
mal:
MsgBox ("Error al ocultar tablas"), vbCritical, "Error"
End Function

Es la misma función sólo que cuando la tabla es de sistema no la toca (además en vez de sumar he puesto un operador lógico «or», que viene a ser lo mismo para bits).

-¿Funciona?
-Sí.
-Pues nada, artículo terminado.
-Ya, pero me da miedo, me he cargado 3 bases de datos. Además, no funciona con tablas vinculadas.
-¿No hay otra forma de hacerlo?
-Vamos a ver…

Entonces empecé a buscar en la web de Microsoft algo relacionado con el tema y encontré los métodos GetHiddenAttribute y SetHiddenAttribute.

Pues nada, vuelvo a construir la función y probamos:

Function ocultarTablas(ByVal Oculta As Boolean)

Dim TablaDef As TableDef

On Error GoTo mal

For Each TablaDef In CurrentDb.TableDefs

    If Application.GetHiddenAttribute(acTable, TablaDef.name) = Not Oculta Then
        Application.SetHiddenAttribute acTable, TablaDef.name, Oculta
    End If

Next

Exit Function
mal:
MsgBox ("Error al ocultar tablas"), vbCritical, "Error"

End Function

Si habéis leído el artículo en profundidad, sabréis que posiblemente con este código tendría una 4ª base de datos inservible (no controlo si es una tabla de sistema), pero esta vez no, esta vez no actuamos a nivel de bits, estamos intentando modificar un atributo de una tabla de sólo lectura y Access nos avisa:

Modificar Tabla de sistema

Modificar Tabla de sistema

Esto me dejaba mucho más tranquilo, así que volviendo a rehacer el código con la comprobación de las tablas de sistema podíamos decir que la función estaba correctamente terminada. Y está vez sí que funcionaba con tablas tanto vinculadas como locales:

Function ocultarTablas(ByVal Oculta As Boolean)

Dim TablaDef As TableDef

On Error GoTo mal

For Each TablaDef In CurrentDb.TableDefs
If Left(TablaDef.name, 4) <> "MSys" Then
    If Application.GetHiddenAttribute(acTable, TablaDef.name) = Not Oculta Then
        Application.SetHiddenAttribute acTable, TablaDef.name, Oculta
    End If

End If
Next

Exit Function
mal:
MsgBox ("Error al ocultar tablas"), vbCritical, "Error"

End Function

-Ahora sí ¿no?, artículo terminado.
-Ya, pero es que… ¿y si quiero modificar una base de datos remota?

Entonces tenemos que modificar un poco (un poco bastante) la función. Empecemos por la llamada, tenemos que pasarle el nombre de la base de datos que queremos modificar (y ya de paso adelantamos y le pasamos la posible contraseña):

Function ocultarTablas(ByVal Oculta As Boolean, ByVal baseDatos As String, ByVal pass As String)

El resto era bastante sencillo, abrir la base de datos remota y recorrer el tabledef. Pero había un problema, los métodos GetHiddenAttribute y SetHiddenAttribute actúan sobre un elemento Application, así que tenía que crearlo (buscando un poco encontré la manera de hacerlo). Así que el código final queda de la siguiente manera (comprobado y funcionando correctamente):

Function ocultarTablas(ByVal Oculta As Boolean, ByVal baseDatos As String, ByVal pass As String)

'*************************************************************************************************************************************
'Autor: Arkaitz Arteaga
'Más artículos: www.programadordepalo.com
'Mail de contacto: admin@programadordepalo.com
'Fecha: Enero 2014
'Version: 1.0
'*************************************************************************************************************************************
    'Función que oculta las tablas de una base de datos que le pasemos (local o remota)
    'Funciona para tablas locales o vinculadas
    'Pasando contraseña funciona para bases de datos encriptadas
    'Utiliza GetHiddenAttribute y SetHiddenAttribute en vez de DB_HIDDENOBJECT (problemas en versiones viejas de Access y posibilidad de dejar inservible la base de datos en la actuales)
    'Probada y ni borra tablas ni deja de sólo lectura
    'Más información www.programadordepalo.com/ocultar-tablas-en-access-remoto-db_hiddenobject-y-sethiddenattribute/
'
'*************************************************************************************************************************************
'*************************************************************************************************************************************
'Copyright: Por favor, no cuesta nada mantener un enlace a mi web en el código.
'Incluso pudes dejar los formularios tal cual, con un enlace a mi web.
'Si vas a utilizar este código con fines lucrativos (es decir, te van a pagar por ello) contacta conmigo por favor.
'*************************************************************************************************************************************

Dim trabajo As DAO.Workspace
Dim base As DAO.Database
Dim TablaDef As TableDef
Dim Aplicacion As Access.Application

On Error GoTo mal

Set trabajo = DBEngine.Workspaces(0)
Set base = trabajo.OpenDatabase(baseDatos, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota

Set Aplicacion = New Access.Application 'Creamos el objeto Application para utilizar los métodos GetHiddenAttribute y SetHiddenAttribute
Aplicacion.OpenCurrentDatabase baseDatos, , pass

For Each TablaDef In base.TableDefs
If Left(TablaDef.name, 4) <> "MSys" Then 'Comprobamos que no sea una tabla de sistema
    If Aplicacion.GetHiddenAttribute(acTable, TablaDef.name) = Not Oculta Then
        Aplicacion.SetHiddenAttribute acTable, TablaDef.name, Oculta
    End If

End If
Next

Aplicacion.RefreshDatabaseWindow 'Actualizamos la ventana por si está abierta
Aplicacion.Quit

Set Aplicacion = Nothing

Exit Function
mal:
MsgBox ("Error al modificar las propiedades. " & Err.Description), vbCritical, "Error al modificar las propiedades"

End Function

En unos días intentaré rehacer la función para ocultar otro tipo de objetos de nuestra base de datos (Módulos de VBA, consultas, etc.). Edito: He incluido en el nuevo Administrador de Aplicaciones Access esta funcionalidad y unas cuántas más.

The following two tabs change content below.
Llevo más de 10 años programando, sobre todo en Visual Basic y con bases de datos Access. Para mí, VBA y Access siguen siendo herramientas muy potentes. He desarrollado varios proyectos con PHP y MySql. Si sumo las webs que he tenido, probablemente pasaría de 100. Ahora prefiero dedicar todo mi esfuerzo a este blog (aunque sigo manteniendo unas cuantas...). Trabajo en la administración pública (si, soy funcionario), pero he trabajado en pequeñas empresas e incluso en una "grande" de las telecomunicaciones. Ultimamente estoy bastante metido en abrirme nuevos horizontes con C# y .NET. Renovarse o morir!

3 Respuestas a Ocultar tablas en Access remoto – DB_HIDDENOBJECT y SetHiddenAttribute

  1. Hola Arkaitz,

    tal como te comenté en el email hace tiempo, el problema del procedimiento SetHiddenAttribute es que, aun a pesar de que la tabla se oculta, el usuario puede seguir consultandola mediante la opcion «Mostrar objetos ocultos».

    Actuando directamente sobre Table.Attributes la tabla nunca se nos mostrará en el navegador pero, efectivamente, no funciona con tablas vinculadas.

    No sabras por casualidad si hay algun modo de evitar al usuario que muestre los objetos ocultos, o alguna otra opcion con la que se pueda resolver el problema?
    Muchas gracias y un saludo

  2. alguien que me ayude! deseo tener en mi programa de access.mdb la opcion de lector de codigo de barra, lo que se utiliza en los supermercados, tengo entendido que ya algunos superexperto los tienen, si alguien colabora con este proyecto, gracias.

    agradecido de antemano.

  3. Alex Muñoz dice:

    Hola Arkaitz, me puedes ayudar porfa con la parte de como llamar esta funcion? estoy tratando con la manera que conozco que es: ocultarTablas true, esto en un boton, pero me sale que el argumento no es opcional. Y te felicito por este excelente block.

Deja una respuesta