OLEDB Data Change Notice

In addition to the previously introduced interfaces, OLEDB also defines some other interfaces that support callbacks, which can operate OLEDB objects asynchronously or get notified of some important events, so that the application has the opportunity to perform some necessary processing. One of the more useful is the change notification interface of the result set object. Through this interface, you can get the data changes of the result set by adding, deleting and modifying in time, and have the opportunity to conduct the necessary data legality audit.

The interface for data change notification is IRowsetNotify, and the asynchronous notification event interface required by the data source object is IDBAsynchNotify.

Standard COM callback method

In order to better understand the callback of OLEDB, first recall the callback method of standard COM.
In addition to providing functions for the application to call actively, the COM component also provides a callback method. This method is implemented by the user to implement the corresponding interface and then called by the COM component, so that we can know the running status of the COM component. , and can handle some situations, such as processing memory exhaustion, getting user input, etc.
A COM component that supports event callbacks must provide the IConnectionPointContainer interface. The caller calls the FindConnectPoint interface of the IConnectionPointContainer interface, finds a specific event mount point through the IID of the callback event, and then calls the Advise method of the interface to associate the mount point with the corresponding callback function Up (an event can correspond to multiple callback functions) so that when the event occurs, the corresponding callback function can be called.
This mechanism is somewhat similar to the signal and slot function mechanism in QT. The events in QT are implementation-defined and can be used directly. Here, you need to find the specific event through the event ID. After you have the event, similar to the QT step, you need to Bind the event to the corresponding callback function.

IRowsetNotify interface

For OLEDB result sets, the most important event interface is IRowsetNotify, which provides three important notification functions:

  • OnFieldChange: The column data has changed
  • OnRowChange: The row has changed, especially when a row is deleted or inserted
  • OnRowsetChange: Modified data is submitted

Through the specific implementation of these event functions, setting different return values ​​can control the response of the result set object to the modification. For example, returning S_OK means accepting the modification, and returning S_FALSE explicitly refuses to accept the modification. This gives an eventual repentance mechanism.
These functions have two important parameters:

  • DBREASON: The reason for the change
  • DBEVENTPHASE: The stage when the event is triggered
    By judging the combination of these two parameters, the dynamic tracking and situation of data changes in the result set can be accurately judged

Relevant values ​​for the DBREASON parameter

  • DBREASON_ROW_ASYNCHINSERT: Asynchronous insert
  • DBREASON_ROWSET_FETCHPOSITIONCHANGE: The row pointer of the result set changes, triggered when calling something like IRowset::GetNextRows or IRowset::RestartPosition
  • DBREASON_ROWSET_RELEASE: Triggered when the result set is released
  • DBREASON_ROWSET_CHANGED: Triggered when some metadata in the database changes. This means that some information describing the database table fields changes, such as the size and type of table fields. To modify these data, the user needs to have certain permissions. Under normal circumstances does not trigger this reason
  • DBREASON_COLUMN_SET: Triggered when row data is set (here only existing row data is set, excluding new rows), generally triggered when SetData is called
  • DBREASON_COLUMN_RECALCULATED: Triggered when the value of the column changes, usually by calling SetData
  • DBREASON_ROW_ACTIVATE: Triggered when the user modifies the row pointer and causes the row's status to change from inactive to active
  • DBREASON_ROW_RELEASE: Triggered when ReleaseRows is called to release some row handles
  • DBREASON_ROW_DELETE: Fired when a row is deleted
  • DBREASON_ROW_FIRSTCHANGE: When a column of some rows is set to a new value and then the pointer of the current row is changed, it will be triggered for the first time, and its trigger will be earlier than DBREASON_COLUMN_SET, this event will only be used when the delayed update is used. time will arise.
  • DBREASON_ROW_INSERT: fires when a new row is inserted
  • DBREASON_ROW_UNDOCHANGE: Triggered when Undo is called to abandon the modification
  • DBREASON_ROW_UNDOINSERT: Triggered when Undo is called to give up inserting a new row
  • DBREASON_ROW_UNDODELETE: Triggered when Undo is called to abandon the deletion
  • DBREASON_ROW_UPDATE: Triggered when Update is called to update

DBEVENTPHASE

This parameter indicates the current execution state. The general operation data result set has 5 states, which correspond to the following 5 values:

  • DBEVENTPHASE_OKTODO: Ready to do, when the application needs to operate the result set, it will send a DBEVENTPHASE_OKTODO to the listener (in this case, it is understood as the data source of OLEDB), the listener will not immediately execute the action after receiving it. Instead, it will return S_OK to indicate that it knows about the request, or S_FALSE to reject the request
  • DBEVENTPHASE_ABOUTTODO: When the data source returns S_OK for DBEVENTPHASE_OKTODO, the application will give a signal to inform the data source that it can perform the final preparatory work before executing the action. After this is completed, the data source will asynchronously execute the relevant request operation
  • DBEVENTPHASE_DIDEVENT: When the data source executes this request, it will reach this state, and the data in the database table has been updated.
  • DBEVENTPHASE_FAILEDTODO: This state will be entered when an error occurs in a previous step, and a rollback will occur at this time to restore the data to the original state.

