Access – errori di record-locking

Anche se si impostano le Opzioni prededefinite di Access (2007) con un valore che sembra corretto per gestire i problemi di record-locking del proprio progetto, probabilmente con un numero elevato di utenti si verificheranno comunque conflitti di varia natura.

Più utenti usano l’applicazione, più probabile che si creino conflitti. Tali conflitti possono comunque essere gestiti (catturati) tramite codice VBA e comunicati agli utenti.

Microsoft con Access 2007 e successivi, ha sviluppato un modo per memorizzare dati nella cache, scrivendoli sul disco solo quando la cache è piena. Questo rende Access più veloce ma rende più difficile l’intercettazione degli errori.

Un altro  problema con il salvataggio dei dati nella cache è che, solo quando la cache è piena i dati verranno scritti sul disco e saranno solo in questo caso disponibili agli altri utenti.

Per risolvere questi problemi bisogna usare nelle procedure transazioni con Workspace.BeginTrans e Workspace.CommitTrans. (Transazioni gestite dall’oggetto Connection di ADO)

Bisogna garantire una gestione degli errori efficente.

I codici di errore  che più spesso si trovano in questi casi sono

3260 (non è possibile aggiornare i dati)

3186 (non è possibile salvare i dati sul disco)

3197 (più istanze dello stesso database aperte sulla stessa macchina)

