
IE4/MSHTML supports a very simple, easily implemented API for
exposing data to HTML pages. The API supports access to string
and variant data types and is built using array-like structures
to expose rows and columns. Third parties can use the OLE-DB
Simple Provider API to implement their custom data source
objects.
Introduction
OLE-DB Simple Provider
OLE-DB Simple Provider Listener
OLE-DB Simple Provider (OSP) is an interface specification
that hosts can implement to expose their tabular data to HTML
elements in IE4/MSHTML. OSP specifies only simple, minimal
functionality that requires only minimal effort on the part of
control/applet authors to expose their data. OSP specifies
methods for adding, deleting, and setting the value of columns,
searching through the set of data and receiving notifications on
data events.
OLE-DB Simple Provider was formerly called Simple Tabular Data,
or STD for short.
OSP exposes a set of tabular data (data set) in an array-like
structure. Elements of the data set are referenced by their row
and column indices.
Data References
Indices begin with value 1 and increase. There are two
special index values:
- 0
- Reserved for label information in the case of a
row, and header information in the case of a
column.
- -1
- The wildcard value. Refers to an unknown value or
all values. For example, Row=-1, Col=2 refers to
the entire column 2.
OSP defines two distinct interfaces: OLEDBSimpleProvider and
OLEDBSimpleProviderListener. As you would expect,
OLEDBSimpleProvider implements the methods used for data access
and OLEDBSimpleProviderListener specifies the methods to be
implemented by the host for receiving notification of data
changes.
Interface ID
The OLEDBSimpleProvider interface is identified by the
following IID:
{E0E270C0-C0BE-11d0-8FE4-00A0C90A6341}
The methods implemented by OLEDBSimpleProvider can be broken
down into the following logical areas.
Schema functions
Three functions are provided for obtaining the schema for
the underlying rows or columns.
- HRESULT
getRowCount([out, retval] LONG *pcRows)
- Returns the number of rows in the data set.
- HRESULT
getColumnCount( [out,retval] LONG *pcColumns)
- Returns the number of columns in the data set.
- HRESULT
getRWStatus([in] LONG iRow, [in] LONG iColumn,
[out, retval] OSPRW *prwStatus)
- Returns the read/write status for the specified
row and column. If one or both of iRow and iColumn have value -1, then
the read/write status is returned for the entire
column, row, or complete data set.
OSPRW is an
enumeration with the following values:
| OSPRW_READONLY
|
cell, row, column, or
data set is read-only
|
| OSPRW_READWRITE
OSPRW_DEFAULT
|
cell, row, column, or
data set can be modified
|
| OSPRW_MIXED
|
cell, row, column, or
data set read-write status unknown OR
row, column or data set mixed status
|
Variant-Oriented Functions
Two functions are provided to allow retrieval and setting
of variant values in the data set.
- HRESULT
getVariant([in] LONG iRow, [in] LONG iColumn,
[in] OSPFORMAT fFormatted, [out, retval] VARIANT
*pVar)
- Retrieves the value of the cell at the row and
column indicated into the pre-allocated variant
supplied in pVar. Based on the value
specified in fFormatted , pVar will
contain either a value with the type of the
underlying column, a string that corresponds to
the underlying type of the column, or an HTML
fragment that corresponds to the underlying type
of the column.
- HRESULT
setVariant([in] LONG iRow, [in] LONG iColumn,
[in] OSPFORMAT fFormatted, [in, retval] VARIANT
Var)
- Sets the value of the cell at the row and column
indicated to the value of the variant supplied in
pVar in the
type requested by the value of fFormatted
OSPFORMAT is an
enumeration with the following values:
| OSPFORMAT_RAW OSPFORMAT_DEFAULT
|
the underlying type of
the column should be used to either set
the value or get the value
|
| OSPFORMAT_FORMATTED
|
the underlying type of
the column should be converted to a
string and the string returned as a BSTR
within the variant
|
| OSPFORMAT_HTML
|
the underlying type of
the column should be converted to an HTML
string.
|
- Notes:
- For both functions, as per
the definition of VARIANT, references are
not supported.
- For setVariant() with any
of the formatting options, it is the
provider's responsibility to perform the
appropriate coercion to the underlying
type of the column. In cases where the
coercion cannot be successfully
completed, an appropriate error return
code should be returned.
- For setVariant() with OSPFORMAT_FORMATTED, the provider is free to
interpret the input string however it
sees fit. Alternatively, the provider may
attempt to parse the input string and
heuristically determine an appropriate
data type and value to place into the
cell. For example, when updating
formatted spreadsheet cells.
- When OSPFORMAT_HTML is requested, the provider may,
at its option, return a plain string
(unadorned with HTML tags, etc.).
- A database NULL is
indicated by returning a variant of type
VT_NULL for any of the fFormatted types.
- Wildcard values
(-1) are not valid for the iRow and iColumn attributes in setVariant() or getVariant().
Deletion and Insertion:
Functions are provided to insert and delete rows. For all
functions, the row numbers provide the position within
the data set to which the row will be inserted. That is,
the row inserted will have the index specified.
- HRESULT
deleteRows([in] LONG iRow, [in] LONG cRows, [out,
retval] LONG *pcRowsDeleted)
- Deletes cRows
from the data set starting at row iRow. The number of rows
successfully deleted is returned in pcRowsDeleted.
- HRESULT
insertRows([in] LONG iRow, [in] LONG cRows, [out,
retval] LONG *pcRowsInserted)
- Inserts cRows
into the data set starting at row iRow. The number of rows
successfully inserted is returned in pcRowsInserted.
- Notes:
- In the case of an error,
the provider may choose to insert/delete
rows up to the point where the error
occurred. In such a case, the [out]
parameter specifies the number of rows
actually inserted/deleted.
- Values for the inserted
rows are not specified. Use the setVariant() function to set the value of
the cells inserted.
Searching
A function is provided which supports some basic
searching capability on the data set. The goal of this
function is to be fairly easy for the provider to
implement while providing the client with a meaningful
set of functionality to perform complex searching.
HRESULT
find([in] LONG iRowStart, [in] LONG iColumn,
[in]
VARIANT varSval, [in] OSPFIND findFlags,
[in]
OSPCOMP compType,
[out,
retval] LONG *piRowFound)
Searches for the values specified in varSval in column iColumn starting at row iRowStart . Upon successful
completion, the row number with the matching value is
returned in piRowFound.
Supported values for OSPFIND are:
| OSPFIND_UP
|
Specifies scan should be
decreasing in row number.
|
| OSPFIND_CASESENSITIVE
|
Specifies that search should be
case sensitive.
|
Supported values for OSPCOMP are:
| OSPCOMP_LT
|
Specifies we are
searching for the first value less than varSval
|
| OSPCOMP_LE
|
Specifies we are
searching for the first value less than or equal
to varSval
|
| OSPCOMP_GT
|
Specifies we are
searching for the first value greater than varSval
|
| OSPCOMP_GE
|
Specifies we are
searching for the first value greater than or
equal to varSval
|
| OSPCOMP_EQ
OSPCOMP_DEFAULT
|
Specifies we are
searching for the first value equal to varSval
|
| OSPCOMP_NE
|
Specifies we are
searching for the first value not equal to varSval
|
- Notes:
- Find() does compares using
the native type of the underlying column.
Providers are encouraged to simply fail
when the type of the varSval differs from the underlying type
of the column.
- Comparing string values
always compares values as they would be
returned from a call to GetVariant() with
OSPFORMAT_FORMATTED. Providers should not
coerce values of varSval
obtained from a previous call to
GetVariant() with OSPFORMAT_HTML.
- If no corresponding match
is found, Find() should return the
constant -1.
Asynchronous Data
Population
The main function of an OSP is to provide data to an HTML
page. In many cases, the data will need to be transported
over high-latency, low bandwidth networks, in most cases
using a 28.8K modem. The OSP design accounts for making
data available as expediently as possible while
maintaining an architecture and interface specification
that is easy to author.
All OSP authors are encouraged
to implement support for populating (or retrieving) the
data they expose asynchronously. This allows the host to
continue processing during data transmission instead of
blocking on a call to the OSP until the entire data set
has been transmitted to the client.
The majority of the work required to support
asynchronous data delivery does not involve the OSP
interface specifically - it is a requirement on the
mechanisms to retrieve data from their underlying
storages. Accordingly, three methods are required in the
OSP interface: one to indicate whether the provider
supports asynchronous population; one to return the
progress of the asynchronous population; and a third to
stop the asynchronous transmission of data.
Two additional events are added to the OSP event
notifications. One event indicates when additional data
has become available for access through the interface
while the other signals that the asynchronous data
population has completed. Both events are specified below
in the OLE-DB Simple Provider Events
section.
- HRESULT
isAsync( [out, retval] BOOL *pbAsynch)
- Returns a boolean indicating whether data is
being populated asychronously.
- Notes:
- IsAsynch() should never block - it should
always return the appropriate state.
-
- HRESULT
getEstimatedRows( [out, retval] LONG *piRows)
- Returns the estimated total number of rows in the
data set. Callers can use this in conjunction
with GetRowCount() with an asynchronous provider
to obtain an estimate of the percentage of data
received.
- Notes:
- When the number of rows in
the data set cannot be estimated, the
provider should return the special value -1.
- Synchronous providers
should not block on the call to GetEstimatedRows(). They should either return -1
to indicate that they cannot return
provide an estimate or the actual row
count (same as would be obtained through GetRowCount()).
- Providers should
not return the final row count
from EstimatedRows prior to
firing the TransferComplete() event (see below).
-
- HRESULT
stopTransfer()
- Requests that the OSP discontinue asynchronous
transfer of data.
- Notes:
- Providers should make
every effort to expose the data
transferred prior to receiving this
request. The provider must expose a
valid, consistent OSP interface for such
data - appropriate column/row count,
read/write status, etc.
- Providers that cannot
expose the data transferred prior to this
request should discontinue the transfer
of data and fail all subsequent calls to
the OSP interface.
Internationalization
Implementers may have to consider cases where the
consumer is running in a different locale from the source
of the data. The provider is responsible for ensuring
that data conversions are done in an appropriate fashion.
In particular be careful in cases where the string
representation of many data types differs according to
locale. For example, the float or double number 3.14
would be "3.14" in the US, and "3,14"
in Germany. Date representations differ even more. For
example, number (especially float, date) to string
conversions done by GetVariant or SetVariant with the OSP_FORMATTED option
specified should usually be done in the locale of the
browser.
The Find method has more complicated issues to
deal with to implement its ordered comparisons correctly
across locale boundaries. These comparisons should, where
possible, also be done in the locale of the browser,
although this issue is not as clear cut. (For example, if
the data consists of strings containing European accented
characters, it is not clear that a browser in the en-us
locale has any preferred sorting order for these strings.
The sorting order of the provider locale might be more
useful.)
It is anticipated that there will be cases where the
consumer will need to know the locale of the data in
order to perform proper operations on that data. A method
is provided for the provider to return this information.
- HRESULT
getLocale([out,retval] BSTR *pbstrLocale)
- Returns a string in pbstrLocale
which indicates the locale of the data returned
by GetLocale() .
This is used to perform the appropriate type
conversions.
- Notes:
- GetLocale() should
simply return the empty string
("") when the provider does not
support localization. This will allow the
consuming entity to use the default from
the operating system.
- For all values of pbstrLocalethe category LC_ALL is assumed
by the consumer.
Sinking Events
Methods are provided to attach and detach a unicast event
handler for all events.
- HRESULT
addOLEDBSimpleProviderListener([in]
OLEDBSimpleProviderListener *posplListener)
- Registers the event handler interface specified
by posplListener
to receive notifications of changes to data.
- Notes:
- If an event handler was
specified previously, addOLEDBSimpleProviderListener() releases the previous event
handler prior to registering posplListener.
- OSP events are unicast
only. There can be only one listener.
- HRESULT
removeOLEDBSimpleProviderListener([in]
OLEDBSimpleProviderListener *posplListener)
- Unregisters the event handler interface specified
by posplListener.
- Notes:
- removeOLEDBSimpleProviderListener()
should always specify the posplListener
previously registered. In the event that
posplListener differs from the event
handler registered, the call should fail.
OSP implementers fire notifications of changes to the
underlying data through a single event handler. There are pre-
and post- notifications for each event.
Interface ID
The OLEDBSimpleProviderListener interface can be
identified by the following IID:
{E0E270C1-C0BE-11d0-8FE4-00A0C90A6341}
The event handler, registered through OLEDBSimpleProvider::addOLEDBSimpleProviderListener(),
should implement the following methods:
- HRESULT
aboutToChangeCell([in] LONG iRow, [in] LONG
iColumn)
- Indicates that the cell(s) indicated are about to
change. This notification is fired when values
are modified through SetVariant()
or internally by a provider. AboutToChangeCell() should
fire before any data values are changed.
- Notes:
- Calls to GetVariant() should return the original,
unchanged value(s) prior to the return of
control from firing the AboutToChangeCell() event.
- AboutToChangeCell(), the value -1 can be specified
for iRow, iColumn,
or both.
- HRESULT
cellChanged([in] LONG iRow, [in] LONG iColumn)
- Indicates that the cell(s)
indicated were changed. This notification is
fired when values are modified through SetVariant() or internally by a provider.
- Notes:
- CellChanged() should be
fired after the data value(s) has
changed. All subsequent calls to GetVariant() should
return the new value(s).
- In CellChanged(), the value -1 can be specified
for iRow, iColumn,
or both.
- HRESULT
aboutToDeleteRows([in] LONG iRow, [in] LONG
cRows)
- Indicates that cRows
beginning at row iRow
are about to be deleted. This notification is
fired just prior to the rows being deleted either
from a call to DeleteRows()
or internally by the provider.
- Notes:
- Access to cells in the
deleted rows should remain valid until
control is returned from the
AboutToDeleteRows() function.
- HRESULT
deletedRows([in] LONG iRow, [in] LONG cRows)
- Indicates that cRows
were deleted beginning at row iRow. This notification is
fired when a rows are deleted through DeleteRows() or
internally by a provider.
- Notes:
- DeletedRows() should be
fired after the rows are deleted.
- HRESULT
aboutToInsertRows([in] LONG iRow, [in] LONG
cRows)
- Indicates that cRows
beginning at row iRow
are about to be inserted. This notification is
fired just prior to the rows being inserted
either from a call to InsertRows()
or internally by the provider.
- HRESULT
insertedRows([in] LONG iRow, [in] LONG cRows)
- Indicates that cRows
were inserted beginning at row iRow. This notification is
fired when a rows are inserted through InsertRows() or
internally by a provider.
- HRESULT
rowsAvailable([in] LONG iRow, [in] LONG cRows)
- Indicates that cRows
beginning at iRow are now available. This is
useful for providers that obtain and expose their
data asynchronously. The event notifies
consumers that additional data is available.
- Notes:
- OSP consumers expect
periodic notifications when data is
available since they will likely be
displaying or processing the data as it
arrives. Providers should weigh the
advantages of code simplification by
firing the event once for each row
against the performance impact of doing
so.
- HRESULT
transferComplete([in] OSPXFER doneReason)
- All providers must fire this event to indicate
that the data transfer is complete. The event
should be fired after the entire data set exposed
by the provider is available. doneReason indicates whether
the population was completed successfully,
aborted or was stopedthe reason for why data
population is complete.
Supported values for
OSPXFER are:
| OSPXFER_COMPLETE
|
Indicates that the data
transmission is completed successfully.
|
| OSPXFER_ABORT
|
Indicates that the data transmission
is completed due to a call to the Stop
method.
|
| OSPXFER_ERROR
|
Indicates that the data transmission
completed in an error state.
|
- Notes:
- For providers that
retrieve their data asynchronously, this
event signifies that no additional RowsAvailable() events will be called for this
data set.
Notes for all events functions:
- The returned value is propagated back to
the function which resulted in the notification. That is,
if CellChanged() returns E_BADVALUE, the SetVariant() function will also return E_BADVALUE.
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.