none
Función de Access poder pasarla a SQLCompact RRS feed

  • Pregunta

  • Hola a todos:

    Tengo esta función en Access y querría por favor que me funcionase en SQLCompactCE:

    Public Shared Function ExisteTabla(ByVal CadenaConexion As String, ByVal tablename As String) As Boolean 'Comprobamos si existe la tabla a crear en SqlCompact Try Using Cnn As New SqlCeConnection(Configuracion.CadenaConexion) Cnn.Open() Dim dt As DataTable = Cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, New Object() _ {Nothing, Nothing, Nothing, "TABLE"}) Dim criterio As String = String.Format("TABLE_NAME = '{0}'", tablename) Dim rows() As DataRow = dt.Select(criterio) Return (rows.Length > 0) End Using Catch ex As Exception Throw End Try End Function

    Y esta conversión también si puede ser como quedaría.
    
     cmd.Parameters.Add("", OleDbType.double).Value = row.Item("Ejer_01")
    
    
    
    

    La parte en negrita es la que no se que se tiene que poner en SqlCOmpact.

    Un cordial saludo a todos y gracias.

    Gemma

    jueves, 23 de julio de 2015 13:26

Respuestas

  • Hola, Gemma:

    En lugar de obtener el objeto DataTable ejecutando

        Dim dt As DataTable = Cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, New Object() _
                              {Nothing, Nothing, Nothing, "TABLE"})

    Hazlo ejecutando el método GetSchema del objeto SqlCeConnection:

        Dim dt As DataTable = cnn.GetSchema("TABLES")

    Ahora lo que hace falta es que estés utilizando la versión 4.0 de SQL Server Compact, porque el método GetSchema indicado de las versiones inferiores a la 4.0 no es compatible. ;-)

    > Y esta conversión también si puede ser como quedaría.
    >
    > cmd.Parameters.Add("", OleDbType.double).Value = row.Item("Ejer_01")

    Siempre que estemos hablando que la variable cmd es del tipo SQLCeCommand, puedes especificar el tipo de dato del parámetro de ésta manera:

    cmd.Parameters.Add("", SqlDbType.Float).Value = row.Item("Ejer_01")


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    jueves, 23 de julio de 2015 14:25
    Moderador
  • Aquí te dejo el proceso para eliminar la contraseña de la base de datos de Access, realizar la compactación, y proteger la nueva base de datos de Access 2007.

    Imports System.Data.OleDb
    Imports System.Reflection
    
    ''' <summary>
    ''' Módulo para la compactación de bases de datos
    ''' Microsoft Access mediante reflexión.
    ''' </summary>
    ''' <author>Enrique Martínez Montejo - 2010</author>
    ''' <remarks></remarks>
    Friend Module AccessDatabase
    
        ''' <summary>
        ''' Enumeración para la versión de la base de datos Microsoft Access.
        ''' </summary>
        ''' <remarks></remarks>
        <System.CLSCompliant(True), System.Flags()> _
        Public Enum AccessDatabaseTypeEnum
            ''' <summary>
            ''' Descifra la base de datos mientras se compacta.
            ''' </summary>
            dbDecrypt = 4
            ''' <summary>
            ''' Cifra la base de datos.
            ''' </summary>
            dbEncrypt = 2
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 1.0.
            ''' </summary>
            dbVersion10 = 1
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 1.1.
            ''' </summary>
            dbVersion11 = 8
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 12.0 (Access 2007).
            ''' </summary>
            dbVersion120 = &H80
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 14.0 (Access 2010).
            ''' </summary>
            dbVersion140 = &H100
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 15.0 (Access 2013).
            ''' </summary>
            dbVersion150 = &H200
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 2.0.
            ''' </summary>
            dbVersion20 = &H10
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 3.0 (Access 95-97).
            ''' </summary>
            dbVersion30 = &H20
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 4.0 (Access 2000-2003).
            ''' </summary>
            dbVersion40 = &H40
        End Enum
    
        ''' <summary>
        ''' Compacta una base de datos Microsoft Accesss.
        ''' </summary>
        ''' <param name="source">Base de datos que se desea compactar.</param>
        ''' <param name="pwdSource">Contraseña de la base de datos de origen.</param>
        ''' <param name="destiny">Base de datos de destino de la compactación.</param>
        ''' <param name="version">Versión de la base de datos compactada.</param>
        ''' <remarks></remarks>
        Friend Sub CompactDataBase(source As String, _
                                   pwdSource As String, _
                                   destiny As String, _
                                   version As AccessDatabaseTypeEnum)
    
            ' 1º) Abrir la base de datos de origen para eliminar su contraseña.
            ' Para modificar la contraseña de la base de datos, ésta hay que
            ' abrirla de manera exclusiva.
            '
            Dim connString As String = String.Format( _
                "Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;" & _
                "Data Source={0};Jet OLEDB:Database Password={1}", source, pwdSource)
    
            Using cnn As New OleDbConnection(connString)
    
                Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                ' Construimos la consulta SQL para cambiar la contraseña
                cmd.CommandText = String.Format("ALTER DATABASE PASSWORD {0} {1}", "NULL", pwdSource)
    
                cnn.Open()
    
                cmd.ExecuteNonQuery()
    
            End Using
    
            ' 2º) Compactar la base de datos sin ninguna contraseña.
            '
            CompactDataBase(source, destiny, version)
    
            ' 3º) Proteger la nueva base de datos resultante de la compactación.
            '
            connString = String.Format( _
                "Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;" & _
                "Data Source={0};Jet OLEDB:Database Password={1}", destiny, pwdSource)
    
            Using cnn As New OleDbConnection(connString)
    
                Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                ' Construimos la consulta SQL para cambiar la contraseña
                cmd.CommandText = String.Format("ALTER DATABASE PASSWORD {0} {1}", pwdSource, "NULL")
    
                cnn.Open()
    
                cmd.ExecuteNonQuery()
    
            End Using
    
        End Sub
    
        ''' <summary>
        ''' Compacta una base de datos Microsoft Accesss que no se encuentre protegida.
        ''' </summary>
        ''' <param name="source">Base de datos que se desea compactar.</param>
        ''' <param name="destiny">Base de datos de destino de la compactación.</param>
        ''' <param name="version">Versión de la base de datos compactada.</param>
        ''' <remarks></remarks>
        Private Sub CompactDataBase(source As String, _
                                    destiny As String, _
                                    version As AccessDatabaseTypeEnum)
    
            Dim dbe As Object = Nothing
    
            Try
                ' Creo mediante reflexión un objeto DAO.DBEngine mediante su ProgId.
                '
                Dim ty As System.Type = Nothing
                dbe = CreateObject("DAO.DBEngine.120", ty)
    
                If (dbe Is Nothing) Then _
                    Throw New Runtime.InteropServices.COMException( _
                    "No se encuentra instalado el motor de bases de datos Microsoft ACE.")
    
                ' Obtengo un nombre de un archivo temporal que será el
                ' que albergará la base de datos compactada.
                '
                Dim tempFile As String = IO.Path.GetTempFileName()
    
                ' Elimino el archivo temporal.
                '
                IO.File.Delete(tempFile)
    
                Dim locale As String = ";LANGID=0x0409;CP=1252;COUNTRY=0"
                
                ' Compactamos la base de datos.
                '
                Dim args() As Object = {source, tempFile, locale, version}
    
                Dim o As Object = ExecuteMethod(dbe, ty, "CompactDatabase", args)
    
                ' Si no se ha creado el archivo temporal, es porque
                ' la base de datos no se ha compactado.
                '
                If (Not IO.File.Exists(tempFile)) Then _
                    Throw New Runtime.InteropServices.COMException( _
                    "No se ha podido compactar la base de datos.")
    
                ' La base de datos se ha compactado satisfactoriamente.
                '
                ' Cuando se llame a éste método, se comprende que se desea
                ' sobrescribir un archivo existente. Compruebo si existe
                ' la base de datos de destino.
                '
                If (IO.File.Exists(destiny)) Then
                    ' Elimino el archivo
                    IO.File.Delete(destiny)
                End If
    
                ' Mueve el archivo temporal a la carpeta de destino.
                '
                IO.File.Move(tempFile, destiny)
    
            Finally
                ' Disminuimos el contador de referencias y liberamos
                ' la referencia al objeto.
                Runtime.InteropServices.Marshal.FinalReleaseComObject(dbe)
                dbe = Nothing
    
            End Try
    
        End Sub
    
        ''' <summary>
        ''' Crea y devuelve una referencia al objeto COM especificado.
        ''' </summary>
        ''' <param name="progId">Nombre correspondiente al ProgId del objeto COM que se desea obtener.</param>
        ''' <param name="ty">Se devolverá el tipo asociado al identificador de programa especificado.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function CreateObject(progId As String, ByRef ty As System.Type) As Object
    
            ' Obtenemos el tipo asociado al identificador de programa
            ' (ProgID) especificado.
            '
            ty = Type.GetTypeFromProgID(progId)
    
            If (ty Is Nothing) Then Return Nothing
    
            ' Creamos la instancia del tipo de objeto especificado.
            '
            Return Activator.CreateInstance(ty)
    
        End Function
    
        ''' <summary>
        ''' Ejecuta el método del objeto COM especificado.
        ''' </summary>
        ''' <param name="app">Instancia del objeto COM cuya método se desea ejecutar.</param>
        ''' <param name="ty">El tipo asociado al programa especificado.</param>
        ''' <param name="methodName">Nombre del método que se desea ejecutar.</param>
        ''' <param name="args">Matriz que contiene los argumentos que se van
        ''' a pasar al método que se desea ejecutar.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function ExecuteMethod(app As Object, _
                                       ty As System.Type, _
                                       methodName As String, _
                                       args() As Object) As Object
    
            If ((app Is Nothing) OrElse _
                (ty Is Nothing)) Then Return Nothing
    
            ' Ejecuto el método especificado.
            '
            Return ty.InvokeMember( _
               methodName, _
               BindingFlags.DeclaredOnly Or BindingFlags.Public Or _
               BindingFlags.NonPublic Or BindingFlags.Instance Or _
               BindingFlags.IgnoreCase Or BindingFlags.InvokeMethod, _
               Nothing, _
               app, _
               args)
    
        End Function
    
    End Module

    Fíjate que el método CompactDataBase antiguo se ha reducido considerablemente, ya que ahora se encargará de compactar una base de datos que no se encuentre protegida. No son necesarias ni las notas de advertencia que tenía escritas. Ahora, éste procedimiento será privado. ;-)

    Obviamente, he tenido que sobrecargar el método CompactDataBase para eliminar la contraseña de la base de datos de Access 2003, compactar la base para crear una nueva base de datos de Access 2007, y por último, proteger la nueva base de datos creada.

    Para realizar todo el proceso, tan solo tienes que ejecutar lo siguiente:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                AccessDatabase.CompactDataBase("C:\Mis documentos\Access2003.mdb", "contraseña", "C:\Mis documentos\Access2007.accdb", AccessDatabaseTypeEnum.dbVersion120)
    
                MessageBox.Show("Se ha compactado satisfactoriamente la base de datos.")
    
                ' Si procede, eliminar aquí el archivo de la
                ' base de Access 2003.
                '
                IO.File.Delete("C:\Mis documentos\Access2003.mdb")
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    Te advierto que tras finalizar el proceso, la base de datos de Access 2003 estará desprotegida, de ahí que haya incluido el código para eliminar físicamente el archivo *.mdb.

    En fin, haz una prueba para ver si la nueva base de datos de Access 2007 protegida la puedes abrir si ningún tipo de problema.


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo jueves, 23 de julio de 2015 18:53
    jueves, 23 de julio de 2015 18:25
    Moderador