3188 (due o più utenti stanno tentando di modificare gli stessi dati

 

La funzione GestError permette la gestione degli errori con una solo funzione pubblica

 

Public Function GestError(vValue As Integer) As Integer

Dim lCounter As Long

Dim lReturn As Long

Dim sCaption As String

Dim sMessage As String

sCaption = “gestione Errori”

Select Case Err.Number

Case 3021

‘ Lascia passare l’errore

Case 3186

‘ Record è bloccato da un’altra macchina

If vValue < 10 Then

For lCounter = 0 To 15000

Next lCounter

GestError = 3

Else

ParseError Err, Error

GestError = 4

End If

Case 3188

‘ Record è bloccato da un’altra sessione dell’applicativo sulla stessa machina

MsgBox “Il record non può essere bloccato in quanto in uso in questa macchina”

Case 3197

sMessage = “Il record che si stà salvando è stato modificato da un altro utente” _

& ” vuoi modificarlo ugualmente?”

lReturn = MsgBox(sMessage, vbYesNo, sCaption)

Select Case lReturn

Case vbYes

GestError = 3

Case vbNo

GestError = 4

End Select

Case 3260

‘ Il record è bloccato da un’altra macchina

If vValue < 10 Then

For lCounter = 0 To 15000

Next lCounter

GestError = 3

Else

ParseError Err, Error

GestError = 4

End If

Case 3421

sMessage = “Inserimento cancellato a causa di un errore di conversione”

lReturn = MsgBox(sMessage, vbOKOnly, sCaption)

Case Else

sMessage = “Il codice di errore è:  ” & Err

lReturn = MsgBox(sMessage, vbInformation, sCaption)

End Select

End Function

 

GestError accetta un singolo argomento (Flag – intero) sulla base del quale prende provvedimenti e visualizza messaggi.

Errore 3260: record non aggiornabile in quanto bloccato da un’altra macchina. Questo errore si verifica quando è abilitato il blocco pessimistico dei record. Accade quando un utente prova a modificare un record e questo viene bloccato fino al termine e salvataggio del record.

Valori possibili di LockType:

adLockBatchOptimistic (valore obbligatorio per gli aggiornamenti batch)

adLockOptimistic (blocco ottimistico dei record, applicato solo con il metodo UPDATE)

adLockPessimistic (blocco pessimistico dei record, applicato non appena si inizia la modifica di un record)

adLockReadOnly (solo lettura, non sono accettate modifiche)

asLockUnspecified (nessun tipo di blocco specificato)

Errore 3186: simile all’errore 3160 ma dice solamente che è stato impossibile salvare il record.

Errore 3188: si verifica quando si ha più di un’istanza del database aperta sulla stessa macchina e si cerca di modificare (bloccare) un record in entrambe le sessioni. La soluzione è non aprire più di un’istanza dello stesso DB nella medesima macchina.

Errore 3197: questo errore può essere causa di confusione. Esso normalmente si verifica quando in un’applicazione è attivo il Locking ottimistico o misto. Bisogna gestire questo tipo di errore anche perchè potrebbe verificarsi un blocco dell’elaborazione dei dati da parte di Access. Probabilmete più utenti stanno tentando di modificare lo stesso record o blocco di record.

Emilio Scaccaglia (emilio.scaccaglia@alice.it)

Annunci

Access – report con colonne affiancate

Se non si ha bisogno dell’intera larghezza della pagina, potrebbe essere utile lavorare con report a colonne affiancate. Questo permette al lettore di avere in una stessa pagina più dati da confrontare. Anche la riduzione delle pagine stampate potrebbe essere significativa. Anche l’estetica risulta avvantaggiata da questa soluzione di stampa.

Per avere più colonne per pagina in un report,  non è necessario ricorrere al codice VBA, basterà accedere alla finestra “Imposta Pagina” del gruppo “Layout” ed accedere alla s cheda ” Colonne”. Appena si cambia il numero delle colonne, si attiva la sezione “Layout Colonne” . L’opzione predefinita è “Priorità Orizzontale” che fa in modo che la stampa proceda prima nel senso della larghezza e poi verso il basso. Questo tipo di impostazione è consigliabile per le etichette adesive, consiglio di scegliere, per un report, “Priorità Verticale” per ottenere colonne affiancate.

Quando si lavora con più colonne affiancate, si deve fare molta attenzione alle opzioni giuste, se non si imposta “Priorità Verticale”, le colonne saranno disposte in orizzontale nella pagina invece di essere correttamente affiancate.

Emilio Scaccaglia

Access – opzioni della riga di comando

Quando si seleziona Access 2007 dal menù Start di Windows, viene eseguito il file di programma MSAccess.exe. Creando in link sul Desktop di Windows ed inserendo nella riga di comando oltre al nome del file di programma di Access anche l’opzione /runtime (MSAccess.exe /runtime), Access si apre senza visualizzare alcun strumento di interfaccia, con il solo pulsante di Office che contiene il solo comando Chiudi database.

L’opzione può essere inserita lanciando il programma dalla finestra Esegui oppure creando in lonk al database sul desktop.

Seguono le opzioni della riga di comando, valide per Access 2007, ricavate dalla guida di access sotto la voce Opzioni della riga di comando per Access.

Nessuna database Consente di aprire il database o il progetto di Microsoft Access specificato. Includere un percorso, se necessario. Se si include un percorso che contiene spazi, racchiudere il percorso tra virgolette.
/excl Nessuno Consente di aprire il database di Access specificato con accesso esclusivo (esclusivo: Tipo di accesso ai dati in un database condiviso in rete. Quando si apre un database in modalità esclusiva, si impedisce agli altri utenti di aprirlo.). Per aprire il database con accesso condiviso in un ambiente multiutente (database multiutente (condiviso): Database che consente a più utenti di accedere e di modificare contemporaneamente lo stesso insieme di dati.), non specificare questa opzione. Si applica solo ai database di Access.
/ro Nessuno Consente di aprire il database o il progetto di Access specificato per l’utilizzo in sola lettura.
/runtime Nessuno Consente di specificare che l’avvio di Access verrà eseguito con le opzioni della versione di runtime.
/user nome utente Consente di avviare Access utilizzando il nome utente specificato. Si applica solo ai database di Access 2002 e 2003 e versioni precedenti.
/pwd password Consente di avviare Access utilizzando la password specificata. Si applica solo ai database di Access 2002 e 2003 e versioni precedenti.
/profile profilo utente Consente di avviare Access utilizzando le opzioni indicate nel profilo utente specificato anziché le impostazioni standard del Registro di sistema di Windows create al momento dell’installazione di Access. Questa opzione sostituisce l’opzione /ini utilizzata nelle versioni di Access precedenti ad Access 95 per specificare un file di inizializzazione.
/compact database di destinazione oppure progetto di Access di destinazione Consente di compattare e ripristinare il database di Access oppure di compattare il progetto di Access specificato prima dell’opzione /compact e quindi di chiudere Access. Se si omette il nome di un file di destinazione dopo l’opzione /compact, il file verrà compattato utilizzando il nome di file e il percorso originali. Per compattarlo con un nome di file diverso, specificare un file di destinazione. Se non si specifica un percorso nel parametro database di destinazione o progetto di Access di destinazione, il file di destinazione verrà creato nella cartella Documenti per impostazione predefinita.

In un progetto di Access questa opzione consente di compattare il file di progetto di Access (con estensione adp) ma non il database di Microsoft SQL Server.

/repair Nessuno Consente di ripristinare il database di Access specificato prima dell’opzione /repair e quindi di chiudere Microsoft Access. In Microsoft Access 2000 e versioni successive le funzionalità di compattazione e ripristino sono state riunite nell’opzione /compact. L’opzione /repair è supportata per motivi di compatibilità con le versioni precedenti.
/convert database di destinazione Consente di convertire un database o un progetto di una versione precedente di Access nel formato di file di Access 2007, di rinominare il nuovo file e quindi di chiudere Access. Prima di utilizzare l’opzione /convert, è necessario specificare il database di origine.
/x macro Consente di aprire il database di Access specificato prima dell’opzione /x e quindi di eseguire la macro specificata. Per eseguire una macro all’apertura di un database, è inoltre possibile creare una macro denominata AutoExec.

Poiché le macro possono contenere virus, è necessario eseguirle con la massima cautela, avendo cura di adottare alcune precauzioni, ad esempio eseguire un software antivirus aggiornato nel computer, utilizzare Centro protezione per disattivare tutte le macro tranne quelle firmate digitalmente e gestire un elenco di fonti attendibili per le macro.

/cmd Nessuno Consente di specificare che le informazioni che seguono l’opzione sulla riga di comando costituiscono il valore che verrà restituito dalla funzione Command. Questa deve essere l’ultima opzione digitata sulla riga di comando. Anziché /cmd è possibile utilizzare un punto e virgola (;).

Utilizzare questa opzione per specificare un argomento della riga di comando che può essere utilizzato nel codice di Visual Basic, Applications Edition (VBA) (Visual Basic, Applications Edition (VBA): Versione in linguaggio macro di Microsoft Visual Basic utilizzata per programmare applicazioni basate su Windows e inclusa in numerosi programmi Microsoft.).

/wrkgrp file di informazioni sul gruppo di lavoro Consente di avviare Access utilizzando il file di informazioni sul gruppo di lavoro specificato. Si applica solo ai database di Access 2002 e 2003 e versioni precedenti.

Access – Controlli ActiveX

I controlli ActiveX sono una famiglia di oggetti software dotati di molteplici funzionalità (metodi e proprietà) utilizzabili in molti contesti di programmazione senza dover riscrivere il loro codice. Sono pacchetti autosufficenti di istruzioni e di dati.

Fisicamente gli ActiveX sono file normalmente inseriti nelle cartelle System e System32 di Windows e si identificano per una delle seguenti estensioni: OCX, DLL, VBX e altri ancora.

Quando si installa un applicativo in Windows, quasi sempre il processo di installazione comporta la copia di file ActiveX nella cartella di Windows predefinita per ospitarli.

Il loro uso, ActiveX, è subordinato a due condizioni, la prima è che l’oggetto ActiveX si registrato nel sistema, la seconda è che il software che deve utilizzarlo, sia abilitato a farlo.

Nota: registrare un oggetto software, significa far sapere al sistema che l’oggetto esiste e dove questo si trovi all’interno del file system. Queste informazioni vengono riportete all’interno del registro di sistema.

Per utilizzare un controllo ActiveX con Access, bisognerà selezionare il comando Inserisci controllo ActiveX.

Non tutti i controlli ActiveX funzioneranno in prodotti software abilitati al loro uso. Alcuni controlli, causa metodi e proprietà non supportabili dal programma, non funzionaeranno correttamente o per nulla.

SQL – query da programma

Query da programma

Le funzioni di aggregazione sui domini sono espressioni predefinite in linguaggio SQL. Con queste espressioni è possibile eseguire query di selezione e di calcolo.

Quando si creano query utilizzando la griglia di struttura grafica, Access costruisce un enunciato SQL, che è quello che viene lanciato per generare i risultati richiesti. E’ possibile creare una quesry direttamente in linguaggio SQL senza passare dalla griglia grafica. La query potrà poi essere lancata usando i comandi RunSQL dell’oggetto DoCmd oppure per mezzo di una macro con l’azione EseguiSQL. Queste due tecniche però, consentono di creare solo quesry di comando o di definizione dati e non le più comuni query di selezione. Per creare ed eseguire questo tipo di query, si hanno a disposizione le funzioni di aggregazione sui domini. La struttura sintattica di queste query corrisponde a quella dell’enunciato SELECT del linguaggio SQL.

Access – funzioni di aggregazione

Si chiama dominio, nella terminologia dei database, l’insieme dei valori validi per un determinato attributo. Un attributo è semplicemente un campo di un record. Per cui il dominio di un attributo chiamato Nome, potrebbe essere l’insieme di tutti i nomi presenti in una determinata tabella.

Le funzioni di aggregazione sui domini restituiscono informazioni su uno specifico dominio. Il concetto di aggregazione insito nel loro nome sta a significare che tali funzioni svolgono il loro lavoro mettendo insieme tutto quello che trovano in un determinato dominio.

DAvg – media dei valori di un campo

DCount – conteggio dei record (il loro numero)

DLookup – ricerca di un valore in un campo

DFirst – primo record che corrisponde a una data specifica

DLast – come DFirst ma cerca l’ultimo record

DMin, DMax – valore minimo e massimo di un campo

DStDev, StDevP – scarto quadratico medioin un dominio

DSum – somma dei valori presenti in un campo

DVar, DVarP – varianza relativa ad un dominio

Access – la funzione SysCmd

Presente in tutte le versioni di Access, la funzione SysCmd consente di eseguire comandi che hanno a che fare col sistema. Il sistema è Access nel suo complesso. Aggiungendo alcuni argomenti alla funzione SysCmd è possibile effettuare le seguenti operazioni:

  1. Accedere ad informazioni su Access e sui suoi file
  2. conoscere lo stato del database, se è aperto o chiuso, modificato o salvato …
  3. visualizzare nella barra di stato, scritte o la barra di avanzamento

Salto la descrizione dei punti 1 e 2, dato che risultano utili quando si costruiscono “creazioni guidate” e saranno oggetto di un post a loro dedicato. Questo post, verrà dedicato al punto 3 che consente di manipolare la barra di stato presente in Access.

La sintassi per gestire la barra di stato è la seguente:

NomeVariabile =  SysCmd(TipoAzione, [Testo], [Valore])

azione è una costante di Access che può avere i seguenti valori ed effetti:

  1. acSysCmdClearStatus;      ripristina lo stato originale della barra
  2. acSysCmdSetStatus;          visualizza del testo nella barra
  3. acSysCmdInitMeter;            inizializza la barra di avanzamento
  4. acSysCmdUpdateMeter;    aggiorna, col valore specificato, la barra di avanzamento
  5. acSysCmdRemovaMeter;  elimina la barra di avanzamento

per far comparire un testo nella StatusBar, si procederà come segue:

Private Sub Form_Open(Cancel As Integer)

Dim MiaVariabile As Variant

MiaVariabile = SysCmd(acSysCmsSetStatus, “Ciao Mondo”)

End Sub

per cancellare la scritta si esegue la seguente istruzione:

MiaVariabile = SysCmd(acSysCmdClearStatus)

MiaVariabile = SysCmd(acSysCmdInitMeter, “La mia Barra”, 100)

dove il numero 100 rappresenta il massimo valore raggiungibile dalla barra di avanzamento.

Access – proprietà dell’applicazione (database)

Le opzioni che si possono impostare nelle pagine della finestra Opzioni di Access, selezionando un valore spuntando una casella di controllo o selezionando una voce in una casella combinata, corrispondono a proprietà dell’oggetto Application.

L’elenco completo, molto lungo, di queste proprietà (Opzioni), si può reperire al seguente indirizzo:

http://msdn2.microsoft.com/en-us/library/aa168263(office.10).aspx

che vi porterà inuna pagina dal titolo Properties Reference

Lo schema sintattico per impostare una di queste opzioni è il seguente:

Application.SetOption(NomeOpzione, Impostazione)

doce Application è un riferimento al database correntemente aperto e NomeOpzione è il nome Inglese della proprietà che si vuole cambiare o conoscere. Impostazione può assumere due valori, Vero/Falso, oppure un semplice valore stringa. Tutti gli argomenti di SetOption sono obbligatori.

Va inoltre considerato che, non tutte le proprietà vengono assegnate a un database quando lo si crea. Per assegnare una proprietà si deve usare il metodo CreateProperty con la seguente struttura sintattica:

database.CreateProperty(“NomeProprietà”, TipoDato, Valore)

database è una variabile che identifica il file del database. NomeProprietà è il nome della proprietà inserito come stringa fra virgolette. TipoDato è il tipo di dato che può essere, dbText o dbBoolean. Valore altro non è che il valore assegnato alla proprietà.

Dopo aver creato la proprietà è necessario accodarla all’insieme Properties del database con il metodo Append. Segue il codice VBA per Append:

database.Properties.Append NuovaProprietà

Per ottenere un elenco delle proprietà assegnate all’avvio del nostro database, possiamo usare la seguente routine:

Public Sub Proprietà()

Dim DB as DAO.Database

Dim strNome as String

Dim K As Integer, j As Integer

Set DB = CurrentDb

j = DB.Properties.Count

For k = 0 To j – 1

    Debug.Print k, DB.Properties(k).Name

Next

End Sub

Access – collegare dati da Excel

Collegare tabelle esterne ad Access usando codice VBA.

Ci sono casi in cui si ha bisogno di collegare dati esterni “al volo”, magari ogni volta che si avvia l’applicazione. In questo esempio userò DAO al posto di ADO in quanto molto più veloce per questo tipo di operazione. Il motivo per cui DAO  è più veloce di ADO in operazioni semplici come per esempio collegare dati esterni, risiede nel fatto che DAO non ha bisogno di tutte le aggiunte portate dalla dichiarazione, istanziazione e chiusura dei controllo ActiveX. Dato che DAO è un modello di oggetti più semplice di ADO, risulta più adatto a operazioni semplici ome l’apertura di una o più tabelle. ADO è sicuramente la scelta da fare quando si devono effettuare operazioni complesse sui dati.

Connect e SourceTableName

Per aprire la finestra immediata, premere i tasti CTRL-G, digitare il seguente codice: ? CurrentDB.TableDefs(“NomeTabella”).Connect

Si otterrà un valore nullo in risposta, ma, se la tabella è una tabella collegata, magari contenuta in un file di Excel, si otterrà il seguente valore: Excel 8.0;HDR)NO;IMEX=2;DATABASE=C:\File\FileExcel.xls dove “C:\File\FileExcel.xls” non è altro che il percorso completo del file con la tabella collegata.

