Problemi di ole Automation Accessexcel



  • Problemi di ole Automation Access/excel
    di Lelè22 data: 01/04/2014 14:03:05

    Salve ragazzi, vi chiedo aiuto riguardo un problema che secondo me riguarda piu' un cattivo funzionamento di Ole Automation che un errore di programmazione.
    Ho l' esigenza di aprire da Access un file di excel, manipolare i dati in excel e importarli in una tabella ACCESS.

    Si verificano una serie di problemi che si presentano casualmente , mentre alle volte la routine funziona: x questo ritengo sia un errore di gestione e passaggio dati fra le varie applicazioni..
    Sto usando Access e Excel in versione 2000 su windows xp, tale è il SW ufficialmente a disposizione.
    il codice, dichiarazioni a parte che non riporto, è incluso sotto:

    sXlsTargetFile è il nome del file excel contenente i dati
    La routine modulo1.PrepareDataToExport funziona correttamente e seleziona un area in un foglio e la ricopia in un nuovo foglio aggiuntivo.
    Gli ordini di problema sono 2 :
    1. la chiusura di Excel non avviene correttamente:sebbene io non veda piu' l' applicativo, che provvedo a chiudere e del quale azzero la variabile che lo gestisce, noto in task manager che un' istanza di excel rimane comunque aperta.
    2. il Docmd.transferSpreadSheet a volte funziona, a volte mi indica che un fantomatico campo F1 in tabella destinazione non esiste... questo accade proprio se si rifa girare il codice con l' istanza "fantasma" di Excel caricata nei processi di task manager
    Questo secondo errore viene "risolto" solo o cancellando la tabella destinazione e rifacendola con i campi corrispondenti a quelli che voglio importare (come peraltro strutturata anche prima) o chiudendo access ed excel e riaprendo il tutto, dopo aver cancellato l' istanza di excel in background.
    In questo caso ipotizzo che le istanze di excel rimaste aperte e invisibili si accavallino facendo importare non cio che io comando ma ciò che in quel momento risulta attivo ( chissa cosa).
    Se sapeste darmi delle dritte mi fareste un immenso favore,

    Grazie a tutti
     
    Codice: Seleziona tutto
    [size=85]
    [color=#80FF00]Set xlApp = New Excel.Application 'creazione dell' oggetto applicazione
        xlApp.Application.Visible = True
        xlApp.Application.Workbooks.Open sXlsTargetFile  'apertura del file selezionato
        ActiveWorkbook.Application.Run ("Modulo1.PrepareDataToExport") ' Comando di esecuzione della preparazioneuire la preparazione dei dati
        ActiveWorkbook.Sheets("DataToExport").Select
        DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True ' comando di import
        xlApp.DisplayAlerts = False ' serve a chiudere il foglio di lavoro senza chiedere di salvare le modifiche
        xlApp.Application.Workbooks.Close
        xlApp.DisplayAlerts = True ' reimposto i messaggi di sistema
        xlApp.Quit ' Chiude l' applicazione
       
        Set xlApp = Nothing 'rilascio della Memoria



  • di Vecchio Frac data: 01/04/2014 15:42:10

    Titolo della discussione modificato come da regolamento (era: "help me, Problemi di ole Automation Access/excel").
    Prego evitare di utilizzare termini come "help me" e simili, grazie.





  • di Vecchio Frac data: 01/04/2014 15:52:36

    Non vedendo tutto il codice è difficile dirti se per esempio il problema non risieda nel cattivo uso di ActiveWorkbook che non risultato settato da nessuna parte. Spero inoltre che utilizzi anche Option Explicit.

    Magari la routine "PrepareDataToExport" che a te sembra funzionare correttamente magari si porta dietro qualche effetto collaterale.

    I problemi di TransferSpreadsheet dipendono sicuramente dalle istanze di Excel rimaste appese.
    Riesci a produrre un file di esempio con cui si possa ricreare lo scenario?

    Considera anche la possibilità di leggere i dati da Excel via ADO senza necessità di importare il file.





  • di Zer0Kelvin data: 02/04/2014 07:02:09

    Ciao.
    Innanzitutto ti consiglio anc'io di usare "Option Explicit", poi bisognerebbe scoprire cosa fa aprire l'istanza fantasma di Excel.
    Puoi tentare un'esecuzione passo-passo col taskmanager aperto, per determinare quale istruzione apre la seconda istanza di excel .
    Intanto prova a modificare così il codice
     
    Dim xlApp As Excel.Application
    Dim WK As Excel.Workbook
       
       Set xlApp = New Excel.Application
       With xlApp
          .Visible = True
          Set WK = .Workbooks.Open(sXlsTargetFile)
          .Run ("Modulo1.PrepareDataToExport")
          WK.Sheets("DataToExport").Select
          DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True
          .DisplayAlerts = False
          WK.Close
          .DisplayAlerts = True
          .Quit
       End With
       Set WK = Nothing
       Set xlApp = Nothing
    



  • di Zer0Kelvin data: 02/04/2014 07:08:16

    PS: ho parlato di "seconda istanza di Excel" perchè sono quasi certo che venga aperta una seconda istanza...



  • di Lelè22 data: 02/04/2014 09:46:04

    Ragazzi,
    innanzitutto vi ringrazio per i suggerimenti ricevuti,
    mi scuso, poi, per aver utilizzato un titolo inappropiato.
    Per quanto riguarda i vostri suggerimenti confermo che utilizzo l' opzione Option Explicit e dichiaro tutte le variabili coinvolte.
    Facendo girare la routine con Task Manager aperto, cosa che avevo fatto ieri, confermo che rimane appesa fra i processi una istanza "fantasma" di Excel.
    L' istanza di excel viene aperta lanciando
    Killandola da Task Manager non ho pià problemi con il comando DoCmd.TransferSpreadSheet.
    ZeroKelvin Grazie per lo stralcio di codice che mi hai inviato.
    In realtà ho usato ache il displayalert in un' altra funzione e mi mandava in palla il tutto... riproverò

    Non conosco bene ADO... utilizzo l' ole automation perchè mi viene più naturale riferirmi ad altre applicazioni considerandole come oggetti.. inoltre ho la necessità di far girare delle routine all' interno dell' oggetto workbook di Excel.Application che seleziono.
    Vecchio frac, che intendi con il dire che Activebook non è stato dichiarato?
    In realtà, in un' istanza precedente dichiaravo un oggetto Excel.Workbook ma il conportamento era simile.
    La routine modulo1.PretpareDataToExport funziona correttamente perchè l' import, diciamo senza istanza fantasma di excel, va a buon fine.

    Pare che tutto sia causato dal fatto che rimanga un' istanza di excel aperta.


    Grazie mille a tutti, vi farò sapere se otterrò una soluzione


  • Last update
    di Lelè22 (utente non iscritto) data: 02/04/2014 13:57:01

    Ho provato a inserire il codice che mi avevate proposto e penso lo manterrò perchè più elegante e inoltre dichiara l' oggetto Workbook che io utilizzavo in modo implicito come collezione dell' oggetto Excel.Application...
    Ebbene... Rullo di tamburi.... il comportamento è esattamente identico a quello del codice originale---



  • di scossa data: 02/04/2014 15:33:25

    Purtroppo ti ostini a non far vedere il codice che utilizzi.
    Io sono quasi certo che la causa sia la mancanta distruzione delle istanze create, cioè manca una o più istruzione set MiaIstanza = Nothing
    alla fine del tuo codice.


     scossa's web site  



  • di Zer0Kelvin data: 02/04/2014 20:48:05

    Prova a vedere cosa succede modificando così la macro
     
    Dim xlApp As Object
    Dim WK As Excel.Workbook
       
       Set xlApp = New Excel.Application
       With xlApp
          .Visible = True
          Set WK = .Workbooks.Open(sXlsTargetFile)
          .Run ("Modulo1.PrepareDataToExport")
          WK.Sheets("DataToExport").Select
          DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True
          .DisplayAlerts = False
          WK.Close
          .DisplayAlerts = True
          .Quit
       End With
       Set WK = Nothing
       Set xlApp = Nothing
       On Error Resume Next
       Set xlApp = GetObject(, "Excel.Application")
       On Error GoTo 0
       If Not xlApp Is Nothing Then xlApp.Close
       Set xlApp = Nothing
    



  • di lelè22 (utente non iscritto) data: 02/04/2014 23:29:11

    beh lastissimo update...
    il codice funziona sul mio notebook personale con windows 7 e office 2007.
    stessa cosa su un altro pc aziendale configurato con office 2003.
    posso verificare che l' istanza di excel viene correttamente chiusam anche se non avendo qui il modulo isam installato, non riesco a gestire excel da access.
    In definitiva credo che il problema sia la configurazione del pc ed eventualmente la versione di office installata.
    X scossa... ho postato la porzione di codice incriminata, all' inizio .. l' ho poi modificata secondo i suggerimenti di zerokelvin anche questi riportati nella discussione.
    Ad ogni modo riposto l0 ultima versione con la funzione che richiama il pezzo di codice che crea il problema

    Saluti

     
    Function Mains()
    '**************************************************
    ' R.R. 26/03/2014
    ' Routine principale: start del programma'
    '**************************************************
    ' Sezione Dichiarazioni
    Dim dbTCBA As Database
    Dim qTCListDel As QueryDef 'Cancella i record di tabella
                               'TCLIst
    '**************************************************
    ' Cancellazione di tutti i record della tabella TCLIst
    '
    Set dbTCBA = CurrentDb()
    Set qTCListDel = CurrentDb.CreateQueryDef("")
    
    With qTCListDel
        .SQL = "DELETE TCList.[TC Number], TCList.Description, TCList.[Sw Version]," _
            & "TCList.Draft FROM TCList;" ' definizione della query
        .Execute ' esecuzione della query di cancellazione
    End With
    
    qTCListDel.Close ' chiusura degli oggetti database
    dbTCBA.Close
    
    Set qTCListDel = Nothing
    Set dbTCBA = Nothing
    ' Fine istruzioni cancellazione tabella
    
    
                 
    ManageXlsWkAndImport
    End Function
    Sub ManageXlsWkAndImport()
    
    Dim xlApp As Excel.Application
    Dim wk As Excel.Workbook
    Dim fsCtrlExt As Scripting.FileSystemObject
    Dim sXlsTargetFile As String 'contiene il path e il name del file xlsTarget
    Dim sTargetExt As String 'estensione del file Target
    Dim bRetrieveTargetFile As Boolean
    
    On Error GoTo ErrorHandler:
    
    ' inizializzazioni
    bRetrieveTargetFile = True
    sTargetExt = Empty
    
    '***********************************************************************
    ' Corpo del Codice'
    '***********************************************************************
        'recupero del file di Excel
        While bRetrieveTargetFile
            sXlsTargetFile = LaunchCD() ' ricerca del file target
            Set fsCtrlExt = CreateObject("Scripting.FileSystemObject")
            sTargetExt = fsCtrlExt.GetExtensionName(sXlsTargetFile)
            bRetrieveTargetFile = False  ' --> si esce dal ciclo
            
            If StrComp(sTargetExt, "xls", vbTextCompare) <> 0 Then
                bRetrieveTargetFile = True ' -->  non si esce dal ciclo
                MsgBox "Attenzione, non hai selezionato un tipo di file corretto (xls)" & Chr(13) _
                       & "Riprova!", vbExclamation, "Errore di selezione"
            End If
        Wend
        
        '*** gestione del foglio target di excel
    
        Set xlApp = New Excel.Application
        With xlApp
            .Visible = True
            Set wk = .Workbooks.Open(sXlsTargetFile)
            .Run ("Modulo1.PrepareDataToExport")
            wk.Sheets("DataToExport").Select
            DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True ' comando di import
            .DisplayAlerts = False
            wk.Close
            .DisplayAlerts = True
            .Quit
        End With
        Set wk = Nothing
        Set xlApp = Nothing
    Exit Sub
    ErrorHandler:
        If Err.Number = 2391 Then
            MsgBox "Errore : importazione dati non effettuata" + Chr(13) + _
                   "Istanza di Excel già aperta come processo." + Chr(13) + _
                   "Eliminarla da Task Manager e ripetere l'operazione di Import", vbCritical, "Import Error"
            Err.Clear
        Else
            MsgBox Err.Description + " " + CStr(Err.Number)
        End If
    Resume Next
    End Sub



  • di Vecchio Frac data: 03/04/2014 08:52:19

    Usare GetObject per intercettare un'istanza di Excel aperta come ha evidenziato Zer0Kelvin è più sicuro (e anche più corretto tecnicamente) di On Error.
    Ma non ne trovo traccia nella tua l'ultima versione cit. "...poi modificata secondo i suggerimenti di zerokelvin".

    Osservazioni:
    La Function Mains() è eccessiva visto che basta solo DoCmd per fare questo:

    Function Mains()
    ' Cancellazione di tutti i record della tabella TCLIst
    DoCmd.RunSQL "DELETE * FROM TCList"
    Call ManageXlsWkAndImport
    End Function



    In Sub "ManageXlsWkAndImport":
    - la ricerca del file target avviene con "LaunchCD()" di cui non si sa niente. Sicuri che anche lì non vengano avviate per caso istanze di Excel?
    - Se cerchi un file specifico con estensione xls perchè hai messo in piedi una costruzione così per verificare l'estensione stessa?
    - Se invece è l'utente a cercare il file (non sappiamo come funziona LaunchCD) perchè non utilizzi semplicemente application.GetOpenFilename( "Excel file, *.xls" ) (ovviamente al posto di application ci va il riferimento all'istanza di Excel creata)? in questo modo sei già quasi sicuro che l'utente sceglie file xls e se proprio non avviene così puoi controllarne l'estensione controllando quanto c'è dopo l'ultimo punto (sfruttando InstrRev senza scomodare un oggetto FileSystemObject)
    - A proposito del FileSystemObject... è inutile assegnare Dim fsCtrlExt As Scripting.FileSystemObject e poi Set fsCtrlExt = CreateObject("Scripting.FileSystemObject")... o usi un metodo o usi l'altro (early e late binding) altrimenti crei semplicemente due oggetti distruggendone uno senza utilizzarlo
    - Non sappiamo bene cosa combina la procedura nel foglio Excel quando la richiami con .Run ("Modulo1.PrepareDataToExport"). Magari è lì che si annida un baco :)







  • di scossa data: 03/04/2014 09:02:27

    In aggiunta alle osservazioni di Vecchio Frac, faccio notare che:

    l'istanza creata con
    Set fsCtrlExt = CreateObject("Scripting.FileSystemObject")
    non provvedi a distruggerla;

    ma soprattutto, le istruzioni:
    Set wk = Nothing
    Set xlApp = Nothing
    le hai inserite prima dell'etichetta ErrorHandler: per cui, in caso di errore le istanze non vengono distrutte!


     scossa's web site  



  • di scossa data: 03/04/2014 09:37:10

    cit. vecchio frac: "... è inutile assegnare Dim fsCtrlExt As Scripting.FileSystemObject e poi Set fsCtrlExt = CreateObject("Scripting.FileSystemObject")... o usi un metodo o usi l'altro (early e late binding) altrimenti crei semplicemente due oggetti distruggendone uno senza utilizzarlo"

    solo una precisazione: l'istruzione Dim fsCtrlExt As Scripting.FileSystemObject  non crea un'istanza dell'oggetto; lo farebbe se avesse usato la sintassi  Dim fsCtrlExt As New Scripting.FileSystemObject.



     scossa's web site  


  • Errata-Corrige
    di scossa data: 03/04/2014 10:36:44

    cit.: "lo farebbe se avesse usato la sintassi Dim fsCtrlExt As New Scripting.FileSystemObject."

    Mi sono espresso malissimo (eufemismo per dire che ho detto una cavolata ).
    Ovviamente nemmeno quell'istruzione crea l'istanza, ma questa viene creata automaticamente appena il codice trova un'istruzione che riguarda quella variabile.


     scossa's web site  



  • di scossa data: 03/04/2014 10:56:29

    errata: "ma questa viene creata automaticamente ......"

    corrige: "ma questa verrebbe creata automaticamente ....."



     scossa's web site  



  • di Vecchio Frac data: 03/04/2014 13:26:55

    Tutte le precisazioni di scossa sono oro colato, in particolare la prima che riguarda l'annientamento degli oggetti fuori della trappola per errori (che io eviterei utilizzando getObject come indicato da Zer0Kelvin).





  • di Lelè (utente non iscritto) data: 03/04/2014 13:58:11

    Ragazzi,

    vi ringrazio tutti moltissimo...
    io non sono un programmatore, anche se mi piace farlo ed è evidente che siete molto più bravi di me...come tantissimi
    Ciò che mi avetre suggerito è corettissimo... provvederò ad aggiornare il codice..
    Per Vecchio Frac: lo stralcio di codice riportato sopra riguarda gli aggiornamenti che avevo fatto al momento seguendo le prime indicazioni di ZeroKelvin, quelle sulla gestione delle istanze di excel... ora provvederò a modificare anche quelle relative alla gestione degli errori...

    Grandi, ciao


  • mi sono dimenticato una cosa
    di lelè (utente non iscritto) data: 03/04/2014 14:03:56

    Ma scusate il resume next alla fine di ErrorHandler non implica la prosecuzione del programma a partire dalla riga successiva a quella che causa errore e quindi che le istruzione di chiusura (Set xlApp = nothing ecc.) vengano comunque eseguite?



  • di Vecchio Frac data: 03/04/2014 14:27:12

    Questa è una buona e giusta osservazione





  • di scossa data: 03/04/2014 15:22:28

    cit.: "Ma scusate il resume next alla fine di ErrorHandler non implica la prosecuzione del programma a partire dalla riga successiva a quella che causa errore e quindi che le istruzione di chiusura (Set xlApp = nothing ecc.) vengano comunque eseguite?"

    L'osservazione è comprensibile, ma ...
    1) quella struttura è, secondo me, un pessimo modo di gestire gli errori;
    2) purtroppo ho avuto modo di vedere, soprattutto quando si fanno interagire applicazioni diverse, che certi errori sono più "errori" degli altri e causano un abend (abnormal end) del codice.

    Del resto puoi verificare tu stesso se, rivedendo la gestione degli errori e spostando il set a nothing a valle dell'etichetta l'istanza di excel viene effettivamente distrutta.


    scossa's web site
    Se tu hai una mela, e io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno.
    Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee.
    (George Bernard Shaw)



  • di lelè22 (utente non iscritto) data: 04/04/2014 09:30:44

    Il modo di gestire gli errori con la struttura on error non piace neanche a me , nonostante non abbia le vs conpetenze , per il semplice fatto che prevede l' esecuzione di un jump all' interno del programma...
    Purtroppo, non conoscevo altri metodi...
    Proverò attuando i vs suggerimenti



  • di scossa data: 04/04/2014 09:55:10

    cit. lelè22: "Il modo di gestire gli errori con la struttura on error non piace neanche a me per il semplice fatto che prevede l' esecuzione di un jump all' interno del programma... "

    Infatti. Ipotizziamo che il codice generi un errore a questa riga:
    Set wk = .Workbooks.Open(sXlsTargetFile)
    salta all'eticheetta, mostra una msgbox e poi torna ad eseguire la riga seguente:
    .Run ("Modulo1.PrepareDataToExport")
    che, a complicare le cose, manda in esecuzione una sub di cui non conosciamo nulla ma che potrebbe generare lei stessa un errore ...
    ammesso che la precedente istruzioni non generi errori, la seguente
    wk.Sheets("DataToExport").Select
    lo genera sicuramente in quanto set wk era andata in errore: altro jump (inutile perchè non risolve il problema) all'etichetta e poi di nuovo a cercare di eseguire il codice seguente .....
    Non credo ci sia da meravigliarsi se in tutto questo caos l'istanza di excel resti in memoria.



    scossa's web site
    Se tu hai una mela, e io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno.
    Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee. (George Bernard Shaw)



  • di lelè22 (utente non iscritto) data: 04/04/2014 13:49:15

    Chiarissimo,
    tuttavia l' istanza rimane in memoria anche quando non si generano errori...
    Forse dovrei postare anche il codice di PrepareDataToExport.... mah si lo faccio
    e della funzione iNoRows...
    Come puoi vedere non fanno nulla di che...Cut&Paste e poco altro
     
    Sub PrepareDataToExport()
    ' R.R. 28/03/2014
    ' prepara dati per l'export in Access
    Dim iNoRows As Integer
    
    iNoRows = iRetrieveRowsNo("Overall Test List", 2, 6) - 1
    ActiveSheet.Range(Cells(2, 6), Cells(2 + iNoRows, 9)).Select
    Selection.Copy
    
    AddNewSheet ("DataToExport")
    Range("A1").Select
    ActiveSheet.Paste
    End Sub
    
    
    Function iRetrieveRowsNo(sName As String, iOffsetV As Integer, IOffsetH As Integer) As Integer
    '************************************************************************
    ' R.Russo 03/03/2014 v.o.a.
    ' la funzione calcola il numero di righe di dati presenti in un  foglio.
    '************************************************************************
    ' dichiarazioni
    Dim sSheetOrigin As String ' memorizza il foglio attivo, quando si richiama
                           ' la routine
    '************************************************************************
    ' corpo della routine
    sSheetOrigin = ActiveSheet.Name
    
    Sheets(sName).Select
    Cells(iOffsetV, IOffsetH).Select
    iRetrieveRowsNo = 0
    While Not IsEmpty(Cells(iRetrieveRowsNo + iOffsetV, IOffsetH))
        iRetrieveRowsNo = iRetrieveRowsNo + 1
    Wend
    Sheets(sSheetOrigin).Select
    End Function
    



  • di scossa data: 04/04/2014 14:29:34

    Ho dato uno sguardo veloce al codice .... per me c'è un inutile e pericoloso (ab)uso di select ed activesheet.
    Inotlre dichiari come Integer variabili che dovrebbero essere Long visto che il numero di righe di un file Excel sono ben di più di 32.767, massimo valore memorizzabile in un Integer.

    Secondo me dovresti rivedere tutto il codice, sostituendo i vari Activequalcosa, qualcosa.Select con istanze degli specifici oggetti.
    Anche i paramteri passati alle varie funzioni sarebbero da rivedere: anziché passare una stringa contenente il nome del foglio che poi vai a selezionare dentro la function, potresti passare direttamente un'istanza dell'oggetto ....

    Sottolineo che sono solo opinioni personali.


    scossa's web site
    Se tu hai una mela, e io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno.
    Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee. (George Bernard Shaw)



  • di lelè22 (utente non iscritto) data: 04/04/2014 16:37:56

    Mah quest' ultima obiezione rivela tutto il mio dilettantismo in materia. Capisco che usare Long anziché integer possa mettermi a riparo da errori di overflow. Non capisco perché invece usare activesheet che è proprietà dell' oggetto workbook debba creare istanze di oggetti che occupano più memoria. Allo stesso modo mi sembra più economico passare una stringa come parametro piuttosto che il puntatore a un'istanza di un oggetto, cosa di cui non vedo i benefici. Se avessi tempo e voglia di darmi 2 dritte mi faresti un immenso piacere. Grazie cmq x l'avviso



  • di scossa (utente non iscritto) data: 04/04/2014 21:58:24

    cit.: "Non capisco perché invece usare activesheet che è proprietà dell' oggetto workbook debba creare istanze di oggetti che occupano più memoria"

    E' evidente che non hai compreso appieno l'"essenza" della programmazione object-oriented, ma non ha importanza; magari qualcuno, con maggiori doti dialettiche e didattiche delle mie, interverrà al riguardo ...

    Ti posto comunque un esempio di come, secondo me, si potrebbe riscrivere la tua function iRetrieveRowsNo (che per inciso non è detto che ".... calcola il numero di righe di dati presenti in un foglio" perché se ci fosse una cella vuota tra quelle piene, il valore restituito sarebbe errato).

    Questa la sub di prova, che richiama le due funzioni:


    Public Sub prova1()
    Dim wsOR As Worksheet
    Dim wsUT As Worksheet
    Dim nUltimaRiga As Long

    Set wsOR = ThisWorkbook.Worksheets("Foglio1")
    Set wsUT = ThisWorkbook.Worksheets("Foglio2")

    nUltimaRiga = iRetrieveRowsNo(wsUT.name, 1, 2)
    MsgBox nUltimaRiga

    nUltimaRiga = uLR(wsUT, 1, 2)
    MsgBox nUltimaRiga


    Set wsOR = Nothing
    Set wsUT = Nothing

    End Sub


    La tua, con tutti gli inutili select etc.:


    Function iRetrieveRowsNo(sName As String, iOffsetV As Integer, IOffsetH As Integer) As Integer
    '************************************************************************
    ' R.Russo 03/03/2014 v.o.a.
    ' la funzione calcola il numero di righe di dati presenti in un foglio.
    '************************************************************************
    ' dichiarazioni
    Dim sSheetOrigin As String ' memorizza il foglio attivo, quando si richiama
    ' la routine
    '************************************************************************
    ' corpo della routine
    sSheetOrigin = ActiveSheet.Name

    Sheets(sName).Select
    Cells(iOffsetV, IOffsetH).Select
    iRetrieveRowsNo = 0
    While Not IsEmpty(Cells(iRetrieveRowsNo + iOffsetV, IOffsetH))
    iRetrieveRowsNo = iRetrieveRowsNo + 1
    Wend
    Sheets(sSheetOrigin).Select
    End Function


    Questa invece una versione che restituisce lo stesso risultato (potenzialmente errato) della tua:


    Private Function uLR(ByVal ws As Worksheet, ByVal nRow As Long, ByVal nCol As Long) As Long
    uLR = ws.Cells(nRow, nCol).End(xlDown).Row
    End Function


    Secondo te, qual'è il codice più performante e "solido"?



    scossa's web site
    Se tu hai una mela, e io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno.
    Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee. (George Bernard Shaw)



  • di lelé (utente non iscritto) data: 06/04/2014 19:53:33

    Bello, bello, bello=-O
    Ovviamente la tua soluzione è più professionale e ti invidio...perchè è evidente che affronti il problema in un'altra ottica...mi piacerebbe avvicinarmi alla tua dimestichezza e bravura...ci sono testi che possano aiutarmi... tuttavia spero che qualcuno mi illumini sul rischio della mia soluzione...purtroppo non ci arrivo...una precisazione il foglio è costruito in modo che non ci possano essere sequenze di righe vuote seguite da righe piena di dati.
    Ciao e grazie



  • di scossa data: 06/04/2014 20:17:34

    I rischi sono difficili da valutare, ma sicuramente hai un minor controllo del tuo codice, una minore efficienza e solidità.
    Prendiamo una cosa banale come ad esempio utilizzare il metodo Select su un range quando non strettamente necessario. Ogni volta che lo applichi richiami, se presente, la routine Worksheet_SelectionChange ..... non è il massimo dell'efficienza.
    Usare ActiveCell o ActiveSheet, soprattutto quando da una sub richiami un'altra sub, ti espone al rischio che, al ritorno alla sub chiamante, il foglio attivo non sia più lo stesso.

    Poi ognuno decide come meglio crede.


    scossa's web site
    Se tu hai una mela, ed io ho una mela, e ce le scambiamo, allora tu ed io abbiamo sempre una mela per uno.
    Ma se tu hai un'idea, ed io ho un'idea, e ce le scambiamo, allora abbiamo entrambi due idee. (George Bernard Shaw)



  • di lelè22 (utente non iscritto) data: 07/04/2014 09:34:51

    Per quanto riguarda invece la gestone oggetti modificata ho dei dubbi sulla posizione dell' istruzione "On Resume Next" non dovrebbe essere inserita in cima al codice per bypassare l' erroer comunque sia?
    Dopo di che getobject dovrebbe assegnare un' istanza di excel se esiste alla Variabile oggwetto xlApp, conseguentemente si testa che esista un' istanza di excel aperta e se si, la si chiude .. Giusto?
     
    Dim xlApp As Object
    Dim WK As Excel.Workbook
       
       Set xlApp = New Excel.Application
       With xlApp
          .Visible = True
          Set WK = .Workbooks.Open(sXlsTargetFile)
          .Run ("Modulo1.PrepareDataToExport")
          WK.Sheets("DataToExport").Select
          DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True
          .DisplayAlerts = False
          WK.Close
          .DisplayAlerts = True
          .Quit
       End With
       Set WK = Nothing
       Set xlApp = Nothing
       On Error Resume Next
       Set xlApp = GetObject(, "Excel.Application")
       On Error GoTo 0
       If Not xlApp Is Nothing Then xlApp.Close
       Set xlApp = Nothing
    



  • di Zer0Kelvin data: 07/04/2014 09:45:57

    Ciao.
    Mettendo un semplice resume next all'inizio del codice ti troveresti a mascherare qualunque errore si verifichi, con effetti imprevedibili.
    Nel nostro caso serve a bypassare una singola istruzione, con un effetto noto (se c'è errore sarà xlApp=Nothing) che gestisco con la If successiva.
    Normalmente gli errori vanno eliminati all'origine, oppure gestiti in maniera idonea caso per caso.



  • di lelè22 (utente non iscritto) data: 07/04/2014 11:04:08

    Esiste quando si esegue un comando docmd.runsql la possibilità di eliminare la visualizzazione degli avvisi.in rxcel esiste displayalerts ma in access non mi pare



  • di lelè22 (utente non iscritto) data: 07/04/2014 13:54:09

    Ho implementato il codice di gestine di errore secondo quanto suggeritomi...
    in realtà, purtroppo l' istanza di excel che rimane appesa non viene chiusa neanche ripetendo un ulteriore xlapp.close...
     
     Set WK = Nothing
       Set xlApp = Nothing
       On Error Resume Next
       Set xlApp = GetObject(, "Excel.Application")
       On Error GoTo 0
       If Not xlApp Is Nothing Then xlApp.Close
       Set xlApp = Nothing
    



  • di Lelè22 data: 08/04/2014 23:12:58

    vi prometto che non tedierò più sull' argomento e, anzi , vi ringrazio per l' aiuto che mi avete dato... mi ha fatto riflettere...
    Le ultime news riguardo l' errore che mi assillava e che ha originato il post.
    In effetti nonostante le modifiche implementate a seguito dei vs suggerimenti, l' errore permane e continuo a pensare che sia un problema di configurazione pc/os e versione di vba, tuttavia ho escogitato un work around che mi permette di operare anche se un' istanza di excel rimane aperta.

    Partendo dal suggerimento di utilizzare la GetObject per la gestione degli errori anzichè il costrutto On error, utilizzo la stessa GetObject per verificare se l' istanza di excel rimane aperta... se si non lancio il costruttore di una nuova istanza di Excel.Application e mi limito ad aprire il workbook di interesse
    Mi direte che non è una soluzione ortodossa... beh effettivamente... ma pare funzionare.
    Allego il codice modificato.
    Di nuovo grazie a tutti
    P.s: posso mettere la spunta di "Risolto"

     
    Sub ManageXlsWkAndImport(sFileToOpen As String)
    '****************************************************************************
    ' R.R. 04/04/2014
    ' apre il file indicato dal parametro sFileToOpen oppure accetta
    ' l'annullamento della procedura
    '****************************************************************************
    ' Dichiarazioni
    Dim xlApp As Excel.Application
    Dim wk As Excel.Workbook
    Dim fsFileOpened As Scripting.FileSystemObject
    Dim sXlsTargetFile As String 'contiene il path e il name del file xlsTarget
    Dim sFileOpened As String
    Dim bRetrieveTargetFile As Boolean
    '****************************************************************************
    ' inizializzazioni
    bRetrieveTargetFile = True
    sXlsTargetFile = Empty
    sFileOpened = Empty
    
    '***********************************************************************
    ' Corpo del Codice'
    '***********************************************************************
    ' recupero del file di Excel
    
        Set fsFileOpened = New Scripting.FileSystemObject
        While bRetrieveTargetFile
            sXlsTargetFile = LaunchCD(sFileToOpen, sgDir) 'ricerca del file target
            sFileOpened = fsFileOpened.GetFileName(sXlsTargetFile)
            sgDir = Left(sXlsTargetFile, Len(sXlsTargetFile) - Len(sFileOpened))
            bRetrieveTargetFile = False  ' -> si esce dal ciclo
            
            If StrComp(sFileToOpen, sFileOpened, vbTextCompare) <> 0 Then
                If "" <> sFileOpened Then
                    bRetrieveTargetFile = True ' -->  non si esce dal ciclo
                    MsgBox "Attenzione, non hai selezionato il file richiesto " & Chr(13) _
                        & "'" & sFileToOpen & "'" & "   ma   " & "'" & sFileOpened & "'" + Chr(13) & "Riprova!", vbExclamation, "Errore di selezione"
                Else
                    MsgBox "Selezione del file da cui importare i dati Annullata!", vbInformation
                End If
            End If
        Wend
        Set fsFileOpened = Nothing
        
    '--------------------------------------------------------------------------------------------------
    ' gestione del foglio target di Excel
    '--------------------------------------------------------------------------------------------------
        If sFileOpened <> "" Then
                       
            On Error Resume Next
            'Controllo  se istanza Excel presente in memoria
            Set xlApp = GetObject(, "Excel.Application") 'verifica se esiste un'istanza di excel aperta
            
            Select Case Err.Number
            Case 0 ' nessun errore
                If xlApp Is Nothing Then Set xlApp = New Excel.Application ' No istanza di Excel
            Case 429
                Set xlApp = New Excel.Application
                Err.Clear
            Case Else
                MsgBox "Routine Importazione Dati Annullata", vbInformation, "Import Message"
            End Select
            
            On Error GoTo 0 ' disabilita controllo degli errori
            
            With xlApp
                Set wk = .Workbooks.Open(sXlsTargetFile)
                .Visible = True
                .Run ("ModDbFunctions.PrepareDataToExport")
                wk.Sheets("DataToExport").Select
                DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel3, "TCLIst", sXlsTargetFile, True 'comando di import
                .DisplayAlerts = False
                wk.Close
                .DisplayAlerts = True
            End With
            
            Set wk = Nothing
            xlApp.Quit
            Set xlApp = Nothing
        End If 'File Opened
    End Sub



  • di lelè (utente non iscritto) data: 10/04/2014 09:28:48

    Visto che nopn ci sono repliche inserisco la spunta di risolto