在前面的主题中,我们添加了一个 ActiveX DLL 工程到 AXData 示例中。在这个步骤中,我们将创建一个实现 OLE DB Simple Provider (OSP) 接口的类来访问保存在一个文本文件中的数据。
注意 该主题是帮助您创建示例数据源系列主题的一部分。创建数据源是第一部分。
要创建 MyOSPObject 类,请按照以下步骤执行:
| 属性 | 设置值 |
| (Name) | MyOSPObject |
您可能已经注意到 DataSourceBehavior 被设置为 none。如果这个部件将作为一个数据源的话,难道 DataSourceBehavior 不应该设置为另外的值吗?不要担心,在后面的步骤中我们将添加另一个类,这个类为该部件提供了数据源能力。
Option Explicit
Implements OLEDBSimpleProvider
Dim MyOSPArray()
Dim RowCount As Integer
Dim ColCount As Integer
Dim colListeners As New Collection
Dim ospl As OLEDBSimpleProviderListener
Public FilePath As String
注意 OLEDBSimpleProvider 的 Implements 关键字的使用。记住,Implements 象一个合约,它意味着您需要实现 OLEDBSimpleProvider 类的所有接口。
Public Sub LoadData() '这个过程从一个分号隔离的文件加载数据'到一个数组。Dim GetLine As VariantDim Spot As Integer, Position As IntegerDim Row As Integer, Col As IntegerOn Error GoTo ErrorTrapOpen FilePath For Input Lock Read Write As #1Position = 1Row = 0Line Input #1, GetLineSpot = InStr(1, GetLine, ";")RowCount = val(Left$(GetLine, Spot))ColCount = val(Right$(GetLine, Len(GetLine) - Spot))ReDim MyOSPArray(RowCount + 1, ColCount + 1)While Not EOF(1)Line Input #1, GetLineCol = 1Spot = InStr(1, GetLine, ";")While Spot <> 0MyOSPArray(Row, Col) = Left$(GetLine, Spot - 1)Col = Col + 1GetLine = Right$(GetLine, Len(GetLine) - Spot)Spot = InStr(1, GetLine, ";")WendIf Len(GetLine) <> 0 ThenMyOSPArray(Row, Col) = GetLineEnd IfRow = Row + 1WendClose #1Exit SubErrorTrap:Err.Raise (E_FAIL)End SubPublic Sub SaveData()'这个过程将一个数组中的数据写到一个分号隔离'的文件中。Dim PutLine As VariantDim iRow As Integer, iCol As IntegerOn Error GoTo ErrorTrapOpen FilePath For Output Lock Read Write As #1Print #1, RowCount & ";" & ColCountFor iRow = 0 To RowCountFor iCol = 1 To ColCountPutLine = PutLine & MyOSPArray(iRow, iCol) & ";"Next iColPrint #1, PutLinePutLine = ""Next iRowClose #1Exit SubErrorTrap:Err.Raise (E_FAIL)End Sub
Private Sub Class_Terminate() On Error Resume Next '调用SaveData方法SaveDataEnd Sub
要实现 OLEDBSimpleProvider,请按照以下步骤执行:
因为 MyOSPObject 类实现 OLEDBSimpleProvider 类,即使不使用它的所有接口,我们也必须实现它们:
Private Sub OLEDBSimpleProvider_addOLEDBSimpleProviderListener _ (ByVal pospIListener As OLEDBSimpleProviderListener) '添加一个listener到Listeners集合。If Not (pospIListener Is Nothing) ThenSet ospl = pospIListenercolListeners.Add osplEnd IfEnd Sub
Private Function OLEDBSimpleProvider_deleteRows _ (ByVal iRow As Long, ByVal cRows As Long) As Long Dim TempArray() Dim listener As OLEDBSimpleProviderListener Dim v As Variant '确保iRow是在正确的范围:If iRow < 1 Or iRow > RowCount ThenErr.Raise (E_FAIL)End If'设置cRows为可以删除的实际数目If iRow + cRows > RowCount + 1 ThencRows = RowCount - iRow + 1End If'建立一个临时数组cNewRows = RowCount - cRowsReDim TempArray(cNewRows + 1, ColCount + 1)'通知每一个listener:For Each v In colListenersSet listener = vlistener.aboutToDeleteRows iRow, cRowsNext'复制删除行前面的行For Row = 0 To iRow - 1For Col = 0 To ColCountTempArray(Row, Col) = MyOSPArray(Row, Col)Next ColNext Row'复制删除行后面的行For Row = iRow + cRows To RowCountFor Col = 0 To ColCountTempArray(Row - cRows, Col) = MyOSPArray(Row, Col)Next ColNext Row'重新分配要复制到的目标数组ReDim MyOSPArray(cNewRows + 1, ColCount + 1)'重新设置回实际的行计数RowCount = cNewRows'复制这些行For Row = 0 To cNewRowsFor Col = 0 To ColCountMyOSPArray(Row, Col) = TempArray(Row, Col)Next ColNext Row'清除临时数组ReDim TempArray(0)'通知每一个listenerFor Each v In colListenersSet listener = vlistener.deletedRows iRow, cRowsNext'返回删除行的数目OLEDBSimpleProvider_deleteRows = cRowsEnd Function
Private Function OLEDBSimpleProvider_find(ByVal iRowStart As Long, _ ByVal iColumn As Long, ByVal val As Variant, _ ByVal findFlags As OSPFIND, ByVal compType As OSPCOMP) As Long Dim RowStart As Integer, RowStop As Integer If (findFlags And (OSPFIND_UP Or OSPFIND_UPCASESENSITIVE)) _ <> 0 Then RowStart = RowCount + 1 RowStop = 0 StepValue = -1 Else RowStart = 0 RowStop = RowCount + 1 StepValue = 1 End If If (findFlags And (OSPFIND_CASESENSITIVE Or _ OSPFIND_UPCASESENSITIVE)) <> 0 Then CaseSens = 1 '使用区分大小写的文本比较ElseCaseSens = 0 '不区分大小写,使用二进制比较End IfIf VarType(val) = vbString ThenStringComp = TrueElseStringComp = FalseEnd IfiAnswerRow = -1For iRow = RowStart To RowStop Step StepValueIf StringComp ThenCompResult = StrComp(MyOSPArray(iRow, iColumn), _val, CaseSens)Select Case (compType)Case OSPCOMP_DEFAULT, OSPCOMP_EQ:If CompResult = 0 TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_GEIf CompResult >= 0 TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_GTIf CompResult > 0 TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_LEIf CompResult <= 0 TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_LTIf CompResult < 0 TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_NEIf CompResult <> 0 TheniAnswerRow = iRowExit ForEnd IfEnd SelectElseSelect Case (compType)Case OSPCOMP_DEFAULT, OSPCOMP_EQ:If MyOSPArray(iRow, iColumn) = val TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_GEIf MyOSPArray(iRow, iColumn) >= val TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_GTIf MyOSPArray(iRow, iColumn) > val TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_LEIf MyOSPArray(iRow, iColumn) <= val TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_LTIf MyOSPArray(iRow, iColumn) < val TheniAnswerRow = iRowExit ForEnd IfCase OSPCOMP_NEIf MyOSPArray(iRow, iColumn) <> val TheniAnswerRow = iRowExit ForEnd IfEnd SelectEnd IfNext iRowOLEDBSimpleProvider_find = iAnswerRowEnd Function
Private Function OLEDBSimpleProvider_getColumnCount() As Long
OLEDBSimpleProvider_getColumnCount = ColCount
End Function
Private Function OLEDBSimpleProvider_getEstimatedRows() As Long
OLEDBSimpleProvider_getEstimatedRows = RowCount
End Function
Private Function OLEDBSimpleProvider_getLocale() As String
OLEDBSimpleProvider_getLocale = ""
End Function
注意在这种情况下,该函数只返回一个 null 值。即使它没有做任何工作,也必须添加该函数,因为这个类实现 OLEDBSimpleProvider,必须包括它的所有接口。
Private Function OLEDBSimpleProvider_getRowCount() As Long
OLEDBSimpleProvider_getEstimatedRows = RowCount
End Function
Private Function OLEDBSimpleProvider_getRWStatus _ (ByVal iRow As Long, ByVal iColumn As Long) As OSPRW If iColumn = 1 Then '使第一列只读OLEDBSimpleProvider_getRWStatus = OSPRW_READONLYElse'使该列可读写OLEDBSimpleProvider_getRWStatus = OSPRW_READWRITEEnd IfEnd Function
Private Function OLEDBSimpleProvider_getVariant _
(ByVal iRow As Long, ByVal iColumn As Long, _
ByVal format As OSPFORMAT) As Variant
OLEDBSimpleProvider_getVariant = MyOSPArray(iRow, iColumn)
End Function
GetVariant 函数也接受一个格式变量,该变量用于确定返回数据的格式。
Private Function OLEDBSimpleProvider_insertRows _ (ByVal iRow As Long, ByVal cRows As Long) As Long Dim TempArray() Dim listener As OLEDBSimpleProviderListener Dim v As Variant '建立一个临时数组cNewRows = RowCount + cRowsReDim TempArray(cNewRows + 1, ColCount + 1)'如果插入超过数组的结尾,则插入到'数组的结尾If iRow > RowCount TheniRow = RowCount + 1End If'通知listenerFor Each v In colListenersSet listener = vlistener.aboutToInsertRows iRow, cRowsNext'复制现存的行For Row = 0 To iRowFor Col = 0 To ColCountTempArray(Row, Col) = MyOSPArray(Row, Col)Next ColNext Row'复制插入行后面的行For Row = iRow + 1 + cRows To cNewRowsFor Col = 0 To ColCountTempArray(Row, Col) = MyOSPArray(Row - cRows, Col)Next ColNext Row'重新分配复制到的目标数组ReDim MyOSPArray(cNewRows + 1, ColCount + 1)'复制这些行For Row = 0 To cNewRowsFor Col = 0 To ColCountMyOSPArray(Row, Col) = TempArray(Row, Col)Next ColNext Row'清除临时数组ReDim TempArray(0)'重新设置回实际行的计数RowCount = cNewRows'通知listenerFor Each v In colListenersSet listener = vlistener.insertedRows iRow, cRowsNext'返回插入的行数OLEDBSimpleProvider_insertRows = cRowsEnd Function
Private Function OLEDBSimpleProvider_isAsync() As Long
OLEDBSimpleProvider_isAsync = False
End Function
Private Sub OLEDBSimpleProvider_removeOLEDBSimpleProviderListener _ (ByVal pospIListener As OLEDBSimpleProviderListener) '删除此listenerFor i = 1 To colListeners.CountIf colListeners(i) Is pospIListener ThencolListeners.Remove iEnd IfNextEnd Sub
Private Sub OLEDBSimpleProvider_setVariant(ByVal iRow As Long, _
ByVal iColumn As Long, ByVal format As OSPFORMAT, _
ByVal Var As Variant)
Dim listener As OLEDBSimpleProviderListener
Dim v As Variant
For Each v In colListeners
Set listener = v
listener.aboutToChangeCell iRow, iColumn ' Pre-notification
Next
MyOSPArray(iRow, iColumn) = Var
For Each v In colListeners
Set listener = v
listener.cellChanged iRow, iColumn ' Post-notification
Next
End Sub
Private Sub OLEDBSimpleProvider_stopTransfer() '不做任何工作,因为已经充填完毕End Sub
注意在这个过程中没有任何代码,但是必须包括这个过程,因为该类实现 OLEDBSimpleProvider。您可以在这里添加代码,该代码允许您在一个长时间传送期间取消加载。
即使看上去好象代码很多,但它的理由也很充分,MyOSPObject 类提供了几乎在一个数据库中能够找到的所有功能。通过 OSP,在过去使用一个数据库的地方您可以使用几乎所有的文件。
在下一个步骤中,我们将创建另一个类,该类将作为到 MyOSPObject 类的数据源。
该主题是帮助您创建示例 ActiveX 数据源系列主题的一部分。
| 要 | 请参阅 |
| 到下一步骤 | 创建 MyDataSource 类 |
| 从头开始 | 创建数据源 |