NOTA: la proprietà Connect di una tabella interna al database è nulla perchè la tabella è presente nel database stesso. Non c’è nulla a cui connettersi, melgio, le tabelle presenti del DB sono sempre connesse. Invece le sorgenti dati esterne al DB origine avranno sempre una proprietà Connect che indica ad Access quali tipi di dati sono contenuti nell’origine dati collegata e dove trovare l’origine dei dati.

Se si accede ad un origine dati ISAM, supportata direttamente da Access, la stringa di connessione si ridurrà alla seguente forma: Oggetto.Connect=”Tipo;Database=Percorso” 

La funzione sotto riportata, mostra come connettersi ad un file Excel. Per collegarsi ad un foglio di calcolo, bisogna specificare di che tipo di foglio si tratti, dove si trova il foglio di calcolo e quale intervallo si vuole importare , per esempio, l’intervallo (B10:C35).

L’istruzione seguente richiama la funzione CollExcel per connettere un intervallo chiamato Names a una tabella di nome ExcelDemo. CollExcel(“File.xls”,”ExcelDemo”,”Names”)

Per utilizzare la funzione, la procedura richiede il nome del file di Excel, il nome della nuova tabella Access e un nome valido di iun intervallo di dati di Excel.

La funzione CollExcel restituisce un valore booleano che indica se la connessione al file Excel è riuscita.

