none
Asignar formato a primera columna en importación de datos desde Excel RRS feed

  • Pregunta

  • Hola a todos:

    Querría saber si hay alguna forma de que en el momento de realizar una importación desde Excel, le pueda cambiar el formato a la primera COLUMNA ya que me lo interpreta como número y no como texto que es lo que necesito.

    Por ejemplo:

    Cód_GC        Ejer_01

    2005                 50,00

    3560                 82,00

    2565-D             36,15

    EL problema es que cuando hace la importación, él registro que corresponde al código 2565-D no lo importa, ahora si voy a Excel y formateo esa columna a Texto, lo importa sin problemas.

    Por ello, la pregunta es si desd evb.net en el momento de importar esa primera columna le puedo poner formato de texto, antes de que empiece toda la importación.

    Hoy tengo varias preguntas que iré haciendo para dejar cualquier pequeño fleco de la aplicación acabado.

    Ruego me disculpéis dichas cantidad de preguntas.

    Un saludo a todos.

    Gemma

    miércoles, 22 de junio de 2016 10:55

Respuestas

  • "gemma_campillo" preguntó:

    > Querría saber si hay alguna forma de que en el momento de realizar una
    > importación desde Excel, le pueda cambiar el formato a la primera COLUMNA
    > ya que me lo interpreta como número y no como texto que es lo que necesito.

    Este tema también lo hablamos ya en su día:

    Importación de datos de Excel a Access 2007

    Y que yo sepa, digamos que no hay una manera "AUTOMÁTICA" para cambiarle el formato a una columna mientras realizas la importación de datos desde Excel. Y de haber alguna manera de hacerlo, entiendo que deberá de ser a través de la propia biblioteca de objetos de Microsoft Excel, por lo que en tu proyecto tendrías que referenciar a la citada biblioteca y lo que ello conlleva.

    El problema que yo veo es que tu dejas al usuario que inserte los datos en Excel, y como te indiqué en su día, unos los insertarán bien y otros no tanto. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 miércoles, 22 de junio de 2016 16:04
    miércoles, 22 de junio de 2016 15:43
    Moderador
  • "gemma_campillo" preguntó:

    > Tu sabes por qué da este error al pulsar el botón:
    >
    > Excepción no controlada del tipo 'System.IO.FileNotFoundException' en SpreadsheetLight.dll
    >
    > Información adicional: No se puede cargar el archivo o ensamblado 'DocumentFormat.OpenXml,
    > Version=2.0.5022.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' ni una de sus dependencias. El
    > sistema no puede encontrar el archivo especificado.
    >
    > Este error me lo da en:
    > Dim sl As New SLDocument("C:\PEPE.xlsx", "Sheet1")
    >
    > Ya he creado en la unidad C, el archivo PEPE.xlsx.

    Entiendo que ese error no tiene nada que ver con que exista o no un archivo llamado PEPE.xlsx en la raíz de la unidad C:, más bien con que no tienes instalada en tu equipo el Open XML SDK 2.0 for Microsoft Office, que parece ser que es utilizado por el ensamblado SpreadsheetLight.dll.

    Desde el siguiente enlace podrás descargar el SDK correspondientes a la versión 2.0 y 2.5:

    Open XML SDK 2.0 for Microsoft Office

    Open XML SDK 2.5 for Microsoft Office

    Ni que decir tiene que si vas a utilizar en tu proyecto la biblioteca SpreadsheetLight, también tendrás que instalar en los equipos cliente la versión del SDK de Open XML que vayas a utilizar.

    Siento decirte que no he utilizado ninguno de los SDKs indicados, por lo que ignoro por completo si solamente puedes distribuir con tu proyecto el ensamblado DocumentFormat.OpenXml.dll, que por el mensaje de error que describes, parece ser que no la tienes referenciada en tu proyecto.

    Y dicho esto, te pregunto: ¿no crees que ya son demasiados paquetes de instalación los que tienen que instalar tus clientes? Si estos disponen de Microsoft Excel, ¿por qué no utilizas la biblioteca de Microsoft Excel mediante reflexión para ejecutar el código que te ha indicado Javier Jiménez? De ésta manera te ahorras tener que referenciar explícitamente en tu proyecto la biblioteca de Excel, ya que en tiempo de ejecución se utilizará aquella versión que tenga instalada el cliente en su equipo.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 junio de 2016 14:50
    Moderador
  • "gemma_campillo" escribió:

    > No me quiero liar mas, voy a ver si tal como indicas el de Javier me funciona ...

    ¡Bueno! Anteriormente te he comentado que ejecutaras el código que te ha indicado Javier pero mediante REFLEXIÓN, para que NO TENGAS que referenciar en tu proyecto la biblioteca de Microsoft Excel y no tener que depender de ésta o aquella versión, porque la versión que se utilizará es la que tenga instalada y debidamente registrada el cliente en su equipo.

    Para ello, copia en tu proyecto la siguiente clase que he preparado en exclusiva para ti, aunque muchos procedimientos compartidos (Shared) los podrías aprovechar para otros trabajos que desees ejecutar también mediante reflexión:

    Option Strict On
    Imports System.Reflection
    
    ''' <summary>
    ''' Clase para interactuar con la biblioteca de objetos
    ''' de Microsoft Excel mediante reflexión, por lo que
    ''' no es necesario referenciarla en nuestro proyecto.
    ''' </summary>
    Friend NotInheritable Class ObjectExcel
    
        Implements IDisposable
    
        Private m_app As Object         ' Objeto Excel.Application (Aplicación Excel)
        Private m_books As Object       ' Objeto Excel.Workbooks (Colección de libros de trabajo)
        Private m_wb As Object          ' Objeto Excel.Workbook (Libro de trabajo)
    
        Private missing As Missing = Missing.Value
    
    #Region "Constructores"
    
        ''' <summary>
        ''' Crea una nueva instancia de la clase con la ruta
        ''' del libro de Excel especificada.
        ''' </summary>
        ''' <param name="fileName">Ruta completa del archivo de Excel.</param>
        Public Sub New(fileName As String)
    
            ' Creamos una nueva instancia del objeto Application.
            m_app = CreateExcelApplication()

    ' Si procede, hacemos visible la instancia de Microsoft Excel. ' SetProperty(m_wb, "Visible", True, Nothing) ' Referenciamos la colección de libros. m_books = GetProperty(m_app, "Workbooks", Nothing) ' Abrimos el libro de trabajo. Dim args(14) As Object args(0) = fileName For n As Integer = 1 To 14 ' Establecer el valor Missing.Value a los 14 ' restantes parámetros opcionales del método ' Open. args(n) = missing Next m_wb = ExecuteMethod(m_books, "Open", args, False) End Sub #End Region #Region "Métodos públicos" ''' <summary> ''' Abre el libro de trabajo especificado devolviendo el ''' envoltorio de un objeto Excel.Workbook. ''' </summary> ''' <param name="nombreHoja">Nombre de la hoja de cálculo.</param> ''' <param name="rangoColumna">Rango de la columna cuyo formato de ''' celdas se desea establecer a Texto. Ejemplos: "A:A" (para la ''' primera columna), "B:C" (para la segunda y tercera columnas).</param> Public Sub SetFormatText(nombreHoja As String, rangoColumna As String) Dim sheets As Object = Nothing ' Objeto Excel.Sheets (Colección de hojas de cálculo) Dim ws As Object = Nothing ' Objeto Excel.Worksheet (Hoja de cálculo) Dim range As Object = Nothing ' Objeto Excel.Range Try ' Referenciamos la colección de hojas de cálculo. ' sheets = GetProperty(m_wb, "Sheets", Nothing) ' Referenciamos la hoja de cálculo especificada. ' ws = GetProperty(sheets, "Item", New Object() {nombreHoja}) ' Referenciamos el rango de celdas correspondientes a la columna especificada ' range = GetProperty(ws, "Range", New Object() {rangoColumna}) ' Seleccionamos el rango ExecuteMethod(range, "Select", Nothing, True) ' Establecemos el formato de texto a las celdas. SetProperty(range, "NumberFormat", "@", Nothing) ' Liberar la referencia al objeto Excel.Range. FinalReleaseComObject(range) ' Referenciamos la primera celda de la hoja de cálculo. range = GetProperty(ws, "Range", New Object() {"A1:A1"}) ' Seleccionamos el rango ExecuteMethod(range, "Select", Nothing, True) Catch ex As Exception ' Se ha producido una excepción. Si procede, indicamos ' que el libro ya ha sido guardado. ' If (Not m_wb Is Nothing) Then SetProperty(m_wb, "Saved", True, Nothing) End If ' Devolver la excepción al procedimiento llamador ' Throw Finally ' Liberar las referencias de los distintos objetos utilizados. FinalReleaseComObject(range) FinalReleaseComObject(ws) FinalReleaseComObject(sheets) End Try End Sub #End Region #Region "Métodos privados." #Region "CreateExcelApplication" ''' <summary> ''' Devuelve una instancia de la clase Excel.Application. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function CreateExcelApplication() As Object Dim ty As Type = CreateType("Excel.Application") ' Creamos la instancia del tipo de objeto especificado. ' Dim flags As BindingFlags = ObjectExcel.BindingFlagsInstance() Dim obj As Object = Activator.CreateInstance(ty, flags, Nothing, Nothing, Nothing, Nothing) If (obj Is Nothing) Then Throw New ArgumentException("No es un objeto válido.") End If Return obj End Function #End Region #Region "CreateType" ''' <summary> ''' Devuelve una instancia de la clase WrappedComObject que envuelve ''' un nuevo objeto COM con el ProgId especificado. ''' </summary> ''' <param name="progId">ProgId del componente COM que se desea referenciar.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function CreateType(progId As String) As Type If (progId Is Nothing) Then Throw New ArgumentNullException("progId") End If ' Obtenemos el tipo asociado al identificador de programa ' (ProgID) especificado. ' Dim ty As Type = Type.GetTypeFromProgID(progId, False) If (ty Is Nothing) Then Throw New Runtime.InteropServices.COMException("Clase no válida o no registrada.") End If Return ty End Function #End Region #Region "BindingFlagsInstance" ''' <summary> ''' Devuelve los indicadores por defecto que se utilizarán para controlar ''' el enlace y la manera en la que se realiza la búsqueda de miembros ''' pertenecientes a una instancia de un objeto. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function BindingFlagsInstance() As BindingFlags Return BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.FlattenHierarchy End Function #End Region #Region "ExecuteMethod" ''' <summary> ''' Ejecuta el método de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya método se desea ejecutar.</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> ''' <param name="ignoreReturn">true si el método no devuelve un valor o si se puede ''' ignorar el valor devuelto; false en caso contrario.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function ExecuteMethod(obj As Object, methodName As String, args As Object(), ignoreReturn As Boolean) As Object Dim flags As BindingFlags = BindingFlags.InvokeMethod If (ignoreReturn) Then flags = flags Or BindingFlags.IgnoreReturn End If If (Not obj Is Nothing) Then ' Ejecutar el método de instancia. flags = flags Or ObjectExcel.BindingFlagsInstance() Return InvokeMember(obj, Nothing, methodName, flags, args, Nothing, Nothing) End If Return Nothing End Function #End Region #Region "GetProperty" ''' <summary> ''' Obtiene el valor de la propiedad del objeto o tipo de dato especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya propiedad se desea leer.</param> ''' <param name="propertyName">Nombre de la propiedad.</param> ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function GetProperty(obj As Object, propertyName As String, index As Object()) As Object Dim flags As BindingFlags = BindingFlags.GetProperty If (Not obj Is Nothing) Then ' Leer el valor de una propiedad de instancia. flags = flags Or BindingFlagsInstance() Return InvokeMember(obj, propertyName, flags, index) End If Return Nothing End Function #End Region #Region "FinalReleaseComObject" ''' <summary> ''' Libera todas las referencias a un contenedor RCW (Contenedor al que ''' se puede llamar en tiempo de ejecución) estableciendo su recuento ''' de referencias en 0. ''' </summary> ''' <param name="obj">Objeto RCW que se va a liberar.</param> ''' <remarks></remarks> Private Shared Sub FinalReleaseComObject(obj As Object) ' RCW = Runtime Callable Wrapper ' Una aplicación de Office no se cierra después de la automatización desde Visual Studio. NET ' Office application does not quit after automation from Visual Studio .NET client ' http://support.microsoft.com/kb/317109 If (Not obj Is Nothing) Then Try ' Se requiere .NET 2.0 o superior. System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj) Catch ' Deshechamos devolver la posible excepción ' si no es un objeto COM válido. Finally obj = Nothing End Try End If End Sub #End Region #Region "InvokeMember" ''' <summary> ''' Invoca el miembro de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param> ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía ''' ("") para llamar al miembro predeterminado.</param> ''' <param name="invokeAttr">Máscara de bits formada por una o varias enumeraciones ''' BindingFlags que especifican la forma en que se realiza la búsqueda.</param> ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al ''' miembro al cual se va a invocar.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function InvokeMember(obj As Object, name As String, invokeAttr As BindingFlags, args As Object()) As Object Return InvokeMember(obj, Nothing, name, invokeAttr, args, Nothing, Nothing) End Function ''' <summary> ''' Invoca el miembro de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param> ''' <param name="ty">El tipo asociado al objeto donde debe invocarse el miembro especificado.</param> ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía ''' ("") para llamar al miembro predeterminado.</param> ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al ''' miembro al cual se va a invocar.</param> ''' <param name="modifiers">Matriz de objetos ParameterModifier que representan los ''' atributos asociados al elemento correspondiente de la matriz args.</param> ''' <param name="namedParameters">Matriz que contiene los nombres de los parámetros ''' a los que se pasan los valores de la matriz args.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function InvokeMember(obj As Object, ty As Type, name As String, invokeAttr As BindingFlags, args As Object(), modifiers As ParameterModifier(), namedParameters As String()) As Object If (String.IsNullOrWhiteSpace(name)) Then Throw New MissingMemberException("El valor del miembro especificado no tiene un formato válido para convertirlo al tipo de dato requerido.") End If If (Not obj Is Nothing) Then ' Invocar el miembro de instancia especificado. Return obj.GetType().InvokeMember(name, invokeAttr, Nothing, obj, args, modifiers, Nothing, namedParameters) End If If (Not ty Is Nothing) Then ' Invocar el miembro estático especificado. Return ty.InvokeMember(name, invokeAttr, Nothing, Nothing, args, modifiers, Nothing, namedParameters) End If Throw New ArgumentNullException() End Function #End Region #Region "SetProperty" ''' <summary> ''' Establece el valor de la propiedad del objeto especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya propiedad se desea establecer.</param> ''' <param name="propertyName">Nombre de la propiedad.</param> ''' <param name="newValue">El nuevo valor de la propiedad.</param> ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param> ''' <remarks></remarks> Private Shared Sub SetProperty(obj As Object, propertyName As String, newValue As Object, index As Object()) Dim flags As BindingFlags = BindingFlags.SetProperty Dim parameters As Object() = Nothing If (Not index Is Nothing) Then parameters = New Object(index.Length) {} For n As Integer = 0 To index.Length - 1 parameters(n) = index(n) Next parameters(index.Length) = newValue Else parameters = New Object() {newValue} End If If (Not obj Is Nothing) Then ' Leer el valor de una propiedad de instancia. flags = flags Or BindingFlagsInstance() InvokeMember(obj, propertyName, flags, parameters) End If End Sub #End Region #Region "Soporte para IDisposable" ' Para detectar llamadas redundantes Private disposedValue As Boolean ' IDisposable Private Sub Dispose(disposing As Boolean) If (Not disposedValue) Then If (disposing) Then ' Elimine el estado administrado (objetos administrados). ' If (Not m_wb Is Nothing) Then ' Guardamos los cambios. ExecuteMethod(m_wb, "Save", Nothing, True) ' Cerramos el libro. ExecuteMethod(m_wb, "Close", Nothing, True) End If If (Not m_books Is Nothing) Then ExecuteMethod(m_books, "Close", Nothing, True) End If If (Not m_app Is Nothing) Then ExecuteMethod(m_app, "Quit", Nothing, True) End If End If ' Libere los recursos no administrados (objetos no administrados) y reemplace Finalize() . ' FinalReleaseComObject(m_wb) FinalReleaseComObject(m_books) FinalReleaseComObject(m_app) End If disposedValue = True End Sub Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region #End Region End Class

    Insisto que con ésta clase no necesitas referenciar en tu proyecto ninguna biblioteca para trabajar con Excel, ni de Microsoft ni de terceras partes, pero el cliente sí tendrá que tener instalada una versión de Excel para que funcione.

    Ahora, cuando desees establecer el formato de Texto a las celdas correspondientes a la primera columna de un libro de Excel cualquiera, simplemente ejecutarías el siguiente código:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using app As New ObjectExcel(IO.Path.Combine(Application.StartupPath, "Libro1.xlsx"))
                    app.SetFormatText("Hoja1", "A:A")
                End Using
    
                MessageBox.Show("Se ha establecido satisfactoriamente el formato Texto a la columna.")
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Ni que decir tiene que éste código lo tendrás que ejecutar ANTES de exportar los datos de Excel a la base de datos que corresponda, es decir, ANTES de rellenar un objeto DataTable o recorrer un objeto DataReader, para que el ISAM de Excel puede leer correctamente los datos de la dichosa columna.

    Fíjate que creamos la instancia de la clase ObjectExcel especificando la ruta del libro de Excel, en el ejemplo, se supone que Libro1.xlsx se encuentra en la misma carpeta que contiene el ejecutable de nuestra aplicación, y la encerramos entre un bloque Using ... End Using (¡vamos! ¡como si fuera un objeto OleDbConnection!) para que se destruyan automáticamente los diferentes objetos de Excel que se han utilizado, a fin de que el proceso de Excel no se quede "colgado" en ejecución.

    Y para establecer el formato de Texto a una columna, tan solo tienes que especificar el nombre de la hoja de cálculo (Hoja1) y el rango de las celdas. Con el rango "A:A", el formato se aplicará a todas las celdas de la primera columna (A). Si no ese el rango que deseas, eres libre de especificar el que creas conveniente. Por ejemplo, si deseas establecer el formato a las filas comprendidas entre la 2 y la 10 (ambas inclusive) de la primera columna, especificarías el rango "A2:A10".

    En fin, espero que disfrutes de la clase ObjectExcel, y de camino, aprendas cómo se utiliza la reflexión en el marco de trabajo de .NET. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 junio de 2016 18:44
    Moderador
  • "gemma_campillo" escribió:

    > Tengo un problema causado por mí, en la aplicación de la ruta de la hoja, ya
    > que me da error en la clase de: Se produjo una excepción en el destino de la
    > invocación.

    Si la firma del procedimiento Insertar es la siguiente:

        Private Sub Importar(ByVal rut As String, ByVal ruc As String)

    donde se supone que el primer parámetro ('rut') contiene la ruta del archivo de Excel seleccionado por el usuario, crearías la instancia de la clase ObjectExcel pasándole dicha ruta:

        Using app As New ObjectExcel(rut)
            app.SetFormatText("hoj", "A:A")
        End Using

    Lo de "IO.Path.Combine(Application.StartupPath, "Libro1.xlsx"))" lo puse como ejemplo, pero al constructor de la clase ObjectExcel simplemente le tienes que pasar la ruta completo del archivo de Excel que vas a utilizar.

    Se comprende que "hoj" es el nombre de la hoja de cálculo donde deseas modificar el formato de las celdas de la columna A. ¿Ese es el nombre correcto de la hoja de cálculo? ¿"hoj"? ¿O por casualidad se llama Hoja1, Hoja2 o Balance? Desde luego, al procedimiento SetFormatText le tienes que pasar el NOMBRE EXACTO DE LA HOJA, sin el carácter $.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 6:59
    viernes, 24 de junio de 2016 6:47
    Moderador
  • "gemma_campillo" escribió:

    > Continúa el mismo error. La variable "hoj" proviene del procedimiento:
    >

    Efectivamente, la variable hoj (sin comillas dobles) contiene el valor devuelto por la función NombrePrimeraHoja:

        Dim hoj As String = NombrePrimeraHoja(cnx)

    Pero fíjate cómo estás llamando al procedimiento SetFormatText:

        app.SetFormatText("hoj", "A:A")

    ¿Te das cuenta de lo que estás haciendo mal? En lugar de utilizar la variable hoj (sin comillas dobles), le estás pasando el valor "hoj" (con comillas dobles) al procedimiento SetFormatText, de ahí que obtengas la correspondiente excepción porque NO EXISTE en el libro de Excel una hoja de cálculo llamada "hoj".

    Tienes que quitar las comillas dobles:

        Dim hoj As String = NombrePrimeraHoja(cnx)
        Using app As New ObjectExcel(rut)
            app.SetFormatText(hoj, "A:A")
        End Using

    ¡Ay, ay!  ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.


    viernes, 24 de junio de 2016 7:19
    Moderador
  • "gemma_campillo" escribió:

    > Ya está corregido  ¡Ay, ay!  ;-), pero continúa dando el error. El error
    > lo da porque haciendo un seguimiento del nombre de la hoja de Excel que es:
    > 5ejerSqlEx.xlsx, lo transforma en 5ejerSqlEx$.xlsx, que es el nombre que
    > le doy a la hoja cuando declaro la variable "NombrePrimeraHoja" en la función.

    Y continuaras obteniendo el error por los siglos de los siglos hasta que no le pases al procedimiento el nombre de una hoja (sin el carácter $) existente en el libro.

    > por lo tanto voy a ver porque arrastra el $ ya que entonces reconoce que
    > la hoja no existe, de ahí el error ya que el nombre de la hoja es: 5ejerSqlEx.xlsx

    Lo primero que tienes que hacer es verificar el nombre que devuelve la función NombrePrimeraHoja, que puede que ésta te devuelva el nombre de la hoja con el carácter $, ya que dicho carácter SÍ ES NECESARIO para que el ISAM de Excel pueda recuperar un conjunto de datos mediante una consulta SQL de selección, como por ejemplo "SELECT * FROM [Hoja1$]".

    Una vez que el nombre de la hoja sea correcto, tan solo tienes que eliminar el carácter $ ANTES de llamar al procedimiento SetFormatText de la clase ObjectExcel.

    Pero lo que me resulta bastante extraño es que la función NombrePrimeraHoja te devuelva el valor "5ejerSqlEx$.xlsx". Eso lo tengo que ver con mis propios ojos.

    Fíjate cómo llamas al procedimiento Importar:

        If ofd.ShowDialog = System.Windows.Forms.DialogResult.OK Then
            Importar(ofd.FileName, ofd.SafeFileName)
        End If

    ¿De donde sale el valor "5ejerSqlEx$.xlsx"? ¿No será de aquel que devuelve la propiedad SafeFileName del objeto OpenFileDialog? Verifica si es así.

    Por cierto, ¿para qué utilizas el valor de la propiedad SafeFileName?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 9:37
    viernes, 24 de junio de 2016 8:12
    Moderador
  • "gemma_campillo" escribió:

    > 1) La propiedad SafeFileName devuelve: 5ejerSqlEx.xlsx

    De verdad que no sé para qué quieres ese valor, cuando la ruta completa del archivo de Excel lo obtienes de la propiedad FileName del objeto OpenFileDialog, valor éste que es el que le pasas al primer parámetro del procedimiento Importar.

    > 2) El nombre de la  NombrePrimeraHoja cuando entra en la función es: "Hoja1$"

    De acuerdo. ¿Y cuando "sale"? ¿Qué valor devuelve la función NombrePrimeraHoja?

    > 3) Cuando en el procedimiento "Importar"  crea la variable
    >
    > Dim Hoj as String = NombrePrimeraHoja(cnx) ahí lleva el valor:
    >    5ejerSqlEx$.xlsx por lo tanto "Hoj" lleva ese valor.

    ¿Me estás diciendo que la función NombrePrimeraHoja devuelve el valor 5ejerSqlEx$.xlsx? Si eso es así, no creo yo que sea un nombre de hoja de cálculo válido, más bien se trata del nombre del archivo de Excel y su extensión, es decir, el valor devuelto por la propiedad SafeFileName del objeto OpenFileDialog.

    > 4) La ruta : Using App as New ObjectExcel(rut) lleva la ruta correctamente,
    > acando en: 5ejerSqlEx.xlsx

    No es así. Al constructor del objeto ObjectExcel tienes que especificarle LA RUTA COMPLETA del archivo de Excel, es decir, el valor del parámetro 'rut' del procedimiento Importar.

    > 5) Lógicamente en el App.SetFormatText(hoj, "A:A") la variable "hoj"
    > también lleva el valor: 5ejerSqlEx$.xlsx

    Te repito de nuevo que no creo que ese sea el nombre correcto de la hoja de cálculo.

    > Por ello, trato de quitar el último dígito de la String Hoh y no hay manera,
    > siempre me da el mismo resultado con el $.
    >
    >  Dim MyChar() As Char = {CChar("$"), CChar(" ")}

    ¡Vamos a ver! Obtienes el nombre de la primera hoja de cálculo ejecutando:

        Dim hoj As String = NombrePrimeraHoja(cnx)

    Ahora vamos a eliminar el carácter final $:

        Dim nombreHoja As String = hoj.Replace("$", "")

    Procedemos a formatear la columna A de la hoja de cálculo:

        Using app As New ObjectExcel(rut)
            app.SetFormatText(nombreHoja, "A:A")
        End Using

    La verdad es que no creía que ibas a tener tantos problemas para formatear la hoja de cálculo, porque solamente SON 3 LÍNEAS DE CÓDIGO las que tienes que ejecutar, pero ¡claro! Hay que pasarle los VALORES CORRECTOS, tanto al constructor de la clase ObjectExcel como al procedimiento SetFormatText. ¡Si fueran 20 líneas de código las que tienes que ejecutar no sé lo que harías entonces! :-))

    Para que compruebes que el método SetFormatText hace bien su trabajo, limítate a pasarle directamente la ruta completa del archivo de Excel y el nombre de una hoja de cálculo que sepas que existe en dicho archivo:

        Using app As New ObjectExcel("C:\Carpeta\Libro1.xlsx")
            app.SetFormatText("Hoja1", "A:A")
        End Using

    Una vez que hayas comprobado que el procedimiento hace bien su trabajo, entonces te "peleas" con los distintos valores devueltos por las funciones y variables que estás utilizando en tu código hasta que encuentres los valores CORRECTOS que tienes que especificar. :-))


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.






    viernes, 24 de junio de 2016 9:58
    Moderador
  • Lo primero de todo: ¿has probado utilizar la clase ObjectExcel pasándole únicamente la ruta de un archivo de Excel con el nombre de una hoja de cálculo que de antemano sabes que existe?

        Try
            Using app As New ObjectExcel("C:\Carpeta\Libro1.xlsx")
                app.SetFormatText("Hoja1", "A:A")
            End Using
    
         Catch ex As Exception
             Dim msg As String = String.Empty
             If (ex.InnerException Is Nothing) Then
                 msg = ex.Message
             Else
                 msg = ex.InnerException.Message
             End If
      
             MessageBox.Show(msg)
    
         End Try

    A modo de prueba, éste código lo puedes ejecutar desde el evento Click de cualquier Button que tengas en un formulario cualquiera de tu aplicación.

    Por favor, es lo que quiero que me respondas de una vez, para ver si el procedimiento SetFormatText hace o no bien su trabajo. Simplemente es lo que quiero que me digas: SÍ o NO. ¿De acuerdo?

    "gemma_campillo" escribió:

    > Bueno, ahora ya coge bien el nombre sin el símbolo del $. Hace dos pasadas
    > por la clase ObjectExcel, la primera la pasa perfectamente pero en la segunda
    > se queda otra colgada en el mismo error.

    No observo el mensaje de error, aunque de producirse, el mensaje que por defecto devuelve poco nos va a decir, ya que en lugar de consultar la propiedad Message de un objeto Exception, tienes que consultar la propiedad Message pero del objeto InnerException existente en el objeto Exception.

          Try
             Importar( ... , ...)
    
          Catch ex As Exception
             Dim msg As String = String.Empty
             If (ex.InnerException Is Nothing) Then
                 msg = ex.Message
             Else
                 msg = ex.InnerException.Message
             End If
      
             MessageBox.Show(msg)
    
          End Try

    Ese es el mensaje de error que me gustaría conocer. De todas maneras, una vez que se detenga el código donde se produce el error (en la línea amarilla que aparece en la imagen que has publicado), ¿me podrías decir el valor que tiene la variable 'name' y los valores que tiene las matriz 'args'?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.



    viernes, 24 de junio de 2016 11:03
    Moderador
  • "gemma_campillo" escribió:

    > SI, he puesto únicamente la tabla de Excel en el disco c:\ La reconoce perfectamente.

    Entonces el problema NO ES de la clase ObjectExcel, de hecho, he descargado el archivo de Excel y he establecido satisfactoriamente el formato Texto a la primera columna de la hoja de cálculo llamada 5ejerSqlEx del libro de trabajo llamado 5ejerSqlEx.xlsx. Pero para esto he tenido que hacer ciertas modificaciones que describo a continuación.

    > Bueno, maestro, insisto en que si no va no le des muchas vueltas, ya que es para ayudar
    > al usuario despistado, pero incluso le pongo un Message box o un tooltip recordándole
    > que de formato a la primera columna.

    El tema no es que sea para ayudar a los usuarios despistados; el tema consiste en si sabes qué es lo que realmente tienes que hacer para que a ti también te funcione correctamente como me funciona a mí.

    En primer lugar, ¿no has podido elegir otro nombre para la hoja de cálculo que no empiece por un número? Si tu nombras a una hoja con el nombre 5ejerSqlEx, vas a obtener un error en el procedimiento SetFormatText a la hora de referenciar dicha hoja, es decir, a la hora de ejecutar la siguiente línea:

        ' Referenciamos la hoja de cálculo especificada.
        '
        ws = GetProperty(sheets, "Item", New Object() {nombreHoja})

    porque si no lo sabes, te diré que cuando el nombre de una hoja de cálculo comienza por un número, como es tu caso, Microsoft Excel encierra el nombre entre comillas simples ('5ejerSqlEx'), por lo que la función NombrePrimeraHoja te devolverá el valor alfanumérico "'5ejerSqlEx$'", estando las comillas simples DENTRO DEL NOMBRE DE LA HOJA. Como posteriormente eliminas el carácter $, el nombre de la hoja de cálculo se queda en "'5ejerSqlEx'", siendo éste el nombre definitivo de la misma. ¿Ves bien las comillas simples dentro del valor alfanumérico encerrado entre comillas dobles?

    Normalmente, los nombres de las hojas de cálculo comienzan por una LETRA o por un guión bajo, no por un número, por lo que en éste caso no podrás referenciar la hoja de cálculo (un objeto Excel.Worksheet) mediante su nombre, por lo que tendrás que hacerlo por su índice en base 1.

    Obtener información acerca de las reglas de sintaxis de los nombres

    Sustituye en el procedimiento SetFormatText la línea anterior por ésta otra:

        ' Referenciamos la primera hoja de cálculo.
        '
        ws = GetProperty(sheets, "Item", New Object() {1})

    De ésta manera ya no te hace falta para nada el parámetro nombreHoja de dicho procedimiento, por lo que lo puedes eliminar de la firma:

       
    Public Sub SetFormatText(rangoColumna As String)

    Y por supuesto, tampoco hace falta ya que elimines el carácter $ del valor devuelto por la función NombrePrimeraHoja.

    Ahora, el código funcionará solamente para cambiar el formato de las celdas de la primera hoja del archivo de Excel, es decir, aquella que tenga en su colección de hojas el índice 1.

    No se por qué motivo, pero me da la sensación que todo el trabajo ha sido en balde. :-((


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.




    viernes, 24 de junio de 2016 15:13
    Moderador
  • "gemma_campillo" escribió:

    Por si te decides finalmente a utilizar la clase ObjectExcel, te comento que para guardar los cambios en el archivo de Excel referentes al formato de las celdas, el archivo NO PUEDE ESTAR ABIERTO. Quiere esto decir que, si en tu procedimiento Importar abres una conexión para obtener el nombre de la primera hoja del archivo de Excel:

        'Conexión Excel
        Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")

        cnx.Open()

        Dim nombreHoja As String = NombrePrimeraHoja(cnx).Replace("$", "")

    NO PUEDES llamar inmediatamente al procedimiento SetFormatText de la clase ObjectExcel hasta que no cierres la conexión:

        ' Cerrar la conexión
        '
        cnx.Close()
    
        ' Dar formato a las celdas
        Using app As New ObjectExcel(rut)
            app.SetFormatText(nombreHoja, "A:A")
        End Using
    

    Y posteriormente abrirla de nuevo para que puedas abrir el lector de datos OleDbDataReader:

       
        cnx.Open()

    Quería comentarte esto ahora que el tema está "caliente", vaya a ser que el día de mañana te surja el problema y no sepamos ni por dónde viene.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 15:54
    viernes, 24 de junio de 2016 15:49
    Moderador
  • "gemma_campillo" escribió:

    > voy a rehacerla un poquito que está la pobre muy tocada

    Copia/pega de nuevo el código fuente de la clase ObjectExcel (¿o mejor se tendría que llamar ExcelObject?), porque hace un rato la he modificado para que no aparezca la interfaz de usuario de Microsoft Excel, ya que ayer se me olvidó comentar la siguiente línea en el constructor de la clase (procedimiento Sub New):

            ' Si procede, hacemos visible la instancia de Microsoft Excel.
            ' SetProperty(m_wb, "Visible", True, Nothing)

    Si quitas el comentario, al usuario le aparecerá la interfaz de Excel, pero no creo que sea necesario hacerlo. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.


    viernes, 24 de junio de 2016 16:06
    Moderador
  • "gemma_campillo" escribió:

    > Maestro, si no te he entendido mal quieres que te ponga la clase, no?.

    No, no te dije eso, pero sí te indiqué que comentaras la siguiente línea para que no se abra la propia interfaz de usuario de Microsoft Excel cuando vayas a formatear la columna:

           ' Si procede, hacemos visible la instancia de Microsoft Excel.
           ' SetProperty(m_wb, "Visible", True, Nothing)

    Esa línea se encuentra en el constructor de la clase ObjectExcel (procedimiento Sub New).


    >    Public Sub SetFormatText(rangoColumna As String)
    >
    >       ' Referenciamos la hoja de cálculo especificada.
    >       '
    >       ws = GetProperty(sheets, "Item", New Object() {1})

    Como finalmente has decidido referenciar la hoja de cálculo por su índice para formatear SIEMPRE la primera hoja del archivo de Excel, poco sentido tiene que llames a la función NombrePrimeraHoja para simplemente obtener el nombre de la primera hoja. ¿No lo crees así?

    No obstante, te aconsejaría que dejaras el procedimiento Importar tal cual lo tenías anteriormente, y te limitases a formatear la hoja de cálculo fuera de dicho procedimiento y ANTES de llamar al procedimiento Importar, por ejemplo, en el evento Click del control llamado btnImpexcel, tras cerrar el cuadro de diálogo que le muestras al usuario para seleccionar el archivo de Excel:

        Private Sub btnImpexcel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnImpexcel.Click
    
            ' ...
    
            ' ...
    
            ' ...
    
            Using ofd As New OpenFileDialog()
                With ofd
                    .Multiselect = False
                    .Filter = "Archivos de Excel (*.xls; *.xlsx)|*.xls;*.xlsx"
                    .CheckFileExists = True
                End With
    
                If (ofd.ShowDialog = DialogResult.OK) Then
               
                    ' Formatear la columna
                    Using app As New ObjectExcel(rut)
                        app.SetFormatText("A:A")
                    End Using
    
                    ' Importar los datos
                    Importar(ofd.FileName, ofd.SafeFileName)
    
                End If
    
            End Using
    
        End Sub

    De ésta manera, en el procedimiento Importar ya no tienes que abrir la conexión para obtener el nombre de la primera hoja, cerrarla para formatear la columna, y nuevamente abrirla para obtener un objeto DataReader, es decir, que del procedimiento Importar eliminarías las siguientes líneas:

        ' Cerrar la conexión para pooder formatear la primera columna
        '
        ' cnx.Close()
        '
        ' Dar formato a las celdas
        ' Using app As New ObjectExcel(rut)
        '     app.SetFormatText("A:A")
        ' End Using
        '
        ' cnx.Open()

    De esta manera descargarías de trabajo al procedimiento Importar, que bastante tiene ya. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.



    sábado, 25 de junio de 2016 7:19
    Moderador
  • Se trata de automatizar Excel. Abres la hoja Excel, asignas los tipos de las celdas y grabas. Algo parecido a esto:

            Dim oXL As Microsoft.Office.Interop.Excel.Application
            Dim oWB As Microsoft.Office.Interop.Excel.Workbook
            Dim oSheet As Microsoft.Office.Interop.Excel.Worksheet
    
            Dim UltimaFila As Integer
    
            oXL = CreateObject("Excel.Application")
            oXL.Visible = False
    
            oWB = exApp.Workbooks.Open("C:\Carpeta\prueba.xls")
    
            oSheet = oWB.Sheet(1)  ' Selecciono la hoja
    
            UltimaFila =  = oWB.ActiveSheet.UsedRange.Row ‐ 1 + oWB.ActiveSheet.UsedRange.Rows.Count
    
            For Fila As Integer = 1 to UltimaFila
      	    For Columna as Integer = 1 to 10
                   oSheet.Cells(Fila, 1).NumberFormat = "@" 
                Next
            Next
    
    	oWB.Save()
    
            oSheet = Nothing
            oWB = Nothing
            oXL.Quit()
            oXL = Nothing


    Saludos, Javier J

    • Marcado como respuesta gemma_campillo miércoles, 22 de junio de 2016 17:00
    miércoles, 22 de junio de 2016 16:54
  • Hola:
    Este ejemplo usa 2 librerias DocumentFormat.OpenXml.dll y SpreadsheetLight.dll
    Añadir referencias a dichas librerias
    En un Form con 1 Button. copia y pega el siguiente codigo
    Imports DocumentFormat.OpenXml
    Imports DocumentFormat.OpenXml.Spreadsheet
    Imports SpreadsheetLight
    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim sl As New SLDocument("D:\PEPE.xlsx", "Sheet1")
            sl.SetCellValue("A1", 123456789.12345)
            sl.SetCellValue(2, 1, -123456789.12345)
            sl.SetCellValue(3, 1, New DateTime(2123, 4, 15))
            sl.SetCellValue(4, 1, 12.3456)
            sl.SetCellValue(5, 1, 12.3456)
            sl.SetCellValue("A6", 123456789.12345)
            Dim style As SLStyle = sl.CreateStyle
            style.FormatCode = "#,##0.000"
            sl.SetColumnStyle(1, style)
            '
            sl.SetCellValue(1, 2, "2005")
            sl.SetCellValue(2, 2, "3560")
            sl.SetCellValue(3, 2, "2565-D")
            Dim style1 As SLStyle = sl.CreateStyle
            style1.FormatCode = "A"
            sl.SetColumnStyle(2, style1)
            '
            sl.SaveAs("D:\PEPE.xlsx")
            MessageBox.Show("fichero creado")
        End Sub
    End Class

    P.D.

    Crea un fichero D:\PEPE.xlsx en blanco para ver los estilo creados

    Un saludo desde Bilbo
    Carlos


    miércoles, 22 de junio de 2016 22:32
  • "gemma_campillo" escribió:

    > Te he de decir que había habandonado el tema, porque incluso la de Javier
    > me estaba dando errores y al final he dicho que les pongo en la ayuda una
    > coletilla por la que tienen que formatear dicha columnas ...

    Pero, ¿has probado el código de la clase que publiqué? Creo que con ella tienes el asunto resuelto para formatear a Texto las celdas de un rango de celdas de Excel, y lo más IMPORTANTE, sin tener que referenciar en tu proyecto la biblioteca de Microsoft Excel.

    > El problema surge porque no leen nada y entonces a llamar
    > por teléfono que es lo más fácil.

    Pues con ese código te puedes ahorrar esas llamadas telefónicas, al menos en lo que concierne al formateo de las celdas. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 6:18
    viernes, 24 de junio de 2016 6:00
    Moderador

Todas las respuestas

  • que tal una macro con VB.NET para poder editar el excel y cambias tu columna(s) a formato "Texto" ?
    miércoles, 22 de junio de 2016 15:09
  • Dejame ver si entendí bien, necesitas exportar datos de una aplicación a Excel???. Si es así tal vez puedas hacer uso de Reflection y detectar el tipo de dato que se va a exportar, algo como esto:

    Suponiendo que tomas los datos de un DataGridView

    if (control.Rows[i].Cells[j].Value.GetType() == typeof(decimal))
    {xlWorkSheet.Cells[i, j] = string.Format("{0:N}", control.Rows[i].Cells[j].Value); }

    Para el formato mira este link:

    http://csharp.net-informations.com/excel/csharp-format-excel.htm

    Puedes pasarlo a VB con esta herramienta:

    http://converter.telerik.com/


    Saludos.

    miércoles, 22 de junio de 2016 15:34
  • Asigna el formato de la celda a texto antes de escribir su valor:

    oSheet.Cells(1, 1).NumberFormat = "@" 
    oSheet.Cells(1, 1) = "2005" 

    Saludos, Javier J

    miércoles, 22 de junio de 2016 15:37
  • Hola:

    No, el tema es para importar de Excel a una tabla.

    Muchas gracias.

    Gemma

    miércoles, 22 de junio de 2016 15:40
  • Hola:

    No se hacer macros, lo siento.,

    Gemma

    miércoles, 22 de junio de 2016 15:41
  • "gemma_campillo" preguntó:

    > Querría saber si hay alguna forma de que en el momento de realizar una
    > importación desde Excel, le pueda cambiar el formato a la primera COLUMNA
    > ya que me lo interpreta como número y no como texto que es lo que necesito.

    Este tema también lo hablamos ya en su día:

    Importación de datos de Excel a Access 2007

    Y que yo sepa, digamos que no hay una manera "AUTOMÁTICA" para cambiarle el formato a una columna mientras realizas la importación de datos desde Excel. Y de haber alguna manera de hacerlo, entiendo que deberá de ser a través de la propia biblioteca de objetos de Microsoft Excel, por lo que en tu proyecto tendrías que referenciar a la citada biblioteca y lo que ello conlleva.

    El problema que yo veo es que tu dejas al usuario que inserte los datos en Excel, y como te indiqué en su día, unos los insertarán bien y otros no tanto. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 miércoles, 22 de junio de 2016 16:04
    miércoles, 22 de junio de 2016 15:43
    Moderador
  • Hola Javier:

    Es para cuando importo de Excel, no se si te refieres a eso. Yo necesito aplicarle el formato en el momento de importar y antes de asignarle los valores del campo ese. "Cód_GC", así el usuario no se tiene que molestar en cambiar el formato de la columna a texto, se lo quiero hacer yo en el momento de la importación.

    Si ves, hay una pregunta sobre importación de Excel hecha hoy mismo y respondida y resuelta por el maestro Enrique Martínez, ahí está la forma en que importo.

    Voy un poco perdida con los objetos de Excel.

    Un abrazo.

    Gemma

    miércoles, 22 de junio de 2016 15:44
  • Hola Enrique:

    Si, encuentras tu antes las respuestas que yo. Bueno, pues nada lo dejo como está y en la ayuda del programa ya le indico que tiene estar formateada la columna como texto. Sabes tu, que los usuarios quieren todo hecho, muchos sin incapaces de mirarse la ayuda, prefieren llamar por teléfono y ya está, por eso, quería ver si con algún truco o algo podía en el momento de la importación que la cambiara por formato texto.

    Pues nada mas, a seguir que ya estoy acabando.

    Un abrazo y muchas gracias.

    Gemma

    miércoles, 22 de junio de 2016 16:04
  • ¿Has probado a asignar formato texto a las celdas como te digo arriba?

    Podrías copiar la hoja y trabajar sobre esa copia modificando las celdas a formato texto.


    Saludos, Javier J

    miércoles, 22 de junio de 2016 16:09
  • Hola Javier:

    Discúlpame pero no me aclaro con lo que me dices.

    Eso lo declaro debajo de la conexión por ejemplo?

        'Conexión Excel
                    Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")
    
                        cnx.Open()
                       
                        Dim hoj As String = NombrePrimeraHoja(cnx)
    
                        oSheet.Cells(1, 1).NumberFormat = "@"
                        oSheet.Cells(1, 1) = "2005"

    Pero me indica que oSheet no está declarado y tampoco se como tengo que declararlo. No me excuso porque lo tendría que saber, pero es que el Excel solo lo toco para esto de la importación de datos.

    Bueno, aver si puedo aclararme con eso que me explicas.

    Un abrazo.

    Gemma

    miércoles, 22 de junio de 2016 16:30
  • Se trata de automatizar Excel. Abres la hoja Excel, asignas los tipos de las celdas y grabas. Algo parecido a esto:

            Dim oXL As Microsoft.Office.Interop.Excel.Application
            Dim oWB As Microsoft.Office.Interop.Excel.Workbook
            Dim oSheet As Microsoft.Office.Interop.Excel.Worksheet
    
            Dim UltimaFila As Integer
    
            oXL = CreateObject("Excel.Application")
            oXL.Visible = False
    
            oWB = exApp.Workbooks.Open("C:\Carpeta\prueba.xls")
    
            oSheet = oWB.Sheet(1)  ' Selecciono la hoja
    
            UltimaFila =  = oWB.ActiveSheet.UsedRange.Row ‐ 1 + oWB.ActiveSheet.UsedRange.Rows.Count
    
            For Fila As Integer = 1 to UltimaFila
      	    For Columna as Integer = 1 to 10
                   oSheet.Cells(Fila, 1).NumberFormat = "@" 
                Next
            Next
    
    	oWB.Save()
    
            oSheet = Nothing
            oWB = Nothing
            oXL.Quit()
            oXL = Nothing


    Saludos, Javier J

    • Marcado como respuesta gemma_campillo miércoles, 22 de junio de 2016 17:00
    miércoles, 22 de junio de 2016 16:54
  • Hola Javier:

    Ahora si lo entiendo, voy a ir probándolo.

    Muchas gracias por tu atención y paciencia.

    Un abrazo.

    Gemma

    miércoles, 22 de junio de 2016 17:01
  • Hola:
    Este ejemplo usa 2 librerias DocumentFormat.OpenXml.dll y SpreadsheetLight.dll
    Añadir referencias a dichas librerias
    En un Form con 1 Button. copia y pega el siguiente codigo
    Imports DocumentFormat.OpenXml
    Imports DocumentFormat.OpenXml.Spreadsheet
    Imports SpreadsheetLight
    Public Class Form1

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim sl As New SLDocument("D:\PEPE.xlsx", "Sheet1")
            sl.SetCellValue("A1", 123456789.12345)
            sl.SetCellValue(2, 1, -123456789.12345)
            sl.SetCellValue(3, 1, New DateTime(2123, 4, 15))
            sl.SetCellValue(4, 1, 12.3456)
            sl.SetCellValue(5, 1, 12.3456)
            sl.SetCellValue("A6", 123456789.12345)
            Dim style As SLStyle = sl.CreateStyle
            style.FormatCode = "#,##0.000"
            sl.SetColumnStyle(1, style)
            '
            sl.SetCellValue(1, 2, "2005")
            sl.SetCellValue(2, 2, "3560")
            sl.SetCellValue(3, 2, "2565-D")
            Dim style1 As SLStyle = sl.CreateStyle
            style1.FormatCode = "A"
            sl.SetColumnStyle(2, style1)
            '
            sl.SaveAs("D:\PEPE.xlsx")
            MessageBox.Show("fichero creado")
        End Sub
    End Class

    P.D.

    Crea un fichero D:\PEPE.xlsx en blanco para ver los estilo creados

    Un saludo desde Bilbo
    Carlos


    miércoles, 22 de junio de 2016 22:32
  • Hola Carlos:

    Buenos días y gracias como siempre por ayudarme.

    Bueno, no encuentro la referencia SpreadsheetLight por ninguna parte en el buscador de referencias.

    Necesito instalar alguna cosa para tenerla, tu lo sabes?.

    Bueno, un  abrazo y voy a ver si la consigo.

    Gemma

    jueves, 23 de junio de 2016 5:35
  • Cralos, ya la he descargado desde la web oficial de SpreadsheetLight.

    Vamos a por ello.

    Gemma

    jueves, 23 de junio de 2016 6:02
  • Hola Carlos:

    Tu sabes por qué da este error al pulsar el botón:

    Excepción no controlada del tipo 'System.IO.FileNotFoundException' en SpreadsheetLight.dll

    Información adicional: No se puede cargar el archivo o ensamblado 'DocumentFormat.OpenXml, Version=2.0.5022.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' ni una de sus dependencias. El sistema no puede encontrar el archivo especificado.

    Este error me lo da en:

    Dim sl As New SLDocument("C:\PEPE.xlsx", "Sheet1")

    Ya he creado en la unidad C, el archivo PEPE.xlsx.

    Bueno Carlos sipuedes y sabes porqué me da el error, me lo indicas

    Un abrazo y gracias como siempre.

    Gemma

    jueves, 23 de junio de 2016 9:04
  • "gemma_campillo" preguntó:

    > Tu sabes por qué da este error al pulsar el botón:
    >
    > Excepción no controlada del tipo 'System.IO.FileNotFoundException' en SpreadsheetLight.dll
    >
    > Información adicional: No se puede cargar el archivo o ensamblado 'DocumentFormat.OpenXml,
    > Version=2.0.5022.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' ni una de sus dependencias. El
    > sistema no puede encontrar el archivo especificado.
    >
    > Este error me lo da en:
    > Dim sl As New SLDocument("C:\PEPE.xlsx", "Sheet1")
    >
    > Ya he creado en la unidad C, el archivo PEPE.xlsx.

    Entiendo que ese error no tiene nada que ver con que exista o no un archivo llamado PEPE.xlsx en la raíz de la unidad C:, más bien con que no tienes instalada en tu equipo el Open XML SDK 2.0 for Microsoft Office, que parece ser que es utilizado por el ensamblado SpreadsheetLight.dll.

    Desde el siguiente enlace podrás descargar el SDK correspondientes a la versión 2.0 y 2.5:

    Open XML SDK 2.0 for Microsoft Office

    Open XML SDK 2.5 for Microsoft Office

    Ni que decir tiene que si vas a utilizar en tu proyecto la biblioteca SpreadsheetLight, también tendrás que instalar en los equipos cliente la versión del SDK de Open XML que vayas a utilizar.

    Siento decirte que no he utilizado ninguno de los SDKs indicados, por lo que ignoro por completo si solamente puedes distribuir con tu proyecto el ensamblado DocumentFormat.OpenXml.dll, que por el mensaje de error que describes, parece ser que no la tienes referenciada en tu proyecto.

    Y dicho esto, te pregunto: ¿no crees que ya son demasiados paquetes de instalación los que tienen que instalar tus clientes? Si estos disponen de Microsoft Excel, ¿por qué no utilizas la biblioteca de Microsoft Excel mediante reflexión para ejecutar el código que te ha indicado Javier Jiménez? De ésta manera te ahorras tener que referenciar explícitamente en tu proyecto la biblioteca de Excel, ya que en tiempo de ejecución se utilizará aquella versión que tenga instalada el cliente en su equipo.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 junio de 2016 14:50
    Moderador
  • Hola Enrique:

    Gracias por todo. No voy a ponerlo porque no me gusta nada tener que añadir mas complementos como tu indicas, aparte esa librería yo no la tenía en mi ordenador, la he descargado de su página oficial SpreadsheetLight.

    No me quiero liar mas, voy a ver si tal como indicas el de Javier me funciona y si no me va, lo dejo como está que me va perfecto con las 3 bases de datos: Access, sql express y la compact y no me lío más, porque si no, no acabo esto y tengo que sacarlo el lunes como sea.

    Bueno maestro, voy a ver si tengo un rato y me meto con lo de Javier tal como indicas. Hoy esto es una fiesta, parece que todo el mundo le ha dado por preguntar (hablo de mi persona).

    Bueno genio, un fuerte abrazo.

    Gemma

    jueves, 23 de junio de 2016 15:14
  • "gemma_campillo" escribió:

    > No me quiero liar mas, voy a ver si tal como indicas el de Javier me funciona ...

    ¡Bueno! Anteriormente te he comentado que ejecutaras el código que te ha indicado Javier pero mediante REFLEXIÓN, para que NO TENGAS que referenciar en tu proyecto la biblioteca de Microsoft Excel y no tener que depender de ésta o aquella versión, porque la versión que se utilizará es la que tenga instalada y debidamente registrada el cliente en su equipo.

    Para ello, copia en tu proyecto la siguiente clase que he preparado en exclusiva para ti, aunque muchos procedimientos compartidos (Shared) los podrías aprovechar para otros trabajos que desees ejecutar también mediante reflexión:

    Option Strict On
    Imports System.Reflection
    
    ''' <summary>
    ''' Clase para interactuar con la biblioteca de objetos
    ''' de Microsoft Excel mediante reflexión, por lo que
    ''' no es necesario referenciarla en nuestro proyecto.
    ''' </summary>
    Friend NotInheritable Class ObjectExcel
    
        Implements IDisposable
    
        Private m_app As Object         ' Objeto Excel.Application (Aplicación Excel)
        Private m_books As Object       ' Objeto Excel.Workbooks (Colección de libros de trabajo)
        Private m_wb As Object          ' Objeto Excel.Workbook (Libro de trabajo)
    
        Private missing As Missing = Missing.Value
    
    #Region "Constructores"
    
        ''' <summary>
        ''' Crea una nueva instancia de la clase con la ruta
        ''' del libro de Excel especificada.
        ''' </summary>
        ''' <param name="fileName">Ruta completa del archivo de Excel.</param>
        Public Sub New(fileName As String)
    
            ' Creamos una nueva instancia del objeto Application.
            m_app = CreateExcelApplication()

    ' Si procede, hacemos visible la instancia de Microsoft Excel. ' SetProperty(m_wb, "Visible", True, Nothing) ' Referenciamos la colección de libros. m_books = GetProperty(m_app, "Workbooks", Nothing) ' Abrimos el libro de trabajo. Dim args(14) As Object args(0) = fileName For n As Integer = 1 To 14 ' Establecer el valor Missing.Value a los 14 ' restantes parámetros opcionales del método ' Open. args(n) = missing Next m_wb = ExecuteMethod(m_books, "Open", args, False) End Sub #End Region #Region "Métodos públicos" ''' <summary> ''' Abre el libro de trabajo especificado devolviendo el ''' envoltorio de un objeto Excel.Workbook. ''' </summary> ''' <param name="nombreHoja">Nombre de la hoja de cálculo.</param> ''' <param name="rangoColumna">Rango de la columna cuyo formato de ''' celdas se desea establecer a Texto. Ejemplos: "A:A" (para la ''' primera columna), "B:C" (para la segunda y tercera columnas).</param> Public Sub SetFormatText(nombreHoja As String, rangoColumna As String) Dim sheets As Object = Nothing ' Objeto Excel.Sheets (Colección de hojas de cálculo) Dim ws As Object = Nothing ' Objeto Excel.Worksheet (Hoja de cálculo) Dim range As Object = Nothing ' Objeto Excel.Range Try ' Referenciamos la colección de hojas de cálculo. ' sheets = GetProperty(m_wb, "Sheets", Nothing) ' Referenciamos la hoja de cálculo especificada. ' ws = GetProperty(sheets, "Item", New Object() {nombreHoja}) ' Referenciamos el rango de celdas correspondientes a la columna especificada ' range = GetProperty(ws, "Range", New Object() {rangoColumna}) ' Seleccionamos el rango ExecuteMethod(range, "Select", Nothing, True) ' Establecemos el formato de texto a las celdas. SetProperty(range, "NumberFormat", "@", Nothing) ' Liberar la referencia al objeto Excel.Range. FinalReleaseComObject(range) ' Referenciamos la primera celda de la hoja de cálculo. range = GetProperty(ws, "Range", New Object() {"A1:A1"}) ' Seleccionamos el rango ExecuteMethod(range, "Select", Nothing, True) Catch ex As Exception ' Se ha producido una excepción. Si procede, indicamos ' que el libro ya ha sido guardado. ' If (Not m_wb Is Nothing) Then SetProperty(m_wb, "Saved", True, Nothing) End If ' Devolver la excepción al procedimiento llamador ' Throw Finally ' Liberar las referencias de los distintos objetos utilizados. FinalReleaseComObject(range) FinalReleaseComObject(ws) FinalReleaseComObject(sheets) End Try End Sub #End Region #Region "Métodos privados." #Region "CreateExcelApplication" ''' <summary> ''' Devuelve una instancia de la clase Excel.Application. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function CreateExcelApplication() As Object Dim ty As Type = CreateType("Excel.Application") ' Creamos la instancia del tipo de objeto especificado. ' Dim flags As BindingFlags = ObjectExcel.BindingFlagsInstance() Dim obj As Object = Activator.CreateInstance(ty, flags, Nothing, Nothing, Nothing, Nothing) If (obj Is Nothing) Then Throw New ArgumentException("No es un objeto válido.") End If Return obj End Function #End Region #Region "CreateType" ''' <summary> ''' Devuelve una instancia de la clase WrappedComObject que envuelve ''' un nuevo objeto COM con el ProgId especificado. ''' </summary> ''' <param name="progId">ProgId del componente COM que se desea referenciar.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function CreateType(progId As String) As Type If (progId Is Nothing) Then Throw New ArgumentNullException("progId") End If ' Obtenemos el tipo asociado al identificador de programa ' (ProgID) especificado. ' Dim ty As Type = Type.GetTypeFromProgID(progId, False) If (ty Is Nothing) Then Throw New Runtime.InteropServices.COMException("Clase no válida o no registrada.") End If Return ty End Function #End Region #Region "BindingFlagsInstance" ''' <summary> ''' Devuelve los indicadores por defecto que se utilizarán para controlar ''' el enlace y la manera en la que se realiza la búsqueda de miembros ''' pertenecientes a una instancia de un objeto. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function BindingFlagsInstance() As BindingFlags Return BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.FlattenHierarchy End Function #End Region #Region "ExecuteMethod" ''' <summary> ''' Ejecuta el método de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya método se desea ejecutar.</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> ''' <param name="ignoreReturn">true si el método no devuelve un valor o si se puede ''' ignorar el valor devuelto; false en caso contrario.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function ExecuteMethod(obj As Object, methodName As String, args As Object(), ignoreReturn As Boolean) As Object Dim flags As BindingFlags = BindingFlags.InvokeMethod If (ignoreReturn) Then flags = flags Or BindingFlags.IgnoreReturn End If If (Not obj Is Nothing) Then ' Ejecutar el método de instancia. flags = flags Or ObjectExcel.BindingFlagsInstance() Return InvokeMember(obj, Nothing, methodName, flags, args, Nothing, Nothing) End If Return Nothing End Function #End Region #Region "GetProperty" ''' <summary> ''' Obtiene el valor de la propiedad del objeto o tipo de dato especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya propiedad se desea leer.</param> ''' <param name="propertyName">Nombre de la propiedad.</param> ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function GetProperty(obj As Object, propertyName As String, index As Object()) As Object Dim flags As BindingFlags = BindingFlags.GetProperty If (Not obj Is Nothing) Then ' Leer el valor de una propiedad de instancia. flags = flags Or BindingFlagsInstance() Return InvokeMember(obj, propertyName, flags, index) End If Return Nothing End Function #End Region #Region "FinalReleaseComObject" ''' <summary> ''' Libera todas las referencias a un contenedor RCW (Contenedor al que ''' se puede llamar en tiempo de ejecución) estableciendo su recuento ''' de referencias en 0. ''' </summary> ''' <param name="obj">Objeto RCW que se va a liberar.</param> ''' <remarks></remarks> Private Shared Sub FinalReleaseComObject(obj As Object) ' RCW = Runtime Callable Wrapper ' Una aplicación de Office no se cierra después de la automatización desde Visual Studio. NET ' Office application does not quit after automation from Visual Studio .NET client ' http://support.microsoft.com/kb/317109 If (Not obj Is Nothing) Then Try ' Se requiere .NET 2.0 o superior. System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj) Catch ' Deshechamos devolver la posible excepción ' si no es un objeto COM válido. Finally obj = Nothing End Try End If End Sub #End Region #Region "InvokeMember" ''' <summary> ''' Invoca el miembro de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param> ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía ''' ("") para llamar al miembro predeterminado.</param> ''' <param name="invokeAttr">Máscara de bits formada por una o varias enumeraciones ''' BindingFlags que especifican la forma en que se realiza la búsqueda.</param> ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al ''' miembro al cual se va a invocar.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function InvokeMember(obj As Object, name As String, invokeAttr As BindingFlags, args As Object()) As Object Return InvokeMember(obj, Nothing, name, invokeAttr, args, Nothing, Nothing) End Function ''' <summary> ''' Invoca el miembro de instancia del objeto especificado. ''' </summary> ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param> ''' <param name="ty">El tipo asociado al objeto donde debe invocarse el miembro especificado.</param> ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía ''' ("") para llamar al miembro predeterminado.</param> ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al ''' miembro al cual se va a invocar.</param> ''' <param name="modifiers">Matriz de objetos ParameterModifier que representan los ''' atributos asociados al elemento correspondiente de la matriz args.</param> ''' <param name="namedParameters">Matriz que contiene los nombres de los parámetros ''' a los que se pasan los valores de la matriz args.</param> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function InvokeMember(obj As Object, ty As Type, name As String, invokeAttr As BindingFlags, args As Object(), modifiers As ParameterModifier(), namedParameters As String()) As Object If (String.IsNullOrWhiteSpace(name)) Then Throw New MissingMemberException("El valor del miembro especificado no tiene un formato válido para convertirlo al tipo de dato requerido.") End If If (Not obj Is Nothing) Then ' Invocar el miembro de instancia especificado. Return obj.GetType().InvokeMember(name, invokeAttr, Nothing, obj, args, modifiers, Nothing, namedParameters) End If If (Not ty Is Nothing) Then ' Invocar el miembro estático especificado. Return ty.InvokeMember(name, invokeAttr, Nothing, Nothing, args, modifiers, Nothing, namedParameters) End If Throw New ArgumentNullException() End Function #End Region #Region "SetProperty" ''' <summary> ''' Establece el valor de la propiedad del objeto especificado. ''' </summary> ''' <param name="obj">Instancia del objeto cuya propiedad se desea establecer.</param> ''' <param name="propertyName">Nombre de la propiedad.</param> ''' <param name="newValue">El nuevo valor de la propiedad.</param> ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param> ''' <remarks></remarks> Private Shared Sub SetProperty(obj As Object, propertyName As String, newValue As Object, index As Object()) Dim flags As BindingFlags = BindingFlags.SetProperty Dim parameters As Object() = Nothing If (Not index Is Nothing) Then parameters = New Object(index.Length) {} For n As Integer = 0 To index.Length - 1 parameters(n) = index(n) Next parameters(index.Length) = newValue Else parameters = New Object() {newValue} End If If (Not obj Is Nothing) Then ' Leer el valor de una propiedad de instancia. flags = flags Or BindingFlagsInstance() InvokeMember(obj, propertyName, flags, parameters) End If End Sub #End Region #Region "Soporte para IDisposable" ' Para detectar llamadas redundantes Private disposedValue As Boolean ' IDisposable Private Sub Dispose(disposing As Boolean) If (Not disposedValue) Then If (disposing) Then ' Elimine el estado administrado (objetos administrados). ' If (Not m_wb Is Nothing) Then ' Guardamos los cambios. ExecuteMethod(m_wb, "Save", Nothing, True) ' Cerramos el libro. ExecuteMethod(m_wb, "Close", Nothing, True) End If If (Not m_books Is Nothing) Then ExecuteMethod(m_books, "Close", Nothing, True) End If If (Not m_app Is Nothing) Then ExecuteMethod(m_app, "Quit", Nothing, True) End If End If ' Libere los recursos no administrados (objetos no administrados) y reemplace Finalize() . ' FinalReleaseComObject(m_wb) FinalReleaseComObject(m_books) FinalReleaseComObject(m_app) End If disposedValue = True End Sub Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region #End Region End Class

    Insisto que con ésta clase no necesitas referenciar en tu proyecto ninguna biblioteca para trabajar con Excel, ni de Microsoft ni de terceras partes, pero el cliente sí tendrá que tener instalada una versión de Excel para que funcione.

    Ahora, cuando desees establecer el formato de Texto a las celdas correspondientes a la primera columna de un libro de Excel cualquiera, simplemente ejecutarías el siguiente código:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using app As New ObjectExcel(IO.Path.Combine(Application.StartupPath, "Libro1.xlsx"))
                    app.SetFormatText("Hoja1", "A:A")
                End Using
    
                MessageBox.Show("Se ha establecido satisfactoriamente el formato Texto a la columna.")
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Ni que decir tiene que éste código lo tendrás que ejecutar ANTES de exportar los datos de Excel a la base de datos que corresponda, es decir, ANTES de rellenar un objeto DataTable o recorrer un objeto DataReader, para que el ISAM de Excel puede leer correctamente los datos de la dichosa columna.

    Fíjate que creamos la instancia de la clase ObjectExcel especificando la ruta del libro de Excel, en el ejemplo, se supone que Libro1.xlsx se encuentra en la misma carpeta que contiene el ejecutable de nuestra aplicación, y la encerramos entre un bloque Using ... End Using (¡vamos! ¡como si fuera un objeto OleDbConnection!) para que se destruyan automáticamente los diferentes objetos de Excel que se han utilizado, a fin de que el proceso de Excel no se quede "colgado" en ejecución.

    Y para establecer el formato de Texto a una columna, tan solo tienes que especificar el nombre de la hoja de cálculo (Hoja1) y el rango de las celdas. Con el rango "A:A", el formato se aplicará a todas las celdas de la primera columna (A). Si no ese el rango que deseas, eres libre de especificar el que creas conveniente. Por ejemplo, si deseas establecer el formato a las filas comprendidas entre la 2 y la 10 (ambas inclusive) de la primera columna, especificarías el rango "A2:A10".

    En fin, espero que disfrutes de la clase ObjectExcel, y de camino, aprendas cómo se utiliza la reflexión en el marco de trabajo de .NET. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 junio de 2016 18:44
    Moderador
  • Enrique:

    Eres mas cabezón que yo, que ya es decir

    Bueno, ante todo infinitas gracias como siempre, pero me jode que te hayas tomado toda esa molestia en hacerme otro infinitésimo favor, pero, eres como eres, un perfeccionista. Te he de decir que había habandonado el tema, porque incluso la de Javier me estaba dando errores y al final he dicho que les pongo en la ayuda una coletilla por la que tienen que formatear dicha columnas. El problema surge porque no leen nada y entonces a llamar por teléfono que es lo más fácil. Pero bueno, eso no lo podemos cambiar, por ello, he tratado en este programa de dar la máxima información para que no mareen.Por todo ello, entre lo que queda de hoy y mañana, ya quiero dejar listo el tema de la sql server express, ya tengo varios links que me habloan de ello, total para ver como va en remoto, como se adjunta la base de datos, como se hace copia de la misma por código y alguna tontería mas, pero con eso, ya está todo repasado y funciona de película, ya verás el mismo esta semana que entra.

    Bueno maestro y amigo, te agradezco otra vez infinitamente el tiempo que me dedicas, a ver si algún día te puedo devolver parte del mismo.

    Enrique te mando un fuerte abrazo y gracias de corazón como siempre.

    Gemma

    jueves, 23 de junio de 2016 20:39
  • "gemma_campillo" escribió:

    > Te he de decir que había habandonado el tema, porque incluso la de Javier
    > me estaba dando errores y al final he dicho que les pongo en la ayuda una
    > coletilla por la que tienen que formatear dicha columnas ...

    Pero, ¿has probado el código de la clase que publiqué? Creo que con ella tienes el asunto resuelto para formatear a Texto las celdas de un rango de celdas de Excel, y lo más IMPORTANTE, sin tener que referenciar en tu proyecto la biblioteca de Microsoft Excel.

    > El problema surge porque no leen nada y entonces a llamar
    > por teléfono que es lo más fácil.

    Pues con ese código te puedes ahorrar esas llamadas telefónicas, al menos en lo que concierne al formateo de las celdas. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 6:18
    viernes, 24 de junio de 2016 6:00
    Moderador
  • Hola Enrique, buenos días.

    Estoy trabajando con tu código, como era de esperar o como siempre. Lo de abandonar el tema era antes de tu código.

    Tengo un problema causado por mí, en la aplicación de la ruta de la hoja, ya que me da error en la clase de: Se produjo una excepción en el destino de la invocación.

    If (Not obj Is Nothing) Then ' Invocar el miembro de instancia especificado. Return obj.GetType().InvokeMember(name, invokeAttr, Nothing, obj, args, modifiers, Nothing, namedParameters) End If Y eso pasa, porque la hoja la busca el usuario mediante un OpenDialog, es decir, no está fija en la carpeta del

    ejecutable, sino que el, normalmente la tiene en mis documentos.

    Bueno, ahora te muestro como lo he dejado porque para mi todo el error está en lo comentado, lo estoy haciendo mal, y estoy centrada ahora en solucionarlo.

    Para que veas como queda todo el proceso, te lo pongo porque si no, siempre falta algún if, etc, ya que te lo doy recortado.

    Aquí llamo al botón importar:

      Private Sub btnImpexcel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImpexcel.Click
            Dim a As Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly
            Dim rm As New ResourceManager(a.GetName.Name & ".Textos", a)
    
            If VarGlobal.StrPlanConta = "PLAN 2007" Then
                If VarGlobal.StrCodEmpresa = "001" Or VarGlobal.StrCodEmpresa = "002" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation) '¡No está permitido importar datos en la empresa de ejemplo!" & vbCrLf & _
                    '"En caso de querer operar con la importación, puede crear una empresa " & vbCrLf & _
                    '"y ver la operativa de la importación en dicha empresa.
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "FISCAL" Then
                If VarGlobal.StrCodEmpresa = "003" Or VarGlobal.StrCodEmpresa = "004" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "ENTPUB_10" Then
                If VarGlobal.StrCodEmpresa = "005" Or VarGlobal.StrCodEmpresa = "006" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "COLOMBIA" Then
                If VarGlobal.StrCodEmpresa = "57A" Or VarGlobal.StrCodEmpresa = "57M" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "PAISES" Then
                If VarGlobal.StrCodEmpresa = "100" Or VarGlobal.StrCodEmpresa = "101" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
            End If
    
            Using ofd As New System.Windows.Forms.OpenFileDialog
                With ofd
                    .Multiselect = False
                    .Filter = "Archivos de Excel (*.xls; *.xlsx)|*.xls;*.xlsx"
                    .CheckFileExists = True
                End With
    
                If ofd.ShowDialog = System.Windows.Forms.DialogResult.OK Then Importar(ofd.FileName, ofd.SafeFileName)
    
            End Using
    
        End Sub


    Aquí un a vez escogida la hoja, procedo a la importación y es aquí donde lo marco en negrita que creo que lo tengo mal, ya que tu me pones la hoja en la carpeta del ejecutable y yo no la tengo ah´ñi, pero se ve, que lo estoy aplicando mal, voy a centrarme en ello.

     Private Function NombrePrimeraHoja(ByVal cnx As System.Data.OleDb.OleDbConnection) As String
            NombrePrimeraHoja = "Hoja1$"
            Using sch As System.Data.DataTable = cnx.GetSchema("Tables")
                For Each fil As System.Data.DataRow In sch.Rows
                    For Each col As System.Data.DataColumn In sch.Columns
                        If col.ColumnName.Equals("TABLE_NAME") Then Return DirectCast(fil.Item(col), String)
                    Next col
                Next fil
            End Using
        End Function
    
       
        Private Sub Importar(ByVal rut As String, ByVal ruc As String)
          
            ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
            Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
            Dim noi As New System.Text.StringBuilder
    
    
            Try
    
                
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    cnn.Open()
    
                    'Conexión Excel
                    Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")
    
                        cnx.Open()
    
                        Dim hoj As String = NombrePrimeraHoja(cnx)
    
                        Using app As New ObjectExcel(IO.Path.Combine("hoj"))
                            app.SetFormatText("hoj", "A:A")
                        End Using
    
                        Using cmdx As New OleDb.OleDbCommand("SELECT * FROM [" & hoj & "]", cnx)
                            Using dr As OleDb.OleDbDataReader = cmdx.ExecuteReader(CommandBehavior.SingleResult)
                                If dr.HasRows Then
                                    Dim fil As Integer = 1I
                                    Dim tot As Integer = 0I
                                    Dim ccc As String = String.Empty
    
                                    Cursor = Cursors.WaitCursor
    
                                    VarGlobal.bolActivadoCuadroContable = True
                                    Dim frmPreparandoInforme = New frmPreparandoInforme
                                    frmPreparandoInforme.Show()
    
                                    Application.DoEvents()
    
                                    While dr.Read
                                        fil += 1I
                                        If dr.IsDBNull(0I) Then
                                            noi.AppendFormat("NULL (fila {0:N0}){1}", fil, Environment.NewLine)
                                        ElseIf dr.FieldCount.Equals(13I) Then '------ Estamos importando 12 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
    
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5, Ejer_06 = @ej6, Ejer_07 = @ej7, Ejer_08 = @ej8, Ejer_09 = @ej9, Ejer_10 = @e10, Ejer_11 = @e11, Ejer_12 = @e12 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Clear()
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej6", dr.GetDouble(6I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej7", dr.GetDouble(7I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej8", dr.GetDouble(8I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej9", dr.GetDouble(9I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e10", dr.GetDouble(10I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e11", dr.GetDouble(11I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e12", dr.GetDouble(12I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(6I) Then '------ Estamos importando 5 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(5I) Then '------ Estamos importando 4 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(4I) Then '------ Estamos importando 3 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(3I) Then '------ Estamos importando 2 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(2I) Then '------ Estamos importando 1 ejercicio
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET " & dr.GetName(1I) & " = @ej1 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
                                        End If
    
                                        cmd.Parameters.Clear()
                                    End While
    
                                    frmPreparandoInforme.Close()
    
                                    CargaDatagridView1()
    
                                    'Dim Cód_GC As String
    
                                    If noi.Length.Equals(0I) Then
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "»", Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    Else
                                        'Dim msg As String = String.Format("Importación finalizada.{0}Se han importado {1} filas del archivo «{2}» con el código contable {3}", Environment.NewLine, tot.ToString("N0"), ruc, & 'Cód_GC')
                                        'MessageBox.Show(msg, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "». Las siguientes cuentas no han sido importadas:" & Environment.NewLine & Environment.NewLine & noi.ToString, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    End If
                                Else
                                    System.Windows.Forms.MessageBox.Show("La hoja de cálculo «" & hoj & "» no contiene datos para importar", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                                End If
                                dr.Close()
    
                                Cursor = Cursors.Default
    
                            End Using
                        End Using
    
                    End Using
                End Using
    
                bolCambiosDatagridView = True 'Para activar la carga de fórmulas.
                CuadreBalances()
    
            Catch ex As Exception
                MsgBox(ex.Message)
    
            End Try
        End Sub

    No se si será mejor poner el procedimiento que me indicastes para llamar a la clase ObjectExcel, fuera del "Importar". Bueno, ese el problemilla que pasa.

    De todas formas y aparte de esto, la clase creada es una pasada aunque se que me tengo que poner a estudiar el objeto Excel ya que al no usarlo, no me he metido con ello,  solo lo uso aquí en la importación, pero creo a priori que sus ventajas en esta aplicación puede ser varias.

    Maestro, muchas gracias por todo y si puedes mira a ver la burrada que he hecho con la ruta y la hoja, discúlpame.

    Un abrazo.

    Gemma


    • Editado gemma_campillo viernes, 24 de junio de 2016 6:34 ortogrsafí
    viernes, 24 de junio de 2016 6:33
  • "gemma_campillo" escribió:

    > Tengo un problema causado por mí, en la aplicación de la ruta de la hoja, ya
    > que me da error en la clase de: Se produjo una excepción en el destino de la
    > invocación.

    Si la firma del procedimiento Insertar es la siguiente:

        Private Sub Importar(ByVal rut As String, ByVal ruc As String)

    donde se supone que el primer parámetro ('rut') contiene la ruta del archivo de Excel seleccionado por el usuario, crearías la instancia de la clase ObjectExcel pasándole dicha ruta:

        Using app As New ObjectExcel(rut)
            app.SetFormatText("hoj", "A:A")
        End Using

    Lo de "IO.Path.Combine(Application.StartupPath, "Libro1.xlsx"))" lo puse como ejemplo, pero al constructor de la clase ObjectExcel simplemente le tienes que pasar la ruta completo del archivo de Excel que vas a utilizar.

    Se comprende que "hoj" es el nombre de la hoja de cálculo donde deseas modificar el formato de las celdas de la columna A. ¿Ese es el nombre correcto de la hoja de cálculo? ¿"hoj"? ¿O por casualidad se llama Hoja1, Hoja2 o Balance? Desde luego, al procedimiento SetFormatText le tienes que pasar el NOMBRE EXACTO DE LA HOJA, sin el carácter $.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 6:59
    viernes, 24 de junio de 2016 6:47
    Moderador
  • Hola Enrique:

    Continúa el mismo error. La variable "hoj" proviene del procedimiento:

      Private Function NombrePrimeraHoja(ByVal cnx As System.Data.OleDb.OleDbConnection) As String
            NombrePrimeraHoja = "Hoja1$"
            Using sch As System.Data.DataTable = cnx.GetSchema("Tables")
                For Each fil As System.Data.DataRow In sch.Rows
                    For Each col As System.Data.DataColumn In sch.Columns
                        If col.ColumnName.Equals("TABLE_NAME") Then Return DirectCast(fil.Item(col), String)
                    Next col
                Next fil
            End Using
        End Function
    
       
        Private Sub Importar(ByVal rut As String, ByVal ruc As String)
          
            ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
            Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
            Dim noi As New System.Text.StringBuilder
    
    
            Try
               
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    cnn.Open()
    
                    'Conexión Excel
                    Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")
    
                        cnx.Open()
    
                        Dim hoj As String = NombrePrimeraHoja(cnx)
                        Using app As New ObjectExcel(rut)
                            app.SetFormatText("hoj", "A:A")
                        End Using
    
                        Using cmdx As New OleDb.OleDbCommand("SELECT * FROM [" & hoj & "]", cnx)
                            Using dr As OleDb.OleDbDataReader = cmdx.ExecuteReader(CommandBehavior.SingleResult)
                                If dr.HasRows Then
                                    Dim fil As Integer = 1I
                                    Dim tot As Integer = 0I
                                    Dim ccc As String = String.Empty

    No se si estoy haciéndolo mal, pero es como creo que tendría que ir.

    Bueno, a seguir a ver que pasa.

    Un abrazo.

    Gemma


    viernes, 24 de junio de 2016 7:01
  • "gemma_campillo" escribió:

    > Continúa el mismo error. La variable "hoj" proviene del procedimiento:
    >

    Efectivamente, la variable hoj (sin comillas dobles) contiene el valor devuelto por la función NombrePrimeraHoja:

        Dim hoj As String = NombrePrimeraHoja(cnx)

    Pero fíjate cómo estás llamando al procedimiento SetFormatText:

        app.SetFormatText("hoj", "A:A")

    ¿Te das cuenta de lo que estás haciendo mal? En lugar de utilizar la variable hoj (sin comillas dobles), le estás pasando el valor "hoj" (con comillas dobles) al procedimiento SetFormatText, de ahí que obtengas la correspondiente excepción porque NO EXISTE en el libro de Excel una hoja de cálculo llamada "hoj".

    Tienes que quitar las comillas dobles:

        Dim hoj As String = NombrePrimeraHoja(cnx)
        Using app As New ObjectExcel(rut)
            app.SetFormatText(hoj, "A:A")
        End Using

    ¡Ay, ay!  ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.


    viernes, 24 de junio de 2016 7:19
    Moderador
  • Hola Enrique:

    Ya está corregido  ¡Ay, ay!  ;-), pero continúa dando el error. El error lo da porque haciendo un seguimiento del nombre de la hoja de Excel que es: 5ejerSqlEx.xlsx, lo transforma en 5ejerSqlEx$.xlsx, que es el nombre que le doy a la hoja cuando declaro la variable "NombrePrimeraHoja" en la función.

     Private Function NombrePrimeraHoja(ByVal cnx As System.Data.OleDb.OleDbConnection) As String
            NombrePrimeraHoja = "Hoja1$"
            Using sch As System.Data.DataTable = cnx.GetSchema("Tables")
                For Each fil As System.Data.DataRow In sch.Rows
                    For Each col As System.Data.DataColumn In sch.Columns
                        If col.ColumnName.Equals("TABLE_NAME") Then Return DirectCast(fil.Item(col), String)
                    Next col
                Next fil
            End Using
        End Function

    Ahora bien, si le saco el "$", a la hoja: "Hoja1$", continúa reconociendo como nombre de hoja: 5ejerSqlEx$.xlsx, por lo tanto voy a ver porque arrastra el $ ya que entonces reconoce que la hoja no existe, de ahí el error ya que el nombre de la hoja es: 5ejerSqlEx.xlsx

    Bueno maestro ya está localizado y voy a intentar corregirlo.

    Un abrazo.

    Gemma

    viernes, 24 de junio de 2016 7:46
  • "gemma_campillo" escribió:

    > Ya está corregido  ¡Ay, ay!  ;-), pero continúa dando el error. El error
    > lo da porque haciendo un seguimiento del nombre de la hoja de Excel que es:
    > 5ejerSqlEx.xlsx, lo transforma en 5ejerSqlEx$.xlsx, que es el nombre que
    > le doy a la hoja cuando declaro la variable "NombrePrimeraHoja" en la función.

    Y continuaras obteniendo el error por los siglos de los siglos hasta que no le pases al procedimiento el nombre de una hoja (sin el carácter $) existente en el libro.

    > por lo tanto voy a ver porque arrastra el $ ya que entonces reconoce que
    > la hoja no existe, de ahí el error ya que el nombre de la hoja es: 5ejerSqlEx.xlsx

    Lo primero que tienes que hacer es verificar el nombre que devuelve la función NombrePrimeraHoja, que puede que ésta te devuelva el nombre de la hoja con el carácter $, ya que dicho carácter SÍ ES NECESARIO para que el ISAM de Excel pueda recuperar un conjunto de datos mediante una consulta SQL de selección, como por ejemplo "SELECT * FROM [Hoja1$]".

    Una vez que el nombre de la hoja sea correcto, tan solo tienes que eliminar el carácter $ ANTES de llamar al procedimiento SetFormatText de la clase ObjectExcel.

    Pero lo que me resulta bastante extraño es que la función NombrePrimeraHoja te devuelva el valor "5ejerSqlEx$.xlsx". Eso lo tengo que ver con mis propios ojos.

    Fíjate cómo llamas al procedimiento Importar:

        If ofd.ShowDialog = System.Windows.Forms.DialogResult.OK Then
            Importar(ofd.FileName, ofd.SafeFileName)
        End If

    ¿De donde sale el valor "5ejerSqlEx$.xlsx"? ¿No será de aquel que devuelve la propiedad SafeFileName del objeto OpenFileDialog? Verifica si es así.

    Por cierto, ¿para qué utilizas el valor de la propiedad SafeFileName?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 9:37
    viernes, 24 de junio de 2016 8:12
    Moderador
  • Hola Enrique:

    Lamento darte la tabarra con esta historia a priori simple, pero no salgo. Vamos aver si me centro en lo que me preguntas:

    1) La propiedad SafeFileName devuelve: 5ejerSqlEx.xlsx

    2) El nombre de la  NombrePrimeraHoja cuando entra en la función es: "Hoja1$"

    3) Cuando en el procedimiento "Importar"  crea la variable

    Dim Hoj as String = NombrePrimeraHoja(cnx) ahí lleva el valor: 5ejerSqlEx$.xlsx por lo tanto "Hoj" lleva ese valor.

    4) La ruta : Using App as New ObjectExcel(rut) lleva la ruta correctamente, acando en: 5ejerSqlEx.xlsx

    5) Lógicamente en el App.SetFormatText(hoj, "A:A") la variable "hoj" también lleva el valor: 5ejerSqlEx$.xlsx

    Por ello, trato de quitar el último dígito de la String Hoh y no hay manera, siempre me da el mismo resultado con el $.

        Dim MyChar() As Char = {CChar("$"), CChar(" ")}
    
                        Dim hoj As String = NombrePrimeraHoja(cnx).TrimEnd(MyChar)
    
                        Using app As New ObjectExcel(rut)
                            app.SetFormatText(hoj, "A:A")
    
                        End Using
    Bueno, el tema está ahí y voy a ir probando hasta que saque el carácter del $-

    Un abrazo maestro.

    Gemma

    viernes, 24 de junio de 2016 9:37
  • "gemma_campillo" escribió:

    > 1) La propiedad SafeFileName devuelve: 5ejerSqlEx.xlsx

    De verdad que no sé para qué quieres ese valor, cuando la ruta completa del archivo de Excel lo obtienes de la propiedad FileName del objeto OpenFileDialog, valor éste que es el que le pasas al primer parámetro del procedimiento Importar.

    > 2) El nombre de la  NombrePrimeraHoja cuando entra en la función es: "Hoja1$"

    De acuerdo. ¿Y cuando "sale"? ¿Qué valor devuelve la función NombrePrimeraHoja?

    > 3) Cuando en el procedimiento "Importar"  crea la variable
    >
    > Dim Hoj as String = NombrePrimeraHoja(cnx) ahí lleva el valor:
    >    5ejerSqlEx$.xlsx por lo tanto "Hoj" lleva ese valor.

    ¿Me estás diciendo que la función NombrePrimeraHoja devuelve el valor 5ejerSqlEx$.xlsx? Si eso es así, no creo yo que sea un nombre de hoja de cálculo válido, más bien se trata del nombre del archivo de Excel y su extensión, es decir, el valor devuelto por la propiedad SafeFileName del objeto OpenFileDialog.

    > 4) La ruta : Using App as New ObjectExcel(rut) lleva la ruta correctamente,
    > acando en: 5ejerSqlEx.xlsx

    No es así. Al constructor del objeto ObjectExcel tienes que especificarle LA RUTA COMPLETA del archivo de Excel, es decir, el valor del parámetro 'rut' del procedimiento Importar.

    > 5) Lógicamente en el App.SetFormatText(hoj, "A:A") la variable "hoj"
    > también lleva el valor: 5ejerSqlEx$.xlsx

    Te repito de nuevo que no creo que ese sea el nombre correcto de la hoja de cálculo.

    > Por ello, trato de quitar el último dígito de la String Hoh y no hay manera,
    > siempre me da el mismo resultado con el $.
    >
    >  Dim MyChar() As Char = {CChar("$"), CChar(" ")}

    ¡Vamos a ver! Obtienes el nombre de la primera hoja de cálculo ejecutando:

        Dim hoj As String = NombrePrimeraHoja(cnx)

    Ahora vamos a eliminar el carácter final $:

        Dim nombreHoja As String = hoj.Replace("$", "")

    Procedemos a formatear la columna A de la hoja de cálculo:

        Using app As New ObjectExcel(rut)
            app.SetFormatText(nombreHoja, "A:A")
        End Using

    La verdad es que no creía que ibas a tener tantos problemas para formatear la hoja de cálculo, porque solamente SON 3 LÍNEAS DE CÓDIGO las que tienes que ejecutar, pero ¡claro! Hay que pasarle los VALORES CORRECTOS, tanto al constructor de la clase ObjectExcel como al procedimiento SetFormatText. ¡Si fueran 20 líneas de código las que tienes que ejecutar no sé lo que harías entonces! :-))

    Para que compruebes que el método SetFormatText hace bien su trabajo, limítate a pasarle directamente la ruta completa del archivo de Excel y el nombre de una hoja de cálculo que sepas que existe en dicho archivo:

        Using app As New ObjectExcel("C:\Carpeta\Libro1.xlsx")
            app.SetFormatText("Hoja1", "A:A")
        End Using

    Una vez que hayas comprobado que el procedimiento hace bien su trabajo, entonces te "peleas" con los distintos valores devueltos por las funciones y variables que estás utilizando en tu código hasta que encuentres los valores CORRECTOS que tienes que especificar. :-))


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.






    viernes, 24 de junio de 2016 9:58
    Moderador
  • Enrique:

    Te estoy fastidiando el día como otras veces. Lo siento mucho. Me sabe mal pero no puedo evitarlo. Gracias.

    Bueno, ahora ya coge bien el nombre sin el símbolo del $. Hace dos pasadas por la clase ObjectExcel, la primera la pasa perfectamente pero en la segunda se queda otra colgada en el mismo error. He creado una imagen por si tienes tiempo te la miras y vuelvo a poner como queda la importación con esos arreglos que has hecho. Si no lo ves claro, tranquilo, no te encaparres que te conozco, no pasa nada.

    De cualquier manera esto es lo que te decía:

    Código para importar:

      Private Function NombrePrimeraHoja(ByVal cnx As System.Data.OleDb.OleDbConnection) As String
            NombrePrimeraHoja = "Hoja1$"
            Using sch As System.Data.DataTable = cnx.GetSchema("Tables")
                For Each fil As System.Data.DataRow In sch.Rows
                    For Each col As System.Data.DataColumn In sch.Columns
                        If col.ColumnName.Equals("TABLE_NAME") Then Return DirectCast(fil.Item(col), String)
                    Next col
                Next fil
            End Using
        End Function
    
        Private Sub Importar(ByVal rut As String, ByVal ruc As String)
    
            ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
            Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
            Dim noi As New System.Text.StringBuilder
    
            Try
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    cnn.Open()
    
                    'Conexión Excel
                    Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")
    
                        cnx.Open()
    
                        Dim nombreHoja As String = NombrePrimeraHoja(cnx).Replace("$", "")
    
                        Using app As New ObjectExcel(rut)
                            app.SetFormatText(nombreHoja, "A:A")
    
                        End Using
    
                        Using cmdx As New OleDb.OleDbCommand("SELECT * FROM [" & nombreHoja & "]", cnx)
                            Using dr As OleDb.OleDbDataReader = cmdx.ExecuteReader(CommandBehavior.SingleResult)
                                If dr.HasRows Then
                                    Dim fil As Integer = 1I
                                    Dim tot As Integer = 0I
                                    Dim ccc As String = String.Empty
    
                                    Cursor = Cursors.WaitCursor
    
                                    VarGlobal.bolActivadoCuadroContable = True
                                    Dim frmPreparandoInforme = New frmPreparandoInforme
                                    frmPreparandoInforme.Show()
    
                                    Application.DoEvents()
    
                                    While dr.Read
                                        fil += 1I
                                        If dr.IsDBNull(0I) Then
                                            noi.AppendFormat("NULL (fila {0:N0}){1}", fil, Environment.NewLine)
                                        ElseIf dr.FieldCount.Equals(13I) Then '------ Estamos importando 12 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
    
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5, Ejer_06 = @ej6, Ejer_07 = @ej7, Ejer_08 = @ej8, Ejer_09 = @ej9, Ejer_10 = @e10, Ejer_11 = @e11, Ejer_12 = @e12 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Clear()
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej6", dr.GetDouble(6I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej7", dr.GetDouble(7I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej8", dr.GetDouble(8I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej9", dr.GetDouble(9I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e10", dr.GetDouble(10I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e11", dr.GetDouble(11I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e12", dr.GetDouble(12I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(6I) Then '------ Estamos importando 5 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(5I) Then '------ Estamos importando 4 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(4I) Then '------ Estamos importando 3 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(3I) Then '------ Estamos importando 2 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(2I) Then '------ Estamos importando 1 ejercicio
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET " & dr.GetName(1I) & " = @ej1 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
                                        End If
    
                                        cmd.Parameters.Clear()
                                    End While
    
                                    frmPreparandoInforme.Close()
    
                                    CargaDatagridView1()
    
                                    'Dim Cód_GC As String
    
                                    If noi.Length.Equals(0I) Then
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "»", Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    Else
                                        'Dim msg As String = String.Format("Importación finalizada.{0}Se han importado {1} filas del archivo «{2}» con el código contable {3}", Environment.NewLine, tot.ToString("N0"), ruc, & 'Cód_GC')
                                        'MessageBox.Show(msg, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "». Las siguientes cuentas no han sido importadas:" & Environment.NewLine & Environment.NewLine & noi.ToString, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    End If
                                Else
                                    System.Windows.Forms.MessageBox.Show("La hoja de cálculo «" & nombreHoja & "» no contiene datos para importar", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                                End If
                                dr.Close()
    
                                Cursor = Cursors.Default
    
                            End Using
                        End Using
    
                    End Using
                End Using
    
                bolCambiosDatagridView = True 'Para activar la carga de fórmulas.
                CuadreBalances()
    
            Catch ex As Exception
                MsgBox(ex.Message)
    
            End Try
        End Sub

    Imagen del error:

    Bien, te lo agradezco como siempre pero no puede ser que estés destinando tanto tiempo a ayudarme.

    El "Brexit" también me ha contagiado a mi.

    Un fuerte abrazo.

    Gemma

    viernes, 24 de junio de 2016 10:41
  • Lo primero de todo: ¿has probado utilizar la clase ObjectExcel pasándole únicamente la ruta de un archivo de Excel con el nombre de una hoja de cálculo que de antemano sabes que existe?

        Try
            Using app As New ObjectExcel("C:\Carpeta\Libro1.xlsx")
                app.SetFormatText("Hoja1", "A:A")
            End Using
    
         Catch ex As Exception
             Dim msg As String = String.Empty
             If (ex.InnerException Is Nothing) Then
                 msg = ex.Message
             Else
                 msg = ex.InnerException.Message
             End If
      
             MessageBox.Show(msg)
    
         End Try

    A modo de prueba, éste código lo puedes ejecutar desde el evento Click de cualquier Button que tengas en un formulario cualquiera de tu aplicación.

    Por favor, es lo que quiero que me respondas de una vez, para ver si el procedimiento SetFormatText hace o no bien su trabajo. Simplemente es lo que quiero que me digas: SÍ o NO. ¿De acuerdo?

    "gemma_campillo" escribió:

    > Bueno, ahora ya coge bien el nombre sin el símbolo del $. Hace dos pasadas
    > por la clase ObjectExcel, la primera la pasa perfectamente pero en la segunda
    > se queda otra colgada en el mismo error.

    No observo el mensaje de error, aunque de producirse, el mensaje que por defecto devuelve poco nos va a decir, ya que en lugar de consultar la propiedad Message de un objeto Exception, tienes que consultar la propiedad Message pero del objeto InnerException existente en el objeto Exception.

          Try
             Importar( ... , ...)
    
          Catch ex As Exception
             Dim msg As String = String.Empty
             If (ex.InnerException Is Nothing) Then
                 msg = ex.Message
             Else
                 msg = ex.InnerException.Message
             End If
      
             MessageBox.Show(msg)
    
          End Try

    Ese es el mensaje de error que me gustaría conocer. De todas maneras, una vez que se detenga el código donde se produce el error (en la línea amarilla que aparece en la imagen que has publicado), ¿me podrías decir el valor que tiene la variable 'name' y los valores que tiene las matriz 'args'?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.



    viernes, 24 de junio de 2016 11:03
    Moderador
  • Hola Enrique:

    Vamos a ver te respondo en el orden que me has hecho las preguntas, pero si te sigo que no se si funciona porque no puedo abrir ninguna hoja de Excel, algo ha pasado, pero está todo que me da error al abrir el comando.

    Te ruego esperes porque lo mismo si funciona y al tener yo fastidiado el Excel da error.

    Te digo algo en cuanto pueda.

    Gemma

    viernes, 24 de junio de 2016 13:58
  • Hola maestro:

    Vamos a ver te respondo en el orden que me has hecho las preguntas:

    <<Lo primero de todo: ¿has probado utilizar la clase ObjectExcel pasándole únicamente la ruta de un archivo de Excel con el nombre de una hoja de cálculo que de antemano sabes que existe?>>

    SI, he puesto únicamente la tabla de Excel en el disco c:\ La reconoce perfectamente.

      Private Sub btnImpexcel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImpexcel.Click
                   Using app As New ObjectExcel("C:\5ejerSqlEx.xlsx")
                app.SetFormatText("Hoja1", "A:A")
            End Using
    End Sub

    Link de la hoja de excel

    2) <<Por favor, es lo que quiero que me respondas de una vez, para ver si el procedimiento SetFormatText hace o no bien su trabajo. Simplemente es lo que quiero que me digas: SÍ o NO. ¿De acuerdo?>> No, vuelve a quedarse colgada en el mismo sitio del cual te adjunto la imagen y responde a las preguntas de <<valor que tiene la variable 'name' y los valores que tiene las matriz 'args'?>>

    Bueno, maestro, insisto en que si no va no le des muchas vueltas, ya que es para ayudar al usuario despistado, pero incluso le pongo un Message box o un tooltip recordándole que de formato a la primera columna.

    Venga un fuerte abrazo y gracias como siempre.

    Gemma


    • Editado gemma_campillo viernes, 24 de junio de 2016 14:19 ampliar datos
    viernes, 24 de junio de 2016 14:17
  • "gemma_campillo" escribió:

    > SI, he puesto únicamente la tabla de Excel en el disco c:\ La reconoce perfectamente.

    Entonces el problema NO ES de la clase ObjectExcel, de hecho, he descargado el archivo de Excel y he establecido satisfactoriamente el formato Texto a la primera columna de la hoja de cálculo llamada 5ejerSqlEx del libro de trabajo llamado 5ejerSqlEx.xlsx. Pero para esto he tenido que hacer ciertas modificaciones que describo a continuación.

    > Bueno, maestro, insisto en que si no va no le des muchas vueltas, ya que es para ayudar
    > al usuario despistado, pero incluso le pongo un Message box o un tooltip recordándole
    > que de formato a la primera columna.

    El tema no es que sea para ayudar a los usuarios despistados; el tema consiste en si sabes qué es lo que realmente tienes que hacer para que a ti también te funcione correctamente como me funciona a mí.

    En primer lugar, ¿no has podido elegir otro nombre para la hoja de cálculo que no empiece por un número? Si tu nombras a una hoja con el nombre 5ejerSqlEx, vas a obtener un error en el procedimiento SetFormatText a la hora de referenciar dicha hoja, es decir, a la hora de ejecutar la siguiente línea:

        ' Referenciamos la hoja de cálculo especificada.
        '
        ws = GetProperty(sheets, "Item", New Object() {nombreHoja})

    porque si no lo sabes, te diré que cuando el nombre de una hoja de cálculo comienza por un número, como es tu caso, Microsoft Excel encierra el nombre entre comillas simples ('5ejerSqlEx'), por lo que la función NombrePrimeraHoja te devolverá el valor alfanumérico "'5ejerSqlEx$'", estando las comillas simples DENTRO DEL NOMBRE DE LA HOJA. Como posteriormente eliminas el carácter $, el nombre de la hoja de cálculo se queda en "'5ejerSqlEx'", siendo éste el nombre definitivo de la misma. ¿Ves bien las comillas simples dentro del valor alfanumérico encerrado entre comillas dobles?

    Normalmente, los nombres de las hojas de cálculo comienzan por una LETRA o por un guión bajo, no por un número, por lo que en éste caso no podrás referenciar la hoja de cálculo (un objeto Excel.Worksheet) mediante su nombre, por lo que tendrás que hacerlo por su índice en base 1.

    Obtener información acerca de las reglas de sintaxis de los nombres

    Sustituye en el procedimiento SetFormatText la línea anterior por ésta otra:

        ' Referenciamos la primera hoja de cálculo.
        '
        ws = GetProperty(sheets, "Item", New Object() {1})

    De ésta manera ya no te hace falta para nada el parámetro nombreHoja de dicho procedimiento, por lo que lo puedes eliminar de la firma:

       
    Public Sub SetFormatText(rangoColumna As String)

    Y por supuesto, tampoco hace falta ya que elimines el carácter $ del valor devuelto por la función NombrePrimeraHoja.

    Ahora, el código funcionará solamente para cambiar el formato de las celdas de la primera hoja del archivo de Excel, es decir, aquella que tenga en su colección de hojas el índice 1.

    No se por qué motivo, pero me da la sensación que todo el trabajo ha sido en balde. :-((


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.




    viernes, 24 de junio de 2016 15:13
    Moderador
  • Hola Enrique:

    Tu trabajo no se por qué te da la sensación de haber sido en balde. Yo creo que nunca es así, quizás si me haya faltado afinar cosas, ya que si desde el primer momento te envío la hoja, te hubieras ahorrado bastantes líneas o respuestas. No pienses así que seguro que te equivocas. La lecciones y el aprendizaje que se realiza con tus explicaciones no tienen precio, o sea, que cambia de pensamiento, cascarrabias.

    Bueno, yendo ya al asunto, funciona perfectamente y efectivamente veo la malditas comillas '  ' en el nombre, ahora si la sustituyo o mejor dicho le quito el 5, funciona perfectamente. Ese era el problema, pero yo no sabía el tema de que si empieza por número la hoja, el Excel la toma como alfanumérica.

    Bueno, maestro ya está arreglado y mira por donde ha servido para solucionar un problema de teléfono y de llamadas aunque tengas la sensación "que todo el trabajo ha sido en balde", piensa también la gente que no sabemos por lo menos de Excel, cuesta aprender la terminología y después lo demás. Con la clase que hicistes ayer es para pasarse un buen rato interpretando y entendiendo lo que hicistes, que es lo que quiero hacer en cuanto se acabe esto.

    Bueno maestro, muchas gracias por tu clase magistral y fuera tonterías.

    Un fuerte abrazo de tu amiga y alumna.

    Gemma

    viernes, 24 de junio de 2016 15:37
  • "gemma_campillo" escribió:

    Por si te decides finalmente a utilizar la clase ObjectExcel, te comento que para guardar los cambios en el archivo de Excel referentes al formato de las celdas, el archivo NO PUEDE ESTAR ABIERTO. Quiere esto decir que, si en tu procedimiento Importar abres una conexión para obtener el nombre de la primera hoja del archivo de Excel:

        'Conexión Excel
        Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")

        cnx.Open()

        Dim nombreHoja As String = NombrePrimeraHoja(cnx).Replace("$", "")

    NO PUEDES llamar inmediatamente al procedimiento SetFormatText de la clase ObjectExcel hasta que no cierres la conexión:

        ' Cerrar la conexión
        '
        cnx.Close()
    
        ' Dar formato a las celdas
        Using app As New ObjectExcel(rut)
            app.SetFormatText(nombreHoja, "A:A")
        End Using
    

    Y posteriormente abrirla de nuevo para que puedas abrir el lector de datos OleDbDataReader:

       
        cnx.Open()

    Quería comentarte esto ahora que el tema está "caliente", vaya a ser que el día de mañana te surja el problema y no sepamos ni por dónde viene.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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 viernes, 24 de junio de 2016 15:54
    viernes, 24 de junio de 2016 15:49
    Moderador
  • Hola maestro:

    Ves tu lo que estoy aprendiendo del Excel con tus explicaciones. Tomo nota de ello y la clase ObjectExcel te aseguro que la utilizo, sería una estúpida si después del curro que te has dado, fuera tan inconsciente de no utilizarla. Vamos por Dios.

    Venga aplico lo que me has dicho ahora y voy a rehacerla un poquito que está la pobre muy tocada, pero no hay problema.

    Gracias maestro.

    Gemma

    viernes, 24 de junio de 2016 15:54
  • "gemma_campillo" escribió:

    > voy a rehacerla un poquito que está la pobre muy tocada

    Copia/pega de nuevo el código fuente de la clase ObjectExcel (¿o mejor se tendría que llamar ExcelObject?), porque hace un rato la he modificado para que no aparezca la interfaz de usuario de Microsoft Excel, ya que ayer se me olvidó comentar la siguiente línea en el constructor de la clase (procedimiento Sub New):

            ' Si procede, hacemos visible la instancia de Microsoft Excel.
            ' SetProperty(m_wb, "Visible", True, Nothing)

    Si quitas el comentario, al usuario le aparecerá la interfaz de Excel, pero no creo que sea necesario hacerlo. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.


    viernes, 24 de junio de 2016 16:06
    Moderador
  • Maestro, si no te he entendido mal quieres que te ponga la clase, no?.

    Si es así, te pongo todo el tema de la importación como lo tengo ahora, he de retocar alguna cosilla pero ya pasa correctamente por la clase.

    'Metodos del form para importar

    :

      Private Sub btnImpexcel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImpexcel.Click
            Dim a As Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly
            Dim rm As New ResourceManager(a.GetName.Name & ".Textos", a)
    
            If VarGlobal.StrPlanConta = "PLAN 2007" Then
                If VarGlobal.StrCodEmpresa = "001" Or VarGlobal.StrCodEmpresa = "002" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation) '¡No está permitido importar datos en la empresa de ejemplo!" & vbCrLf & _
                    '"En caso de querer operar con la importación, puede crear una empresa " & vbCrLf & _
                    '"y ver la operativa de la importación en dicha empresa.
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "FISCAL" Then
                If VarGlobal.StrCodEmpresa = "003" Or VarGlobal.StrCodEmpresa = "004" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "ENTPUB_10" Then
                If VarGlobal.StrCodEmpresa = "005" Or VarGlobal.StrCodEmpresa = "006" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "COLOMBIA" Then
                If VarGlobal.StrCodEmpresa = "57A" Or VarGlobal.StrCodEmpresa = "57M" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
    
            ElseIf VarGlobal.StrPlanConta = "PAISES" Then
                If VarGlobal.StrCodEmpresa = "100" Or VarGlobal.StrCodEmpresa = "101" Then
                    MsgBox(rm.GetString("NoImportarEnDemo"), vbInformation)
                    Return
                End If
            End If
    
            Using ofd As New System.Windows.Forms.OpenFileDialog
                With ofd
                    .Multiselect = False
                    .Filter = "Archivos de Excel (*.xls; *.xlsx)|*.xls;*.xlsx"
                    .CheckFileExists = True
                End With
    
                If ofd.ShowDialog = System.Windows.Forms.DialogResult.OK Then Importar(ofd.FileName, ofd.SafeFileName)
    
            End Using
    
        End Sub
    
    
        Private Function NombrePrimeraHoja(ByVal cnx As System.Data.OleDb.OleDbConnection) As String
            NombrePrimeraHoja = "Hoja1$"
            Using sch As System.Data.DataTable = cnx.GetSchema("Tables")
                For Each fil As System.Data.DataRow In sch.Rows
                    For Each col As System.Data.DataColumn In sch.Columns
                        If col.ColumnName.Equals("TABLE_NAME") Then Return DirectCast(fil.Item(col), String)
                    Next col
                Next fil
            End Using
        End Function
    
        Private Sub Importar(ByVal rut As String, ByVal ruc As String)
    
            ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
            Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
            Dim noi As New System.Text.StringBuilder
    
            Try
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    cnn.Open()
    
                    'Conexión Excel
                    Using cnx As New OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & rut & ";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'")
    
                        cnx.Open()
    
                        Dim nombreHoja As String = NombrePrimeraHoja(cnx).Replace("$", "")
    
                        ' Cerrar la conexión para pooder formatear la primera columna
                        '
                        cnx.Close()
    
                        ' Dar formato a las celdas
                        Using app As New ObjectExcel(rut)
                            app.SetFormatText("A:A")
                        End Using
    
                        cnx.Open()
    
                        Using cmdx As New OleDb.OleDbCommand("SELECT * FROM [" & nombreHoja & "]", cnx)
                            Using dr As OleDb.OleDbDataReader = cmdx.ExecuteReader(CommandBehavior.SingleResult)
                                If dr.HasRows Then
                                    Dim fil As Integer = 1I
                                    Dim tot As Integer = 0I
                                    Dim ccc As String = String.Empty
    
                                    Cursor = Cursors.WaitCursor
    
                                    VarGlobal.bolActivadoCuadroContable = True
                                    Dim frmPreparandoInforme = New frmPreparandoInforme
                                    frmPreparandoInforme.Show()
    
                                    Application.DoEvents()
    
                                    While dr.Read
                                        fil += 1I
                                        If dr.IsDBNull(0I) Then
                                            noi.AppendFormat("NULL (fila {0:N0}){1}", fil, Environment.NewLine)
                                        ElseIf dr.FieldCount.Equals(13I) Then '------ Estamos importando 12 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
    
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5, Ejer_06 = @ej6, Ejer_07 = @ej7, Ejer_08 = @ej8, Ejer_09 = @ej9, Ejer_10 = @e10, Ejer_11 = @e11, Ejer_12 = @e12 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Clear()
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej6", dr.GetDouble(6I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej7", dr.GetDouble(7I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej8", dr.GetDouble(8I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej9", dr.GetDouble(9I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e10", dr.GetDouble(10I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e11", dr.GetDouble(11I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@e12", dr.GetDouble(12I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(6I) Then '------ Estamos importando 5 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4, Ejer_05 = @ej5 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(5I) Then '------ Estamos importando 4 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3, Ejer_04 = @ej4 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej4", dr.GetDouble(4I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej5", dr.GetDouble(5I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(4I) Then '------ Estamos importando 3 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2, Ejer_03 = @ej3 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej3", dr.GetDouble(3I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(3I) Then '------ Estamos importando 2 ejercicios
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET Ejer_01 = @ej1, Ejer_02 = @ej2 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                                .Add(Configuracion.CreateParameter(cmd, "@ej2", dr.GetDouble(2I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
    
                                        ElseIf dr.FieldCount.Equals(2I) Then '------ Estamos importando 1 ejercicio
                                            If dr.GetFieldType(0I).Equals(GetType(System.Double)) Then
                                                ccc = dr.GetDouble(0I).ToString("R")
                                            ElseIf dr.GetFieldType(0I).Equals(GetType(System.String)) Then
                                                ccc = dr.GetString(0I)
                                            End If
                                            cmd.CommandText = ("UPDATE Balances SET " & dr.GetName(1I) & " = @ej1 WHERE IdEmpresa = '" & VarGlobal.StrCodEmpresa & "' AND Cód_GC = '" & ccc & "'")
                                            With cmd.Parameters
                                                .Add(Configuracion.CreateParameter(cmd, "@ej1", dr.GetDouble(1I)))
                                            End With
                                            If cmd.ExecuteNonQuery.Equals(0I) Then noi.AppendFormat("{0} (fila {1:N0}){2}", ccc, fil, Environment.NewLine)
                                            tot += 1I
                                        End If
    
                                        cmd.Parameters.Clear()
                                    End While
    
                                    frmPreparandoInforme.Close()
    
                                    CargaDatagridView1()
    
                                    'Dim Cód_GC As String
    
                                    If noi.Length.Equals(0I) Then
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "»", Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    Else
                                        'Dim msg As String = String.Format("Importación finalizada.{0}Se han importado {1} filas del archivo «{2}» con el código contable {3}", Environment.NewLine, tot.ToString("N0"), ruc, & 'Cód_GC')
                                        'MessageBox.Show(msg, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                        System.Windows.Forms.MessageBox.Show("Importación finalizada" & Environment.NewLine & "Se han importado " & tot.ToString("N0") & " filas del archivo «" & ruc & "». Las siguientes cuentas no han sido importadas:" & Environment.NewLine & Environment.NewLine & noi.ToString, Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
                                    End If
                                Else
                                    System.Windows.Forms.MessageBox.Show("La hoja de cálculo «" & nombreHoja & "» no contiene datos para importar", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                                End If
                                dr.Close()
    
                                Cursor = Cursors.Default
    
                            End Using
                        End Using
    
                    End Using
                End Using
    
                bolCambiosDatagridView = True 'Para activar la carga de fórmulas.
                CuadreBalances()
    
            Catch ex As Exception
                Dim msg As String = String.Empty
                If (ex.InnerException Is Nothing) Then
                    msg = ex.Message
                Else
                    msg = ex.InnerException.Message
                End If
    
                MessageBox.Show(msg)
    
            End Try
        End Sub
    Clase ObjectExcel

    Option Strict On
    Imports System.Reflection
    
    ''' <summary>
    ''' Clase para interactuar con la biblioteca de objetos
    ''' de Microsoft Excel mediante reflexión, por lo que
    ''' no es necesario referenciarla en nuestro proyecto.
    ''' </summary>
    ''' <author>Enrique M. Montejo - 2016</author>
    Public Class ObjectExcel
    
        Implements IDisposable
    
        Private m_app As Object         ' Objeto Excel.Application (Aplicación Excel)
        Private m_books As Object       ' Objeto Excel.Workbooks (Colección de libros de trabajo)
        Private m_wb As Object          ' Objeto Excel.Workbook (Libro de trabajo)
    
        Private missing As Missing = missing.Value
    
    #Region "Constructores"
    
        ''' <summary>
        ''' Crea una nueva instancia de la clase con la ruta
        ''' del libro de Excel especificada.
        ''' </summary>
        ''' <param name="fileName"></param>
        Public Sub New(fileName As String)
    
            ' Creamos una nueva instancia del objeto Application.
            m_app = CreateExcelApplication()
            SetProperty(m_wb, "Visible", True, Nothing)
    
            ' Referenciamos la colección de libros.
            m_books = GetProperty(m_app, "Workbooks", Nothing)
    
            ' Abrimos el libro de trabajo.
            Dim args(14) As Object
            args(0) = fileName
            For n As Integer = 1 To 14
                ' Establecer el valor Missing.Value a los 14
                ' restantes parámetros opcionales del método
                ' Open.
                args(n) = missing
            Next
    
            m_wb = ExecuteMethod(m_books, "Open", args, False)
    
        End Sub
    
    #End Region
    
    #Region "Métodos públicos"
    
        ''' <summary>
        ''' Abre el libro de trabajo especificado devolviendo el
        ''' envoltorio de un objeto Excel.Workbook.
        ''' </summary>
        ''' <param name="rangoColumna">Rango de la columna cuyo formato de
        ''' celdas se desea establecer a Texto. Ejemplos: "A:A" (para la
        ''' primera columna), "B:C" (para la segunda y tercera columnas).</param>
        Public Sub SetFormatText(rangoColumna As String)
    
            Dim sheets As Object = Nothing      ' Objeto Excel.Sheets (Colección de hojas de cálculo)
            Dim ws As Object = Nothing          ' Objeto Excel.Worksheet (Hoja de cálculo)
            Dim range As Object = Nothing       ' Objeto Excel.Range
    
            Try
                ' Referenciamos la colección de hojas de cálculo.
                '
                sheets = GetProperty(m_wb, "Sheets", Nothing)
    
                ' Referenciamos la hoja de cálculo especificada.
                '
                ws = GetProperty(sheets, "Item", New Object() {1})
    
                ' Referenciamos el rango de celdas correspondientes a la columna especificada
                '
                range = GetProperty(ws, "Range", New Object() {rangoColumna})
    
                ' Seleccionamos el rango
                ExecuteMethod(range, "Select", Nothing, True)
    
                ' Establecemos el formato de texto a las celdas.
                SetProperty(range, "NumberFormat", "@", Nothing)
    
                ' Liberar la referencia al objeto Excel.Range.
                FinalReleaseComObject(range)
    
                ' Referenciamos la primera celda de la hoja de cálculo.
                range = GetProperty(ws, "Range", New Object() {"A1:A1"})
    
                ' Seleccionamos el rango
                ExecuteMethod(range, "Select", Nothing, True)
    
            Catch ex As Exception
                ' Se ha producido una excepción. Si procede, indicamos
                ' que el libro ya ha sido guardado.
                '
                If (Not m_wb Is Nothing) Then
                    SetProperty(m_wb, "Saved", True, Nothing)
                End If
    
                ' Devolver la excepción al procedimiento llamador
                '
                Throw
    
            Finally
                ' Liberar las referencias de los distintos objetos utilizados.
                FinalReleaseComObject(range)
                FinalReleaseComObject(ws)
                FinalReleaseComObject(sheets)
    
            End Try
    
        End Sub
    
    #End Region
    
    #Region "Métodos privados."
    
    #Region "CreateExcelApplication"
    
        ''' <summary>
        ''' Devuelve una instancia de la clase Excel.Application.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function CreateExcelApplication() As Object
    
            Dim ty As Type = CreateType("Excel.Application")
    
            ' Creamos la instancia del tipo de objeto especificado.
            ' Si se utiliza el método Activator.CreateInstance, no
            ' es necesario especificar el indicador BindingFlags.CreateInstance.
            '
            Dim flags As BindingFlags = ObjectExcel.BindingFlagsInstance()
    
            ' No llamar al método ReflectionHelper.CreateObject, porque aparte de que éste
            ' no tiene en cuenta los miembros privados, evito llamadas innecesarias al 
            ' método RuntimeHelpers.GetObjectValue.
    
            Dim obj As Object = Activator.CreateInstance(ty, flags, Nothing, Nothing, Nothing, Nothing)
            If (obj Is Nothing) Then
                Throw New ArgumentException("No es un objeto válido.")
            End If
    
            Return obj
    
        End Function
    
    #End Region
    
    #Region "CreateType"
    
        ''' <summary>
        ''' Devuelve una instancia de la clase WrappedComObject que envuelve
        ''' un nuevo objeto COM con el ProgId especificado.
        ''' </summary>
        ''' <param name="progId">ProgId del componente COM que se desea referenciar.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function CreateType(progId As String) As Type
    
            If (progId Is Nothing) Then
                Throw New ArgumentNullException("progId")
            End If
    
            ' Obtenemos el tipo asociado al identificador de programa
            ' (ProgID) especificado. 
            '
            Dim ty As Type = Type.GetTypeFromProgID(progId, False)
            If (ty Is Nothing) Then
                Throw New Runtime.InteropServices.COMException("Clase no válida o no registrada.")
            End If
    
            Return ty
    
        End Function
    
    #End Region
    
    #Region "BindingFlagsDefault"
    
        ''' <summary>
        ''' Devuelve los indicadores por defecto que se utilizarán para controlar
        ''' el enlace y la manera en la que se realiza la búsqueda de miembros de
        ''' instancia y estáticos.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function BindingFlagsDefault() As BindingFlags
            Return BindingFlags.Instance Or BindingFlags.Static Or BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.FlattenHierarchy
        End Function
    
    #End Region
    
    #Region "BindingFlagsInstance"
    
        ''' <summary>
        ''' Devuelve los indicadores por defecto que se utilizarán para controlar
        ''' el enlace y la manera en la que se realiza la búsqueda de miembros
        ''' pertenecientes a una instancia de un objeto.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function BindingFlagsInstance() As BindingFlags
            Return BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.FlattenHierarchy
        End Function
    
    #End Region
    
    #Region "BindingFlagsStatic"
    
        ''' <summary>
        ''' Devuelve los indicadores por defecto que se utilizarán para controlar
        ''' el enlace y la manera en la que se realiza la búsqueda de miembros
        ''' estáticos.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function BindingFlagsStatic() As BindingFlags
            Return BindingFlags.Static Or BindingFlags.Public Or BindingFlags.IgnoreCase Or BindingFlags.FlattenHierarchy
        End Function
    
    #End Region
    
    #Region "ExecuteMethod"
    
        ''' <summary>
        ''' Ejecuta el método de instancia del objeto especificado.
        ''' </summary>
        ''' <param name="obj">Instancia del objeto cuya método se desea ejecutar.</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>
        ''' <param name="ignoreReturn">true si el método no devuelve un valor o si se puede
        ''' ignorar el valor devuelto; false en caso contrario.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function ExecuteMethod(obj As Object, methodName As String, args As Object(), ignoreReturn As Boolean) As Object
    
            Dim flags As BindingFlags = BindingFlags.InvokeMethod
            If (ignoreReturn) Then
                ' El marcador BindingFlags.IgnoreReturn se utiliza en la interoperabilidad COM
                ' para especificar que se puede omitir el valor devuelto del miembro. Parece
                ' ser que no tiene ningún efecto si se utiliza con un objeto .NET.
                '
                flags = flags Or BindingFlags.IgnoreReturn
            End If
    
            If (Not obj Is Nothing) Then
                ' Ejecutar el método de instancia. En el método InvokeMember
                ' se verificará el valor null de parámetro Object.
                flags = flags Or ObjectExcel.BindingFlagsInstance()
                Return InvokeMember(obj, Nothing, methodName, flags, args, Nothing, Nothing)
            End If
    
            Return Nothing
    
        End Function
    
    #End Region
    
    #Region "GetProperty"
    
        ''' <summary>
        ''' Obtiene el valor de la propiedad del objeto o tipo de dato especificado.
        ''' </summary>
        ''' <param name="obj">Instancia del objeto cuya propiedad se desea leer.</param>
        ''' <param name="propertyName">Nombre de la propiedad.</param>
        ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor
        ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function GetProperty(obj As Object, propertyName As String, index As Object()) As Object
    
            Dim flags As BindingFlags = BindingFlags.GetProperty
    
            If (Not obj Is Nothing) Then
                ' Leer el valor de una propiedad de instancia. En el método InvokeMember
                ' se verificará el valor null de parámetro Object.
                flags = flags Or BindingFlagsInstance()
                Return InvokeMember(obj, propertyName, flags, index)
            End If
    
            Return Nothing
    
        End Function
    
    #End Region
    
    #Region "FinalReleaseComObject"
    
        ''' <summary>
        ''' Libera todas las referencias a un contenedor RCW (Contenedor al que
        ''' se puede llamar en tiempo de ejecución) estableciendo su recuento
        ''' de referencias en 0.
        ''' </summary>
        ''' <param name="obj">Objeto RCW que se va a liberar.</param>
        ''' <remarks></remarks>
        Private Shared Sub FinalReleaseComObject(obj As Object)
    
            ' RCW = Runtime Callable Wrapper
    
            ' Una aplicación de Office no se cierra después de la automatización desde Visual Studio. NET
            ' Office application does not quit after automation from Visual Studio .NET client
            ' http://support.microsoft.com/kb/317109
    
            If (Not obj Is Nothing) Then
                Try
                    ' Se requiere .NET 2.0 o superior.
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj)
                Catch
                    ' Deshechamos devolver la posible excepción
                    ' si no es un objeto COM válido.
                Finally
                    obj = Nothing
                End Try
            End If
    
        End Sub
    
    #End Region
    
    #Region "InvokeMember"
    
        ''' <summary>
        ''' Invoca el miembro de instancia del objeto especificado.
        ''' </summary>
        ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param>
        ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la
        ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía
        ''' ("") para llamar al miembro predeterminado.</param>
        ''' <param name="invokeAttr">Máscara de bits formada por una o varias enumeraciones
        ''' BindingFlags que especifican la forma en que se realiza la búsqueda.</param>
        ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al
        ''' miembro al cual se va a invocar.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function InvokeMember(obj As Object, name As String, invokeAttr As BindingFlags, args As Object()) As Object
            Return InvokeMember(obj, Nothing, name, invokeAttr, args, Nothing, Nothing)
        End Function
    
        ''' <summary>
        ''' Invoca el miembro de instancia del objeto especificado.
        ''' </summary>
        ''' <param name="obj">Objeto donde debe invocarse el miembro especificado.</param>
        ''' <param name="ty">El tipo asociado al objeto donde debe invocarse el miembro especificado.</param>
        ''' <param name="name">Cadena que contiene el nombre del constructor, el método, la
        ''' propiedad o el miembro de campo al que se va a invocar, o bien una cadena vacía
        ''' ("") para llamar al miembro predeterminado.</param>
        ''' <param name="args">Matriz que contiene los argumentos que se van a pasar al
        ''' miembro al cual se va a invocar.</param>
        ''' <param name="modifiers">Matriz de objetos ParameterModifier que representan los
        ''' atributos asociados al elemento correspondiente de la matriz args.</param>
        ''' <param name="namedParameters">Matriz que contiene los nombres de los parámetros
        ''' a los que se pasan los valores de la matriz args.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function InvokeMember(obj As Object, ty As Type, name As String, invokeAttr As BindingFlags, args As Object(),
                                            modifiers As ParameterModifier(), namedParameters As String()) As Object
    
            If (String.IsNullOrWhiteSpace(name)) Then
                Throw New MissingMemberException("El valor del miembro especificado no tiene un formato válido para convertirlo al tipo de dato requerido.")
            End If
    
            If (Not obj Is Nothing) Then
                ' Invocar el miembro de instancia especificado. 
                Return obj.GetType().InvokeMember(name, invokeAttr, Nothing, obj, args, modifiers, Nothing, namedParameters)
            End If
    
            If (Not ty Is Nothing) Then
                ' Invocar el miembro estático especificado.
                Return ty.InvokeMember(name, invokeAttr, Nothing, Nothing, args, modifiers, Nothing, namedParameters)
            End If
    
            Throw New ArgumentNullException()
    
        End Function
    
    #End Region
    
    #Region "SetProperty"
    
        ''' <summary>
        ''' Establece el valor de la propiedad del objeto especificado.
        ''' </summary>
        ''' <param name="obj">Instancia del objeto cuya propiedad se desea establecer.</param>
        ''' <param name="propertyName">Nombre de la propiedad.</param>
        ''' <param name="newValue">El nuevo valor de la propiedad.</param>
        ''' <param name="index">Valores de índice opcionales para propiedades indexadas. Este valor
        ''' debe ser null (Nothing en Visual Basic) para propiedades no indexadas.</param>
        ''' <remarks></remarks>
        Private Shared Sub SetProperty(obj As Object, propertyName As String, newValue As Object, index As Object())
    
            Dim flags As BindingFlags = BindingFlags.SetProperty
    
            Dim parameters As Object() = Nothing
            If (Not index Is Nothing) Then
                parameters = New Object(index.Length) {}
                For n As Integer = 0 To index.Length - 1
                    parameters(n) = index(n)
                Next
                parameters(index.Length) = newValue
            Else
                parameters = New Object() {newValue}
            End If
    
            If (Not obj Is Nothing) Then
                ' Leer el valor de una propiedad de instancia. En el método InvokeMember
                ' se verificará el valor null de parámetro Object.
                flags = flags Or BindingFlagsInstance()
                InvokeMember(obj, propertyName, flags, parameters)
            End If
    
        End Sub
    
    #End Region
    
    #Region "Soporte para IDisposable"
    
        ' Para detectar llamadas redundantes
        Private disposedValue As Boolean
    
        ' IDisposable
        Private Sub Dispose(disposing As Boolean)
    
            If (Not disposedValue) Then
                If (disposing) Then
                    ' Elimine el estado administrado (objetos administrados).
                    '
                    If (Not m_wb Is Nothing) Then
                        ' Guardamos los cambios.
                        ExecuteMethod(m_wb, "Save", Nothing, True)
    
                        ' Cerramos el libro.
                        ExecuteMethod(m_wb, "Close", Nothing, True)
                    End If
    
                    If (Not m_books Is Nothing) Then
                        ExecuteMethod(m_books, "Close", Nothing, True)
                    End If
    
                    If (Not m_app Is Nothing) Then
                        ExecuteMethod(m_app, "Quit", Nothing, True)
                    End If
                End If
    
                ' Libere los recursos no administrados (objetos no administrados) y reemplace Finalize() .
                '
                FinalReleaseComObject(m_wb)
                FinalReleaseComObject(m_books)
                FinalReleaseComObject(m_app)
    
            End If
    
            disposedValue = True
    
        End Sub
    
        Protected Overrides Sub Finalize()
            Dispose(False)
            MyBase.Finalize()
        End Sub
    
        Public Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
    
    #End Region
    
    #End Region
    
    End Class
    
    Un abrazo.Gemma

    viernes, 24 de junio de 2016 16:43
  • Enrique:

    Está funcionando perfectamente. Todo en un solo proceso. Va perfecto.

    Gemma

    viernes, 24 de junio de 2016 17:33
  • "gemma_campillo" escribió:

    > Maestro, si no te he entendido mal quieres que te ponga la clase, no?.

    No, no te dije eso, pero sí te indiqué que comentaras la siguiente línea para que no se abra la propia interfaz de usuario de Microsoft Excel cuando vayas a formatear la columna:

           ' Si procede, hacemos visible la instancia de Microsoft Excel.
           ' SetProperty(m_wb, "Visible", True, Nothing)

    Esa línea se encuentra en el constructor de la clase ObjectExcel (procedimiento Sub New).


    >    Public Sub SetFormatText(rangoColumna As String)
    >
    >       ' Referenciamos la hoja de cálculo especificada.
    >       '
    >       ws = GetProperty(sheets, "Item", New Object() {1})

    Como finalmente has decidido referenciar la hoja de cálculo por su índice para formatear SIEMPRE la primera hoja del archivo de Excel, poco sentido tiene que llames a la función NombrePrimeraHoja para simplemente obtener el nombre de la primera hoja. ¿No lo crees así?

    No obstante, te aconsejaría que dejaras el procedimiento Importar tal cual lo tenías anteriormente, y te limitases a formatear la hoja de cálculo fuera de dicho procedimiento y ANTES de llamar al procedimiento Importar, por ejemplo, en el evento Click del control llamado btnImpexcel, tras cerrar el cuadro de diálogo que le muestras al usuario para seleccionar el archivo de Excel:

        Private Sub btnImpexcel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnImpexcel.Click
    
            ' ...
    
            ' ...
    
            ' ...
    
            Using ofd As New OpenFileDialog()
                With ofd
                    .Multiselect = False
                    .Filter = "Archivos de Excel (*.xls; *.xlsx)|*.xls;*.xlsx"
                    .CheckFileExists = True
                End With
    
                If (ofd.ShowDialog = DialogResult.OK) Then
               
                    ' Formatear la columna
                    Using app As New ObjectExcel(rut)
                        app.SetFormatText("A:A")
                    End Using
    
                    ' Importar los datos
                    Importar(ofd.FileName, ofd.SafeFileName)
    
                End If
    
            End Using
    
        End Sub

    De ésta manera, en el procedimiento Importar ya no tienes que abrir la conexión para obtener el nombre de la primera hoja, cerrarla para formatear la columna, y nuevamente abrirla para obtener un objeto DataReader, es decir, que del procedimiento Importar eliminarías las siguientes líneas:

        ' Cerrar la conexión para pooder formatear la primera columna
        '
        ' cnx.Close()
        '
        ' Dar formato a las celdas
        ' Using app As New ObjectExcel(rut)
        '     app.SetFormatText("A:A")
        ' End Using
        '
        ' cnx.Open()

    De esta manera descargarías de trabajo al procedimiento Importar, que bastante tiene ya. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    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.



    sábado, 25 de junio de 2016 7:19
    Moderador
  • Hola Enrique, buenos días.

    Todo hecho tal como me has indicado.

    Va todo perfectamente.

    Ahora ya me pongo con el sql server que es lo único que me falta y a ver si lo acabo hoy y mañana preparo la ayuda.

    Bueno, maestro te doy las gracias por tu inestimable ayuda, ya lo sabes, como siempre.

    Recibe un gran abrazo de tu amiga.

    Gemma

    sábado, 25 de junio de 2016 7:31