Handling SQL-DMO Events

The SQL-DMO Backup, BulkCopy, Replication, Restore, SQLServer, and Transfer objects are connectable COM objects, supporting callback to the client application.

For connectable objects, COM defines the responsibilities for servers and clients. A connectable object exposes the IConnectionPointContainer interface, through which the client obtains the IConnectionPoint interface. The client implements functions to handle callbacks from the server, called a sink. Using the IConnectionPoint interface, the client notifies the server of its ability to handle callbacks, providing its sink implementation as an argument.

The client-implemented sink is a COM object. As with any COM application development task, implementing a sink for any SQL-DMO connectable object is fairly painless when using C++. The client application defines a class, inheriting from a defined SQL-DMO sink interface definition, then implements members to handle the callbacks of interest. The example below illustrates class definition and partial inline implementation for a COM object that can be connected to a SQLServer object instance:

class CSQLServerSink : public ISQLDMOServerSink

{

public:

    CSQLServerSink();

  

    ~CSQLServerSink()

        { ; }

  

    // IUnknown interface on all COM objects.

    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj);

  

    // AddRef has an inline implementation.

    STDMETHOD_(ULONG, AddRef) (THIS)

        {return (++m_uiRefCount);}

  

    STDMETHOD_(ULONG, Release) (THIS);

  

  

    // Sink properties and methods. Implement CommandSent,
   // ConnectionBroken, QueryTimeout and RemoteLoginFailed as no
   // operation.

    STDMETHOD(CommandSent) (THIS_ SQLDMO_LPCSTR strSQL)
       {return (NOERROR);}

  

    STDMETHOD(ConnectionBroken) (THIS_ SQLDMO_LPCSTR strMsg,
       LPBOOL pbRetry)

        {return (NOERROR);}

  

    STDMETHOD(QueryTimeout) (THIS_ SQLDMO_LPCSTR strMsg,
       LPBOOL pbContinue)
       {return (NOERROR);}

  

    STDMETHOD(RemoteLoginFailed) (THIS_ long lMsgSeverity,
       long lMsgNumber, long MsgState, SQLDMO_LPCSTR strMsg)
       {return (NOERROR);}

  

    // Code implementing sink method ServerMessage is shown elsewhere.

    STDMETHOD(ServerMessage) (THIS_ long lMsgSeverity, long lMsgNumber,

        long MsgState, SQLDMO_LPCSTR strMsg);

  

private:

    // Keeping track of ourselves.

    UINT            m_uiRefCount;

  

    // Used to format status messages from handled ServerMessage event.

    TCHAR           m_acMessage[2048];

};

Implementing the QueryInterface and Release functions is done in standard fashion as:

HRESULT STDMETHODCALLTYPE CSQLServerSink::QueryInterface(
   THIS_ REFIID riid, LPVOID* ppvObj)

    {

    if ((riid == IID_IUnknown) || (riid == IID_IWSQLDMOServerSink))

        {

        AddRef();

        *ppvObj = this;

  

        return (NOERROR);

        }

  

    return (E_NOINTERFACE);

    }

and:

ULONG STDMETHODCALLTYPE CSQLServerSink::Release(THIS)

    {

    --m_uiRefCount;

  

    if (m_uiRefCount == 0)

        delete this;

  

    return (m_uiRefCount);

    }

Reference counting on COM objects implies a constructor such as the following:

CSQLServerSink::CSQLServerSink()

    {

    m_uiRefCount = 0;

    }

And finally, the implementation of the function handling the ServerMessage callback. The example shows using a message box to display the status messages received by the application.

HRESULT STDMETHODCALLTYPE CSQLServerSink::ServerMessage

    (

    THIS_ long lMsgSeverity,

    long lMsgNumber,

    long MsgState,

    SQLDMO_LPCSTR szMsg

    )

    {

#ifdef UNICODE

    swprintf(m_acMessage, L"%s", szMsg);

#else

    sprintf(m_acMessage, "%S", szMsg);

#endif

  

    MessageBox(NULL, m_acMessage, _T("SQLServer Status Message"),
       MB_OK | MB_ICONINFORMATION);

  

    return (NOERROR);

    }

With the class defined and its members implemented, an object instance of the class can be connected to a SQLServer object instance, as shown below:

BOOL CSQLServerHandler::InstallConnectionPoint(

    LPSQLDMOSQLSERVER pSQLServer)

    {

    LPCONNECTIONPOINTCONTAINER  piCPContainer = NULL;

    HRESULT             hr;

    CSQLServerSink*     pSQLServerSink;

  

    // Create an instance of the SQLServer sink.

    pSQLServerSink = new CSQLServerSink;

  

    if (pSQLServerSink != NULL)

        {

        hr = pSQLServer->QueryInterface(

            IID_IConnectionPointContainer, (void**) &piCPContainer);

  

        if (SUCCEEDED(hr))

            {

            // m_pCP is a CSQLServerHandler member variable (a pointer

            // to an IConnectionPoint). The connection point will be
           // used both to advise the SQLServer object of event
           // handling and to terminate event handling later. For that
           // reason, the variable is not local in scope to this
           // function.

            hr = piCPContainer->FindConnectionPoint(
               IID_ISQLDMOServerSink, &m_pCP);

  

            if (SUCCEEDED(hr))

                m_pCP->Advise(pSQLServerSink, &m_dwCookie);

  

            piCPContainer->Release();

            }

        }

  

    // If anything fails, delete the instance of CSQLServerSink that

    // was created. Otherwise, the self-destruct mechanism in
   // CSQLServerSink::Release will handle object destruction.

    if (FAILED(hr))

        {

        hrDisplayError(hr);

        

        delete pSQLServerSink;

        }

  

    return (SUCCEEDED(hr));

    }

When an application connects to a connectable object, it becomes responsible for breaking that connection when it is no longer required. An example is shown below:

void CSQLServerHandler::ReleaseConnectionPoint()

    {

    if (m_dwCookie != _BAD_COOKIE)

        m_pCP->Unadvise(m_dwCookie);

  

    if (m_pCP != NULL)

        {

        m_pCP->Release();

        m_pCP = NULL;

        }

    }


Note The details of COM connectable object implementation are beyond the scope of this documentation. For more information about COM connectable objects, IConnectionPointContainer, and IConnectionPoint, see a reliable COM/OLE reference.


  


(c) 1988-98 Microsoft Corporation. All Rights Reserved.