Public Function CollExcel( ByVal sFileName As String, ByVal sTablename As String, _
    ByVal sRangeName As String ) As Boolean
 
  Const conCannotOpen = 3432
  Const conNotRange = 3011
  Const conTableExists = 3012

  Dim db As DAO.Database
  Dim td As DAO.Tabledef
 
  Dim sConnect As String
  Dim sMsg As String
  Dim sFunction As String
 
On Error GoTo HandleError
  
  CollExcel = False
  sFunction = “CollExcel”
 
  ‘ Controlla l’esistenza del file di Excel:
  sFileName = CurDir() & “\” & sFileName
  
  If Len(Dir(sFileName)) = 0 Then
    MsgBox “Il file ” & sFileName _
        & ” non è stato trovato!”
    MsgBox “Sposta il file in: ” _
        & CurDir() & ” per continuare.”
    Exit Function
  End If
  Set db = CurrentDb
 
  ‘ Crea una nuova tabledef nel database:
  Set td = db.CreateTableDef(sTablename)
 
  ‘ Stringa di connessione:
  sConnect = “Excel 8.0;HDR=YES;DATABASE=” & sFileName
  td.Connect = sConnect
 
  ‘ Specifica il nome del range dei dati in Excel:
  td.SourceTableName = sRangeName
  
  db.TableDefs.Append td
 
  ‘Restituisce True:
  CollExcel = True
 
