& # 8220; Variabile oggetto o Con variabile blocco non impostata & # 8221; errore di runtime in VB6
-
05-07-2019 - |
Domanda
Ho un problema con VB6. Ho un modulo con diversi oggetti ComboBox su di esso. Desidero popolare i ComboBox tramite una funzione che accetta una query SQL come parametro. Quindi il codice è simile a questo
Private Function FillComboBoxFromMDB(ByVal sDBName As String, _
ByVal sSQL As String) As ComboBox
'/*
' * Execute SQL in MDB and fill the ComboBox with the results
' * Returns filled ComboBox
' */
Dim DB As Database
Dim DBRecordset As Recordset
On Error GoTo FillComboBoxFromMDB_ErrHandler
Set DB = OpenDatabase(sDBName, False, False)
If Not DB Is Nothing Then
Set DBRecordset = DB.OpenRecordset(sSQL)
If Not DBRecordset Is Nothing Then
If DBRecordset.RecordCount > 0 Then
Call FillComboBoxFromMDB.AddItem(DBRecordset.Fields(0).Value)
' ^^ This row gives the "Object variable or With block variable not set"
End If
Else
Call WriteLog("Unable to execute " & sSQL)
End If
DB.Close
Else
Call WriteLog("Unable to open " & sDBName)
End If
Exit Function
FillComboBoxFromMDB_ErrHandler:
Call WriteLog("FillComboBoxFromMDB() error: " & Err.Number & " " & Err.Description)
End Function
Chiamo la funzione in questo modo.
Private Function Test()
' Fill the combobox
frmMyForm.cmbMyCombo = FillComboBoxFromMDB("Database.mdb", _
"SELECT MyTable.MyText FROM MyTable")
End Function
Quindi in pratica capisco che questo si riduce all'istanza, ma non ho trovato nulla di utile al riguardo online. La nuova parola chiave non funziona come funziona in VB.Net. Come posso creare un'istanza della casella combinata FillComboBoxFromMDB affinché la funzione funzioni? È anche possibile?
Grazie in anticipo!
Soluzione
Il codice esprime la convinzione che l'identificatore FillComboBoxFromMDB
abbia acquisito un riferimento alla casella combinata sul lato sinistro del compito nella procedura Test.
Questo non è il caso in cui la funzione verrà eseguita per prima con FillCombBoxFromMDB che è Nothing una volta che tenterà (e non riuscirà) di assegnare il risultato sul lato sinistro.
Devi passare la casella combinata come parametro.
Private Sub FillComboBoxFromMDB(ByVal sDBName As String, _
ByVal sSQL As String, ByVal cbo As ComboBox)
'/*
' * Execute SQL in MDB and fill the ComboBox with the results
' * Returns filled ComboBox
' */
Dim DB As Database
Dim DBRecordset As Recordset
On Error GoTo FillComboBoxFromMDB_ErrHandler
Set DB = OpenDatabase(sDBName, False, False)
If Not DB Is Nothing Then
Set DBRecordset = DB.OpenRecordset(sSQL)
If Not DBRecordset Is Nothing Then
If DBRecordset.RecordCount > 0 Then
Call cbo.AddItem(DBRecordset.Fields(0).Value)
' ^^ This row gives the "Object variable or With block variable not set"
End If
Else
Call WriteLog("Unable to execute " & sSQL)
End If
DB.Close
Else
Call WriteLog("Unable to open " & sDBName)
End If
Exit Sub
FillComboBoxFromMDB_ErrHandler:
Call WriteLog("FillComboBoxFromMDB() error: " & Err.Number & " " & Err.Description)
End Sub
Chiamalo così: -
Private Function Test()
' Fill the combobox
Call FillComboBoxFromMDB("Database.mdb", _
"SELECT MyTable.MyText FROM MyTable", _
frmMyForm.cmbMyCombo )
End Function
Altri suggerimenti
Che il problema con il funzionamento con i moduli vb6 controlli, possono essere istanziati solo in un modulo. Che strana cavallina! Oh sì, puoi registrare la DLL in cui risiedono i controlli. Divertiti con quello! Mi sono imbattuto in questo con il socket tcp / ip.
La mia soluzione era quella di creare un'interfaccia SocketDriver. Creare un modulo e inserire il socket nel modulo. Rendi invisibile il modulo. Implementare l'interfaccia SocketDriver sul modulo. Ora puoi passare SocketDriver in giro.
Mi piace la risposta di Anthony, tranne per il fatto che avrei creato un'interfaccia chiamata 'DataFiller' con un metodo.
Public Sub AddItem(item As String)
End Sub
Quindi implementare sul modulo.
Public Sub AddItem(item As String)
cmbMyCombo.AddItem(item)
End Sub
Ora usa la firma
Private Sub FillComboBoxFromMDB(ByVal sDBName As String, _
ByVal sSQL As String, ByVal injectWith As DataFiller)
'yada yada code
injectWith.AddItem(DBRecordset.Fields(0).Value)
'yada yada code
End Sub
Private Function Test()
' Fill the combobox
FillComboBoxFromMDB("Database.mdb", _
"SELECT MyTable.MyText FROM MyTable", frmMyForm)
End Function
Usando l'interfaccia puoi avere una certa separazione delle preoccupazioni. Il tuo accesso ai dati non sa nulla di moduli o controlli e i tuoi from e controlli non sanno da dove provengano quei dati perché la dipendenza è su un'interfaccia
D: Cos'è FillComboBoxFromMDB impostato prima di chiamare AddItem?
A: Niente, ecco perché ottieni l'errore
Prova a definire una variabile come
Dim Value as ComboBox
Quindi chiamando AddItem su questo
Value.AddItem(...)
quindi alla fine della funzione hai
FillComboBoxFromMDB = Value
O come l'altra risposta se non vuoi usare un tipo di ritorno come stavi cercando di usare.
Hai una funzione che afferma che il suo tipo di ritorno è ComboBox
, ma non riesco a vedere da nessuna parte dove tu abbia mai effettivamente impostato il valore di ritorno. Poiché il valore restituito non è mai impostato, sarà Nothing
, quindi l'errore quando si accede ad esso.
Dal caso d'uso fornito, penso che ciò che desideri sia una subroutine di supporto che funzioni su una casella combinata esistente . Quindi lo chiameresti così:
' Fill the combobox
FillComboBoxFromMDB(frmMyForm.cmbMyCombo, _
"Database.mdb", _
"SELECT MyTable.MyText FROM MyTable")
e la stessa subroutine avrebbe una firma come questa:
Private Sub FillComboBoxFromMDB (ByVal cbo come ComboBox, _ ByVal sDBName As String, _ ByVal sSQL As String)
(nota che si tratta di un Sub
non di un Function
). All'interno del corpo della subroutine, dove hai
Call FillComboBoxFromMDB.AddItem(DBRecordset.Fields(0).Value)
invece ha
cbo.AddItem(DBRecordset.Fields(0).Value)
per agire sul ComboBox
passato nella subroutine.
Ho riscontrato lo stesso problema in vb6 e ho trovato anche una soluzione.
Il motivo alla base del problema era,
la mia procedura memorizzata aveva più istruzioni select.
Soluzione: ho usato SET NOCOUNT ON
all'inizio della procedura memorizzata e SET NOCOUNT OFF
appena prima dell'istruzione di selezione (output) finale.