Question

I have a VB6 application that takes a recordset as a parameter in one of its functions. I am using ADODB in a .NET project to create and pass the recordset to the VB6 project. When I create the recordset in VS2010 by connecting to the database and then disconnecting, all is well:

con.ConnectionString = "Provider=SQLOLEDB.1;Data Source=MyDB;Initial Catalog=IC;User     ID=user;Password=pass"
rs.ActiveConnection = con
rs.Open("SELECT * FROM Table1")
rs.ActiveConnection = Nothing

However, when I create the recordset by copying the data from a .net DataTable: rsRecordSet = New ADODB.Recordset

For Each dtDataColumn As DataColumn In dtDataTable.Columns
    Select Case dtDataColumn.DataType.UnderlyingSystemType.ToString
        Case "System.Boolean" : dteRecordSetDataType = DataTypeEnum.adBoolean
        Case "System.Byte" : dteRecordSetDataType = DataTypeEnum.adUnsignedTinyInt
        Case "System.Char" : dteRecordSetDataType = DataTypeEnum.adChar
        Case "System.DateTime" : dteRecordSetDataType = DataTypeEnum.adDate
        Case "System.Double" : dteRecordSetDataType = DataTypeEnum.adDouble
        Case "System.Int16" : dteRecordSetDataType = DataTypeEnum.adSmallInt
        Case "System.Int32" : dteRecordSetDataType = DataTypeEnum.adInteger
        Case "System.Int64" : dteRecordSetDataType = DataTypeEnum.adBigInt
        Case "System.SByte" : dteRecordSetDataType = DataTypeEnum.adTinyInt
        Case "System.Single" : dteRecordSetDataType = DataTypeEnum.adSingle
        Case "System.UInt16" : dteRecordSetDataType = DataTypeEnum.adUnsignedSmallInt
        Case "System.UInt32" : dteRecordSetDataType = DataTypeEnum.adUnsignedInt
        Case "System.UInt64" : dteRecordSetDataType = DataTypeEnum.adUnsignedBigInt
        Case "System.Guid" : dteRecordSetDataType = DataTypeEnum.adGUID
        Case "System.String" : dteRecordSetDataType = DataTypeEnum.adVarChar
        Case Else : dteRecordSetDataType = DataTypeEnum.adVarChar
     End Select
     If dtDataColumn.AllowDBNull Then
        faeRecordSetAttribute = FieldAttributeEnum.adFldIsNullable
     Else
        faeRecordSetAttribute = FieldAttributeEnum.adFldUnspecified
     End If
     rsRecordSet.Fields.Append(dtDataColumn.ColumnName, dteRecordSetDataType, dtDataColumn.MaxLength, faeRecordSetAttribute)
Next

rsRecordSet.CursorLocation = CursorLocationEnum.adUseClient
rsRecordSet.CursorType = CursorTypeEnum.adOpenDynamic
rsRecordSet.LockType = LockTypeEnum.adLockOptimistic
rsRecordSet.ActiveConnection = Nothing
rsRecordSet.Open()

For Each dtDataRow As DataRow In dtDataTable.Rows
     rsRecordSet.AddNew()
     For Each rsField As ADODB.Field In rsRecordSet.Fields
         Select Case rsField.Type
              Case DataTypeEnum.adBoolean : rsField.Value = Convert.ToBoolean(dtDataRow.Item(rsField.Name))
               Case DataTypeEnum.adGUID : rsField.Value = "{" & dtDataRow.Item(rsField.Name).ToString & "}"
               Case Else : rsField.Value = dtDataRow.Item(rsField.Name)
         End Select
     Next
Next

Return rsRecordSet

...my VB6 project rejects it right away with errors such as "Operation is not allowed in this context" and "The callee (server [not server application]) is not available and disappeared; all connections are invalid. The call may have executed. (Exception from HRESULT: 0x80010007 (RPC_E_SERVER_DIED))". I have also been having an impossible time debugging the two project together (it worked at one point) to see where in the VB6 project the recordset is being rejected, but I have a feeling it is happening before it even goes into my VB6 function.

I am hoping someone can explain to me the difference between the two different recordsets. Is there information in one recordset somewhere that indicates that it was at one time connected to a database source? Is there a way I can "select" from my existing datatable so that the recordset thinks it pulled from somewhere?

Thanks in advance!

Was it helpful?

Solution

.Net defaults to disconnected recordsets, but VB6 doesn't. The recordset that you have opened in your code is a Dynamic recordset, which is incapable of operating without an open connection. The dynamic cursortype means that all changes to your recordset are posted immediately to the database. When you closed your connection, you couldn't do that anymore. Your errors suggest that the dynamic cursor looked for a connection when you tried to add a new record, and couldn't find one.

You might be interested to check whether your CursorLocation is still adUseClient. It shouldn't be; once you set the type to dynamic, the cursor has to be server side. Either your cursor is static or your location is server.

So, to make a disconnected recordset the properties have to be:

.CursorLocation = adUseClient  
.CursorType = adOpenStatic 'This is automatic as a result of the previous line
.LockType = adLockBatchOptimistic

This last has to do with making batch changes on the disconnected recordset, and then when ready to post locking for the whole batch, posting the records, and then going through a conflict resolution procedure. Anyway, see if that helps you. It should.

A little more: if you just set your location to client-side, the type will default to static. It's the only cursortype that works client side. Kind of makes sense; you're working with a local "snapshot" of your data if it's on the client side.

Here is a simple explanation from back in 1999, when this was cutting edge stuff. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top