ExitHere:
 
  Exit Function
 
HandleError:
 
  Select Case Err
    Case conCannotOpen
        sMsg = “Non posso aprire: ” & sFileName
 
    Case conTableExists
        sMsg = “La tabella ” & sTablename & _
             ” esiste già.”
 
    Case conNotRange
        sMsg = “Non posso trovare il range di dati: ” & sRangeName & ” .”
  
    Case Else
        sMsg = “Error#” & Err & “: ” & Error$
 
  End Select
 
  MsgBox sMsg, vbExclamation + vbOKOnly, _
       “Errore nella Procedura: ” & sFunction
 
  ‘Ritorna False:
  CollExcel = False
 
  Resume ExitHere
 
End Function

Access – collegamento a dati esterni

Il collegamento ai dati esterni, per gli utilizzatori di MS Access è fondamentale. Microsoft Access ha gli strumenti fondamentali per trattare molti tipi di dati esterni. Vecchi database, HTML e XML sono i dati che più spoesso richiedono un collegamento esterno da parte di Access.

Immaginiamo, per esempio, di avere un’applicazione che si collega a un database esterno quale potrebe essere SQL Server, e che la rete si blocchi. Se un utente, che ignora il problema della rete, tenta di collegarsi e di aprire la fonte dati, si verifica un errore che lo mette sicuramente in difficoltà. Potrebbe anche capitare che un applicazione Access che si collega ad un file di Excel determini un errore perchè il file è stato spostao o cancellato o ha subito sostanziali modifiche.

