Problemi di ole Automation Accessexcel
Hai un problema con Excel? 
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
Vuoi Approfondire?