Todas las respuestas

  • Hola, Gemma:

    En lugar de obtener el objeto DataTable ejecutando

        Dim dt As DataTable = Cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, New Object() _
                              {Nothing, Nothing, Nothing, "TABLE"})

    Hazlo ejecutando el método GetSchema del objeto SqlCeConnection:

        Dim dt As DataTable = cnn.GetSchema("TABLES")

    Ahora lo que hace falta es que estés utilizando la versión 4.0 de SQL Server Compact, porque el método GetSchema indicado de las versiones inferiores a la 4.0 no es compatible. ;-)

    > Y esta conversión también si puede ser como quedaría.
    >
    > cmd.Parameters.Add("", OleDbType.double).Value = row.Item("Ejer_01")

    Siempre que estemos hablando que la variable cmd es del tipo SQLCeCommand, puedes especificar el tipo de dato del parámetro de ésta manera:

    cmd.Parameters.Add("", SqlDbType.Float).Value = row.Item("Ejer_01")


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    jueves, 23 de julio de 2015 14:25
    Moderador
  • Hola maestro, buenas tardes:

    Siempre estás ahí para ayudarme. Mira, la versión es la 4.0 o sea que todo perfecto. Enrique, al final te prometo que me está dando muchos problemas el Access 2007 con la "extensión al 2010", me falla en las contraseñas, no la puedo compactar, etc. y he decidido meterme el sql a través del compact que ya me servirá también cuando si Dios quiere pueda trabajar en la web con el programa. He tardado como media hora en convertir todo el código a sqlcompact, nada mas estoy tardando en que tenías "procesos almacenados" en el Access y el compact no los tiene, aprovcho los mismos y he creado las selects del todas las fórmulas a través de ellos, nos los he borrqado, los he tildado, porque si algún día vamos a parar a sql server ya los tendré hechos, retocando alguna cosilla.

    Bueno maestro, te he querido explicar un poco la situación porque si todo va bien, la semana que viene saco el programa después de dos años y muchísimas horas.

    Evidentemente no hubiera llegado al final y lo hubiera mandado a tomar leches porque en algunos momentos me ha roto las meninges, pero que pasa, pues que sale de no se donde el cascarrabias, me gira la tortilla y me hace ver que todo tiene solución.

    Bueno querido amigo siempre, te avisaré y si a mal no lo consideras, me gustaría remitirte una copia de dicho software, no se si ha ti te hará ilusión, pero a mi sí.

    Bueno, ya hablaremos.

    Un gran abrazo como siempre maestro.

    Gemma

    jueves, 23 de julio de 2015 14:43
  • "gemma_campillo" escribió:

    > Enrique, al final te prometo que me está dando muchos problemas el Access 2007
    > con la "extensión al 2010", me falla en las contraseñas, no la puedo compactar, etc

    El motivo de ello ya te lo expliqué el otro día, y se debe a que el método de cifrado de Access 2007 y Access 2010 o superior es incompatible.

    Mientras que utilices el motor de datos de Access 2007, no vas a tener ningún problema. Pero si has protegido una base de datos cualquiera de Access mediante los objetos de Access 2010 o superior, no vas a poder abrirla con los objetos de Acces 2007.

    Entiendo que tendrías que abrir las Opciones de Access 2010 o superior y modificar el método de cifrado predeterminado para proporcionar compatibilidad inversa, tal y como muestra la siguiente captura de las Opciones de Access 2013:

    Échale un vistazo al apartado Usar una contraseña de base de datos para cifrar una base de datos de Access que aparece en el siguiente artículo:

    Introducción a la seguridad de Access 2010

    > Bueno querido amigo siempre, te avisaré y si a mal no lo consideras,
    > me gustaría remitirte una copia de dicho software, no se si ha ti
    > te hará ilusión, pero a mi sí.

    ¡Por supuesto que me hace mucha ilusión! Aunque yo no vaya a trabajar con tu aplicación ya que me dedico a otros menesteres, sí me gustaría ver el resultado final, por si le tengo que poner algún que otro "pero". ¡Jejeje!


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    jueves, 23 de julio de 2015 15:06
    Moderador
  • Hola Enrique:

    Voy a mirarme lo que me dices pero me ha dado muchos problemas. Entiendo lo que me explicas pero me da miedo no saber resolver ante el usuario un problema de contraseñas, apertura de la base, cualquier cosa. Voy a mirármelo bien otra vez y evidentemente muchas gracias otra vez. Te pido por favor tu correo para cuando este esto y como me imagino que no quieres que sea público me lo puede enviar a: gemmaARROBAmanagerialanalyzer.com

    Un abrazo maestro.

    Gemma

    jueves, 23 de julio de 2015 15:13
  • "gemma_campillo" escribió:

    > Entiendo lo que me explicas pero me da miedo no saber resolver ante
    > el usuario un problema de contraseñas, apertura de la base, cualquier cosa
    >

    ¡Vamos a ver! ¿Qué sucedería si NO PROTEGES tu base de datos de Access? ¿Podría ser sumamente perjudicial para tu aplicación?

    El motivo de migrar a SQL Server Compact, ¿es por el tema de la contraseña de la base de datos de Access? ¿Te has parado a sopesar detenidamente los pros y los contras que tal operación conlleva?

    Me has comentado anteriormente que ya tienes lista tu aplicación para distribuirla, y ¿ya te ha dado tiempo de depurar todo para ver cómo se comporta con SQL Server Compact?


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    jueves, 23 de julio de 2015 15:32
    Moderador
  • Enrique:

    Ya lo puedes borrar.

    La base de datos de Access lleva dentro los planes contables, parámetros con los que se puede cambiar los tipos de versiones, las claves de activación que esas las voy a encriptar como la de usuarios. El gran problema lo tengo con una tabla de 5 campos que es la que lleva el tipo de aplicación, si es demo o no, el tipo de versión, es decir esos campos son importantes. Evidentemente que puedo dejarla abierta, pero también me parece poco profesional el que cualquier persona pueda acceder a ella. Tengo las 2 soluciones por separado, la de Access que es la "buena" y la ora con SQLCompact que estoy probando hoy, ya que mañana empiezo a hacer la ayuda del programa. En fin los motivos aparentemente tiene solución pero tyo personalmente no veo del todo correcto que cualquiera fisgonee donde no tiene que hacerlo.

    Un abrazo maestro.

    Gemma

    jueves, 23 de julio de 2015 15:41
  • Enrique, una duda.

    Si la base de datos fuese Access 2010 o 2013, continuarían existiendo esos posibles problemas no?.

    Un abrazo.

    Gemma

    jueves, 23 de julio de 2015 15:44
  • Está claro que por el contenido de la base de datos ésta no puede estar "abierta a todo el mundo", mayormente por el tema de tipos de versiones, claves de activación, tipo de aplicación, y otras que tengan que ver con la gestión propia de tu aplicación.

    A mi manera de ver estas cuestiones, todo esto tendría que estar en otra base de datos diferente a aquella que contiene los datos del usuario (planes contables y cualquier otros datos exclusivos del usuario de tu aplicación).

    Y ¿cómo has protegido la contraseña de la base de datos en la cadena de conexión? Cierta vez alguien del foro te comentó que utilizaras un método de encriptación del que yo no estaba muy de acuerdo que digamos con el mismo, porque puede suceder que tú creas que tienes segura tu base de datos cuando "el menos pintado" puede ser capaz de descubrir la contraseña. ;-)

    > Si la base de datos fuese Access 2010 o 2013, continuarían existiendo
    > esos posibles problemas no?.

    Si la base de datos con extensión *.accdb utiliza el cifrado de Access 2010 o 2013, entiendo que no tendrías el problema de compatiblidad que estás teniendo ahora cuando cifras una base de datos con los objetos de Access 2010 y deseas abrirla con los objetos de Access 2007. Podrías requerir como requisito de tu aplicación que el cliente tenga instalado los objetos de Access 2010 o superior.

    Ahora bien, si el día de mañana Microsoft saca al mercado Access XXXX y modifica el método de cifrado para hacerlo incompatible con Access 2010-2013, pues entonces estarías en las mismas condiciones que te encuentras ahora. ;-)

    Creo recordar que el problema estaba a la hora de migrar la base de datos de Access 2003 a 2007 o superior. En lugar de compactar y proteger la base de datos a la misma vez, estudia las posibilidades que tienes de compactar sin contraseña y posteriormente asignársela a la base de datos resultante de la compactación.

    He movido los mensajes porque me he equivocado de conversación al responder anteriormente. :-(


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    jueves, 23 de julio de 2015 16:06
    Moderador
  • Hola Enrique:

    Si, la solución que no me acuerdo si la comentamos el otro día, es la de cuando el usuario me envíe la base de datos 2003 para convertirla, exactamente le quito la contraseña, compacto y convierto con tu código a Access 2007?. Este interrogante es porque voy a mirar esta tarde-noche de probar con un Access 2010 ya que según lo que me explicas, entiendo que quizás ya no tendríamos problemas. Pero bueno, no es tampoco un problemón.

    Si funcionase lo que pasa es que el propio usuario puede hacer la conversión en su propio ordenador.

    Respecto a la contraseña encriptada no te puedo explicar mucho porque me la ha hecho un amigo que conozco hace muchos años, lo que pasa es que tenemos poco contacto.

    Queda así.

    App.config

     <connectionStrings>
        <add name="MiCadenaConexion" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source = C:\Users\Gemma\Documents\Visual Studio 2010\Projects\FinancialSystems\gemmafin.accdb"
          providerName="System.Data.OleDb" />
      </connectionStrings>

    Llamada desde la clase, aquí esta la encriptación:

    Public Class Configuracion
    
        Public Shared Function CadenaConexion() As String
            Try
    
                Dim cnx As String = ConfigurationManager.ConnectionStrings("MiCadenaConexion").ConnectionString
                Return cnx & System.Text.Encoding.Default.GetString(System.Convert.FromBase64String("O0pldCBPTEV...semRsa2xncw=="))
            Catch exc As Exception
                Throw exc
            End Try
        End Function
    
    
    End Class

    Eso es todo. Funciona perfectamente.

    Un saludo.

    Gemma


    jueves, 23 de julio de 2015 16:26
  • "gemma_campillo" escribió:

    > Respecto a la contraseña encriptada no te puedo explicar mucho porque me
    > la ha hecho un amigo que conozco hace muchos años, lo que pasa es que
    > tenemos poco contacto.
    >
    >   Return cnx & Encoding.Default.GetString(Convert.FromBase64String("O0pldCBPTEV...semRsa2xncw=="))
    >
    > Eso es todo. Funciona perfectamente.

    Funcionar puede que funcione perfectamente, pero de seguridad tiene lo que yo tengo de ...

    Fíjate la seguridad que tiene que cuando lo he visto, inmediatamente he modificado tu mensaje para recortar el valor de la cadena en base 64 que lee el método FromBase64String, vaya a ser que sea de vox populi la contraseña de tu base de datos. Espero que no te haya molestado.

    La contraseña tiene 8 caracteres, comenzando con la letra 'l' y terminando con la letra 's'. ;-)

    Siento desilusionarte, pero ese "método de encriptación" (por llamarlo de alguna manera) y no tener nada, es lo mismo.


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    jueves, 23 de julio de 2015 16:44
    Moderador
  • Bueno maestro:

    Si ya dijistes que le pongas lo que le pongas te la pueden abrir, si en google corren programillas que te abren las bases, pero por lo menos el usuario no tiene fácil acceso a abrirla que es de lo que se trata, ya que adentro de ella los datos más, más importantes van encriptados.

    Y efectivamente maestro listo la contraseña empieza por l y acaba en s, jajajaja. Eres la leche, de verdad.

    Venga un fuerte abrazo y ves a la playa y no trabajes tanto que te lo mereces.

    Un fuertísimo abrazo, ah, y te comentaré lo del Access 2010 a ver si no a problemas.

    Gemma

    jueves, 23 de julio de 2015 16:51
  • "gemma_campillo" escribió:

    > ... pero por lo menos el usuario no tiene fácil acceso a abrirla que
    > es de lo que se trata, ...

    Cualquier persona que quiera hacer daño, lo va a hacer. Tan solo tiene que abrir el ejecutable de tu aplicación con cualquier programa descompilador existente, y buscar el método de obtención de la cadena de conexión. Cuando encuentre algún procedimiento del tipo

        Public Shared Function CadenaConexion() As String

    dirá ¡Bingo! ¡Ya tengo la contraseña de la base de datos!

    Con copiar/pegar el método y ejecutarlo en un programa de prueba de Visual Studio Express, obtendrá la contraseña tan fácil como la he conseguido yo.

    > ... ya que adentro de ella los datos más importantes van encriptados.

    Eso espero. Que estén mejor encriptados que la contraseña de la base de datos. ;-)


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    jueves, 23 de julio de 2015 17:00
    Moderador
  • Mira, este es el codigo para encryptar el password del login. Si has de borrar algo bórralo por favor.,

    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    
    Imports System.Security.Cryptography
    
    
    Friend Class Helper
    
        Public Shared Function EncodePassword(ByVal originalPassword As String) As String
    
            Dim sha1 As SHA1 = New SHA1CryptoServiceProvider()
    
            Dim inputBytes As Byte() = (New UnicodeEncoding()).GetBytes(originalPassword)
            Dim hash As Byte() = sha1.ComputeHash(inputBytes)
    
            Return Convert.ToBase64String(hash)
    
        End Function
    
    End Class

    jueves, 23 de julio de 2015 17:04
  • "gemma_campillo" escribió:

    > Mira, este es el codigo para encryptar el password del login.
    > Si has de borrar algo bórralo por favor.,
    >
    >     Dim hash As Byte() = sha1.ComputeHash(inputBytes)
    >     Return Convert.ToBase64String(hash)

    A eso no se le puede llamar "encriptar", al menos no técnicamente hablando. Eso es la manera de obtener una cadena en base 64 del resumen hash de un valor dado, que precisamente esta mañana le he proporcionado a un usuario del foro una función parecida pero con un algoritmo de hash más fuerte que el SHA1.

    https://social.msdn.microsoft.com/Forums/es-ES/cf664e9a-a9ec-4daa-a088-2d91eb766a3e/contrasea-cifrada?forum=vbes

    Para encriptar/desencriptar mediante un algoritmo simétrico (AES, Rijndael), tiene que existir una clave privada (una matriz de bytes que cuanto mayor sea su longitud, más difícil de averiguar será), clave que puede derivarse del texto plano de una contraseña cualquiera, y un vector de inicialización que será el encargado de realizar las transformaciones criptográficas de los datos. La pregunta sería, ¿dónde almacenas de una manera segura tanto la contraseña, para derivar ésta y obtener la clave privada del algoritmo simétrico, como el vector de inicialización?

    El tema de la encriptación con clave privada es más complicado que lo que te puedas imaginar en estos momentos, y requiere bastante experiencia y soltura. Si estás interesada en el tema, aquí tienes algunos artículos para "abrir boca". ;-)

    Servicios criptográficos

    Tareas criptográficas

    Tutorial: Crear una aplicación criptográfica

    Modelo de criptografía de .NET Framework


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    jueves, 23 de julio de 2015 17:31
    Moderador
  • Gracias Enrique:

    Miraré todos esos ejemplos.

    Un abrazo.

    Gemma

    jueves, 23 de julio de 2015 17:48
  • Aquí te dejo el proceso para eliminar la contraseña de la base de datos de Access, realizar la compactación, y proteger la nueva base de datos de Access 2007.

    Imports System.Data.OleDb
    Imports System.Reflection
    
    ''' <summary>
    ''' Módulo para la compactación de bases de datos
    ''' Microsoft Access mediante reflexión.
    ''' </summary>
    ''' <author>Enrique Martínez Montejo - 2010</author>
    ''' <remarks></remarks>
    Friend Module AccessDatabase
    
        ''' <summary>
        ''' Enumeración para la versión de la base de datos Microsoft Access.
        ''' </summary>
        ''' <remarks></remarks>
        <System.CLSCompliant(True), System.Flags()> _
        Public Enum AccessDatabaseTypeEnum
            ''' <summary>
            ''' Descifra la base de datos mientras se compacta.
            ''' </summary>
            dbDecrypt = 4
            ''' <summary>
            ''' Cifra la base de datos.
            ''' </summary>
            dbEncrypt = 2
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 1.0.
            ''' </summary>
            dbVersion10 = 1
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 1.1.
            ''' </summary>
            dbVersion11 = 8
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 12.0 (Access 2007).
            ''' </summary>
            dbVersion120 = &H80
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 14.0 (Access 2010).
            ''' </summary>
            dbVersion140 = &H100
            ''' <summary>
            ''' Motor de base de datos Microsoft Access 15.0 (Access 2013).
            ''' </summary>
            dbVersion150 = &H200
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 2.0.
            ''' </summary>
            dbVersion20 = &H10
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 3.0 (Access 95-97).
            ''' </summary>
            dbVersion30 = &H20
            ''' <summary>
            ''' Motor de base de datos Microsoft Jet versión 4.0 (Access 2000-2003).
            ''' </summary>
            dbVersion40 = &H40
        End Enum
    
        ''' <summary>
        ''' Compacta una base de datos Microsoft Accesss.
        ''' </summary>
        ''' <param name="source">Base de datos que se desea compactar.</param>
        ''' <param name="pwdSource">Contraseña de la base de datos de origen.</param>
        ''' <param name="destiny">Base de datos de destino de la compactación.</param>
        ''' <param name="version">Versión de la base de datos compactada.</param>
        ''' <remarks></remarks>
        Friend Sub CompactDataBase(source As String, _
                                   pwdSource As String, _
                                   destiny As String, _
                                   version As AccessDatabaseTypeEnum)
    
            ' 1º) Abrir la base de datos de origen para eliminar su contraseña.
            ' Para modificar la contraseña de la base de datos, ésta hay que
            ' abrirla de manera exclusiva.
            '
            Dim connString As String = String.Format( _
                "Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;" & _
                "Data Source={0};Jet OLEDB:Database Password={1}", source, pwdSource)
    
            Using cnn As New OleDbConnection(connString)
    
                Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                ' Construimos la consulta SQL para cambiar la contraseña
                cmd.CommandText = String.Format("ALTER DATABASE PASSWORD {0} {1}", "NULL", pwdSource)
    
                cnn.Open()
    
                cmd.ExecuteNonQuery()
    
            End Using
    
            ' 2º) Compactar la base de datos sin ninguna contraseña.
            '
            CompactDataBase(source, destiny, version)
    
            ' 3º) Proteger la nueva base de datos resultante de la compactación.
            '
            connString = String.Format( _
                "Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;" & _
                "Data Source={0};Jet OLEDB:Database Password={1}", destiny, pwdSource)
    
            Using cnn As New OleDbConnection(connString)
    
                Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                ' Construimos la consulta SQL para cambiar la contraseña
                cmd.CommandText = String.Format("ALTER DATABASE PASSWORD {0} {1}", pwdSource, "NULL")
    
                cnn.Open()
    
                cmd.ExecuteNonQuery()
    
            End Using
    
        End Sub
    
        ''' <summary>
        ''' Compacta una base de datos Microsoft Accesss que no se encuentre protegida.
        ''' </summary>
        ''' <param name="source">Base de datos que se desea compactar.</param>
        ''' <param name="destiny">Base de datos de destino de la compactación.</param>
        ''' <param name="version">Versión de la base de datos compactada.</param>
        ''' <remarks></remarks>
        Private Sub CompactDataBase(source As String, _
                                    destiny As String, _
                                    version As AccessDatabaseTypeEnum)
    
            Dim dbe As Object = Nothing
    
            Try
                ' Creo mediante reflexión un objeto DAO.DBEngine mediante su ProgId.
                '
                Dim ty As System.Type = Nothing
                dbe = CreateObject("DAO.DBEngine.120", ty)
    
                If (dbe Is Nothing) Then _
                    Throw New Runtime.InteropServices.COMException( _
                    "No se encuentra instalado el motor de bases de datos Microsoft ACE.")
    
                ' Obtengo un nombre de un archivo temporal que será el
                ' que albergará la base de datos compactada.
                '
                Dim tempFile As String = IO.Path.GetTempFileName()
    
                ' Elimino el archivo temporal.
                '
                IO.File.Delete(tempFile)
    
                Dim locale As String = ";LANGID=0x0409;CP=1252;COUNTRY=0"
                
                ' Compactamos la base de datos.
                '
                Dim args() As Object = {source, tempFile, locale, version}
    
                Dim o As Object = ExecuteMethod(dbe, ty, "CompactDatabase", args)
    
                ' Si no se ha creado el archivo temporal, es porque
                ' la base de datos no se ha compactado.
                '
                If (Not IO.File.Exists(tempFile)) Then _
                    Throw New Runtime.InteropServices.COMException( _
                    "No se ha podido compactar la base de datos.")
    
                ' La base de datos se ha compactado satisfactoriamente.
                '
                ' Cuando se llame a éste método, se comprende que se desea
                ' sobrescribir un archivo existente. Compruebo si existe
                ' la base de datos de destino.
                '
                If (IO.File.Exists(destiny)) Then
                    ' Elimino el archivo
                    IO.File.Delete(destiny)
                End If
    
                ' Mueve el archivo temporal a la carpeta de destino.
                '
                IO.File.Move(tempFile, destiny)
    
            Finally
                ' Disminuimos el contador de referencias y liberamos
                ' la referencia al objeto.
                Runtime.InteropServices.Marshal.FinalReleaseComObject(dbe)
                dbe = Nothing
    
            End Try
    
        End Sub
    
        ''' <summary>
        ''' Crea y devuelve una referencia al objeto COM especificado.
        ''' </summary>
        ''' <param name="progId">Nombre correspondiente al ProgId del objeto COM que se desea obtener.</param>
        ''' <param name="ty">Se devolverá el tipo asociado al identificador de programa especificado.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function CreateObject(progId As String, ByRef ty As System.Type) As Object
    
            ' Obtenemos el tipo asociado al identificador de programa
            ' (ProgID) especificado.
            '
            ty = Type.GetTypeFromProgID(progId)
    
            If (ty Is Nothing) Then Return Nothing
    
            ' Creamos la instancia del tipo de objeto especificado.
            '
            Return Activator.CreateInstance(ty)
    
        End Function
    
        ''' <summary>
        ''' Ejecuta el método del objeto COM especificado.
        ''' </summary>
        ''' <param name="app">Instancia del objeto COM cuya método se desea ejecutar.</param>
        ''' <param name="ty">El tipo asociado al programa especificado.</param>
        ''' <param name="methodName">Nombre del método que se desea ejecutar.</param>
        ''' <param name="args">Matriz que contiene los argumentos que se van
        ''' a pasar al método que se desea ejecutar.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function ExecuteMethod(app As Object, _
                                       ty As System.Type, _
                                       methodName As String, _
                                       args() As Object) As Object
    
            If ((app Is Nothing) OrElse _
                (ty Is Nothing)) Then Return Nothing
    
            ' Ejecuto el método especificado.
            '
            Return ty.InvokeMember( _
               methodName, _
               BindingFlags.DeclaredOnly Or BindingFlags.Public Or _
               BindingFlags.NonPublic Or BindingFlags.Instance Or _
               BindingFlags.IgnoreCase Or BindingFlags.InvokeMethod, _
               Nothing, _
               app, _
               args)
    
        End Function
    
    End Module

    Fíjate que el método CompactDataBase antiguo se ha reducido considerablemente, ya que ahora se encargará de compactar una base de datos que no se encuentre protegida. No son necesarias ni las notas de advertencia que tenía escritas. Ahora, éste procedimiento será privado. ;-)

    Obviamente, he tenido que sobrecargar el método CompactDataBase para eliminar la contraseña de la base de datos de Access 2003, compactar la base para crear una nueva base de datos de Access 2007, y por último, proteger la nueva base de datos creada.

    Para realizar todo el proceso, tan solo tienes que ejecutar lo siguiente:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                AccessDatabase.CompactDataBase("C:\Mis documentos\Access2003.mdb", "contraseña", "C:\Mis documentos\Access2007.accdb", AccessDatabaseTypeEnum.dbVersion120)
    
                MessageBox.Show("Se ha compactado satisfactoriamente la base de datos.")
    
                ' Si procede, eliminar aquí el archivo de la
                ' base de Access 2003.
                '
                IO.File.Delete("C:\Mis documentos\Access2003.mdb")
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    Te advierto que tras finalizar el proceso, la base de datos de Access 2003 estará desprotegida, de ahí que haya incluido el código para eliminar físicamente el archivo *.mdb.

    En fin, haz una prueba para ver si la nueva base de datos de Access 2007 protegida la puedes abrir si ningún tipo de problema.


    Enrique Martínez Montejo
            [MS MVP - VB]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo jueves, 23 de julio de 2015 18:53
    jueves, 23 de julio de 2015 18:25
    Moderador
  • Hola Enrique:

    Te tomas muchas molestias y sin dudas te lo agradezco.

    Voy a ponerme con ello y mañana te digo algo, que voy a preparar la cena.

    Gracias de todo corazón. Un abrazo muy grande.

    Gemma

    jueves, 23 de julio de 2015 18:53
  • Maestro:

    El tema de la compactación, etc., funciona a la perfección, lo he probado y 10 de 10. (Como siempre).

    Bueno genio informático, muchas gracias como siempre. Ahora no da ningún problema.

    Perfecto.

    Un fuerte abrazo.

    Gemma

    viernes, 24 de julio de 2015 15:56