& # 8220; Variable de objeto o Con variable de bloque no establecida & # 8221; error de tiempo de ejecución en VB6
-
05-07-2019 - |
Pregunta
Tengo un problema con VB6. Tengo un formulario con varios objetos ComboBox en él. Deseo rellenar los ComboBoxes a través de una función que toma una consulta SQL como parámetro. Así que el código se ve así
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
Llamo a la función como esta.
Private Function Test()
' Fill the combobox
frmMyForm.cmbMyCombo = FillComboBoxFromMDB("Database.mdb", _
"SELECT MyTable.MyText FROM MyTable")
End Function
Básicamente, entiendo que esto se reduce a la creación de instancias, pero no he encontrado nada útil al respecto en línea. La nueva palabra clave no funciona como funciona en VB.Net. ¿Cómo puedo crear una instancia del cuadro combinado FillComboBoxFromMDB para que la función funcione? ¿Es incluso posible?
Gracias de antemano!
Solución
Su código expresa la creencia de que el identificador FillComboBoxFromMDB
ha adquirido una referencia al cuadro combinado en el lado izquierdo de la tarea en el procedimiento de Prueba.
Este no es el caso, la función se ejecutará primero con FillCombBoxFromMDB siendo Nothing una vez que intentará (y fallará) asignar el resultado al lado izquierdo.
Debes pasar el cuadro combinado como parámetro.
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
Llámalo así: -
Private Function Test()
' Fill the combobox
Call FillComboBoxFromMDB("Database.mdb", _
"SELECT MyTable.MyText FROM MyTable", _
frmMyForm.cmbMyCombo )
End Function
Otros consejos
El problema de trabajar con el formulario vb6 controla que solo se pueden crear instancias en un formulario. ¡Qué maldita mierda! Oh sí, puedes registrar la DLL en la que residen los controles. ¡Diviértete con eso! Me encontré con esto con el socket TCP / IP.
Mi solución fue crear una interfaz SocketDriver. Crear un formulario y poner el socket en el formulario. Hacer la forma invisible. Implementar la interfaz SocketDriver en el formulario. Ahora puedes pasar el SocketDriver.
Me gusta la respuesta de Anthony, excepto que hubiera creado una interfaz llamada 'DataFiller' con un método.
Public Sub AddItem(item As String)
End Sub
Luego implementa en tu formulario.
Public Sub AddItem(item As String)
cmbMyCombo.AddItem(item)
End Sub
Ahora 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
Al usar la interfaz puede tener una cierta separación de preocupaciones. Su acceso a los datos no sabe nada sobre los formularios o controles, y sus valores y controles no saben de dónde provienen esos datos porque la dependencia está en una interfaz
P: ¿Qué es FillComboBoxFromMDB configurado antes de llamar a AddItem?
R: Nada, es por eso que obtienes el error
Intenta definir una variable como
Dim Value as ComboBox
Luego llamando al AddItem en este
Value.AddItem(...)
luego al final de la función tenemos
FillComboBoxFromMDB = Value
O como la otra respuesta si no desea utilizar un tipo de retorno como el que estaba tratando de usar.
Tiene una función que afirma que su tipo de devolución es ComboBox
, pero no puedo ver en ningún lugar donde haya establecido el valor de devolución. Dado que el valor de retorno nunca se establece, será Nothing
, de ahí su error cuando acceda a él.
Desde el caso de uso que proporciona, creo que lo que quiere es una subrutina auxiliar que funcione en un cuadro combinado existente . Así que lo llamarías así:
' Fill the combobox
FillComboBoxFromMDB(frmMyForm.cmbMyCombo, _
"Database.mdb", _
"SELECT MyTable.MyText FROM MyTable")
y la subrutina en sí tendría una firma como esta:
Private Sub FillComboBoxFromMDB (ByVal cbo As ComboBox, _ ByVal sDBName como cadena, _ ByVal sSQL As String)
(tenga en cuenta que es un Sub
no una Function
). Dentro del cuerpo de la subrutina, donde tienes
Call FillComboBoxFromMDB.AddItem(DBRecordset.Fields(0).Value)
en lugar de tener
cbo.AddItem(DBRecordset.Fields(0).Value)
para actuar sobre el ComboBox
que se pasó a la subrutina.
Enfrenté el mismo problema en vb6 y también encontré una solución.
La razón detrás del problema fue,
mi procedimiento almacenado tenía múltiples declaraciones selectas.
Solución: usé SET NOCOUNT ON
en el inicio del procedimiento almacenado y SET NOCOUNT OFF
justo antes de la declaración de la selección final (salida).