The following is a data state transition diagram, which vividly shows various state changes during the execution of an operation.
state transition diagram

How to use the result set object event notification interface

  1. Define a class derived from the IRowsetNotify interface and implement all the methods in its interface
  2. Set the DBPROP_IConnectionPointContainer property in the result set object property set DBPROPSET_ROWSET to VARIANT_TRUE
  3. get result set object
  4. Call the IRowset::QueryInterface method to get the IConnectionPointContainer interface pointer
  5. Call the IConnectionPointContainer::FindConnectionPoint method to get the IConnectionPoint interface pointer corresponding to the IRowsetNotify interface
  6. Instantiate a class created in the first step
  7. Call IConnectionPoint::Advise and pass the object pointer
  8. Operates on the result set object. At this time, if the event condition is established, the result set object will call the corresponding method of the object to notify the caller what event was triggered

For details, please refer to MSDN IRowsetNotify

example

Finally, let's look at the specific example used

class CCOMRowsetNotify:
    public IRowsetNotify
{
public:
    CCOMRowsetNotify(void);
    virtual ~CCOMRowsetNotify(void);

protected:
    virtual HRESULT FindConnectionPointContainer(IUnknown *pIUnknown, REFIID rrid, IConnectionPoint* &pIcp);
public:
    virtual HRESULT Addvise(IUnknown *pIUnknown, REFIID rrid);
    virtual HRESULT UnAddvise(IUnknown *pIUnknown, REFIID rrid);

public:
    virtual STDMETHODIMP_(ULONG) AddRef(void);
    virtual STDMETHODIMP_(ULONG) Release(void);
    virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);

    virtual STDMETHODIMP OnFieldChange (IRowset *pRowset, HROW hRow, DBORDINAL cColumns, DBORDINAL rgColumns[], DBREASON eReason, DBEVENTPHASE ePhase,BOOL fCantDeny);
    virtual STDMETHODIMP OnRowChange (IRowset *pRowset, DBCOUNTITEM cRows,const HROW rghRows[], DBREASON eReason, DBEVENTPHASE   ePhase, BOOL fCantDeny);
    virtual STDMETHODIMP OnRowsetChange (IRowset *pRowset, DBREASON eReason, DBEVENTPHASE ePhase, BOOL fCantDeny);

protected:
    ULONG m_uRef;
    DWORD m_dwCookie;
};

When using, first define a class derived from IRowsetNotify and implement all interface methods

if (!OpenTable(pIOpenRowset, pIRowsetChange))
{
        COM_PRINTF(_T("打开表失败\n"));
        goto __CLEAN_UP;
}

RowsetNotify.Addvise(pIRowsetChange, IID_IRowsetNotify);

HRESULT CCOMRowsetNotify::FindConnectionPointContainer(IUnknown *pIUnknown, REFIID rrid, IConnectionPoint* &pIcp)
{
    IConnectionPointContainer* pICpc = NULL;
    HRESULT hr = pIUnknown->QueryInterface(IID_IConnectionPointContainer,(void**)&pICpc);
    if(FAILED(hr))
    {
        COM_PRINTF(_T("通过IRowset接口获取IConnectionPointContainer接口失败,错误码:0x%08X\n"),hr);
        return hr;
    }
    hr = pICpc->FindConnectionPoint(rrid,&pIcp);
    if(FAILED(hr))
    {
        COM_PRINTF(_T("获取IConnectionPoint接口失败,错误码:0x%08X\n"),hr);
        COM_SAFE_RELEASE(pIcp);
        return hr;
    }

    return hr;
}

HRESULT CCOMRowsetNotify::Addvise(IUnknown *pIUnknown, REFIID rrid)
{
    IConnectionPoint *pIcp = NULL;
    HRESULT hRes = FindConnectionPointContainer(pIUnknown, rrid, pIcp);
    if (S_OK != hRes)
    {
        return hRes;
    }

    hRes = pIcp->Advise(dynamic_cast<IRowsetNotify*>(this), &m_dwCookie);
    COM_SAFE_RELEASE(pIcp);
    return hRes;
}

The above code first opens the data result set, and then calls the Addvise method of the class object to pass in the IID_IRowsetNotify interface pointer. The main operation in the method Addvise is to first use the incoming interface pointer to find the interface IConnectionPointContainer, and then use the FindConnectionPoint method of the IConnectionPointContainer interface to find The corresponding mount point, and finally call the Advise method of IConnectionPointContainer to mount the corresponding class object on the mount point, so that the corresponding On function will be called when the result set is manipulated later to complete the processing of the corresponding event.

Finally put the link of the complete code
click here to get the complete code


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325299886&siteId=291194637