Se quando apriamo l’applicativo creato con Access, controlliamo che tutti i link ai dati esterni siano disponibili, potremmo informare l’utente se qualcosa non è andato per il verso giusto ed eventualmente porvi rimedio.

Segue una funzione, da eseguire all’apertura dell’applicazione Access che, permette di verificare se un link è acora valido. La procedura prova ad accedere ai dati esterni, riceverndo il nome della tabella esterna per mezzo del paramentro “sTablename”. La funzione prova ad aprire la tabella come recordset, se il metodo “OpenRecordset” fallisce, significa che la tabella non esiste o che il collegamento si è perso. In questo sventurato casa, la funzione mostra un messaggio per informare l’utente che si è verificato un problema e che l’applicazione non funzionerà correttamente.

Public Function TestLink(sTablename As String) As Boolean
  Dim db As DAO.Database
  Dim rs As DAO.Recordset
  Dim iStartODBC As Integer
  Dim iEndODBC As Integer
  Dim sDataSrc As String
  Dim iODBCLen As Integer
  Dim sMessage As String
  Dim iReturn As Integer
 
On Error GoTo HandleError
 
  Set db = CurrentDb
 
  ‘Apre un recordset per forzare l’eventuale errore:
  Set rs = db.OpenRecordset(sTablename)
 
  ‘Se il link è valido si esce dalla funzione:
  TestLink = True
 
ExitHere:
 
  If Not rs Is Nothing Then
    rs.Close
    Set rs = Nothing
  End If
 
  If Not db Is Nothing Then
    db.Close
    Set db = Nothing
  End If
 
  Exit Function
 
HandleError:

  ‘Se il link non è valido, si cerca di determinare quale possa essere il problema
  ‘e comunque si esce dalla funzione:
  Select Case Err
     
      Case 3078    ‘La tabella non esiste:
     
          sMessage = “Table ‘” & sTablename & “‘ non esiste in questo database”
     
      Case 3151    ‘link inesistente
          ‘Ricavo il nome dell’odbc DSN
          ‘da usare nel messaggio di errore:
          iStartODBC = InStr(Error, “to ‘”) + 4
         
          iEndODBC = InStr(Error, “‘ failed”)
          iODBCLen = iEndODBC – iStartODBC
         
          sDataSrc = Mid$(Error, iStartODBC, iODBCLen)
         
          sMessage = “Tabella ‘” & sTablename & “‘ è linked a un ODBC datasource ‘” & sDataSrc _

         & “‘ non attualmente disponibile”
     
      Case Else
     
          sMessage = Err.Description
     
  End Select
 
  iReturn = MsgBox(sMessage, vbOKOnly)
 
  ‘Return failure:
  TestLink = False
 
  Resume ExitHere
 
End Function