Sending and Receiving Objects

You use IReplObjHandler to serialize or convert an object to a series of bytes. It also deserializes an object or converts the bytes back to an object to transmit data to a device or desktop. There is no limitation or specification on how to serialize an object. A desktop provider module can serialize the object into any number of bytes, and it can group these bytes into any number of packets.

Whenever an object requires serialization, the service manager calls the IReplObjHandler methods in the following order:

  1. IReplObjHandler::Setup to tell the desktop provider module what object to serialize and to enable the desktop provider module to allocate any resources that are required for serialization.
  2. IReplObjHandler::GetPacket to let the desktop provider module create one or more packets of bytes of any size.

    The service manager calls this method repeatedly until RWRN_LAST_PACKET is returned.

  3. IReplObjHandler::Reset to let the desktop provider module free any used resources.

    The service manager calls this method when serialization is completed.

The service manager does not recognize byte format during serialization. The service manager simply sends the packets in the same byte number and sequence as they were originally received.

The following illustration shows the sequence of calls necessary to send and receive data.

The following code example shows how to implement IReplObjHandler::Setup and IReplObjHandler::GetPacket. It also shows the definition for CDataHandler, which is a COM class whose base is IReplStore.

class CDataHandler : public IReplObjHandler
{
public:
    CDataHandler( CStore *pStore );
    ~CDataHandler();

    // ******** IUnknown methods **************
    // AddRef, Release, QueryInterface
    
    // ******** IReplObjHandler methods **************
    // Setup, Reset, GetPacket, SetPacket, DeleteObj

private:
    long     m_cRef;
     PREPLSETUP m_pWriteSetup, m_pReadSetup;
};

STDMETHODIMP CDataHandler::Setup
( 
    PREPLSETUP pSetup    // Points a REPLSETUP structure, which contains // information about the object to be serialized // or deserialized.
)
{
    // Could be reading and writing at the same time, so it is necessary     // to save the pointer to set up the structure differently.
    if ( pSetup->fRead )
        m_pReadSetup = pSetup;
    else
        m_pWriteSetup = pSetup;

    return NOERROR;
}

STDMETHODIMP CDataHandler::GetPacket
( 
    LPBYTE  *lppbPacket,        // Pointer to the pointer of the outgoing 
                            // packet
    DWORD   *pcbPacket,        // Pointer to a DWORD for the packet size
    DWORD   cbRecommend         // Recommended maximum size of the packet
)
{
     if ( m_pReadSetup->hItem == NULL )
        return E_UNEXPECTED;

     // Initialize the packet. 

// ...

    // Fill up the packet.

// ...

    // Assign the size of the packet to *pcbPacket and the packet
    // to *lppbPacket.
    //*pcbPacket = sizeof( packet );
    //*lppbPacket = (LPBYTE)&packet;

    return NOERROR;     
    //Return RWRN_LAST_PACKET if it is the final packet.
}

During synchronization, the service manager creates an instance of IReplObjHandler for each object type. The desktop provider module recognizes when IReplObjHandler::SetPacket is sending information about a new object by checking for RSF_NEW_OBJECT in REPLSETUP::dwFlags. The service manager passes REPLSETUP::dwFlags in the IReplObjHandler::Setup call. The structure REPLSETUP is passed in IReplObjHandler::Setup.

The following table shows the REPLSETUP members that are used by the desktop provider module. All other members are internal to the service manager and should not be changed.

REPLSETUP member
Description
fRead Set to TRUE for reading an object from the desktop store.

Set to FALSE for writing an object to the desktop store.

dwFlags A collection of bit flags related to serialization and deserialization.
Hfolder A handle to the folder.
HItem A handle to the object to be serialized. The desktop provider module uses the information in this handle to identify and convert the object into packets of bytes.

The process of receiving an object from the device is similar to sending an object to the device. After the packets of data arrive from the device, the service manager calls the IReplObjHandler interface methods, which enable the desktop provider module to convert those packets back into an object. The desktop provider module must take the data packets and create an object. It then must create a new HREPLITEM that represents the object in REPLSETUP::hItem.

The IReplObjhandler methods are always called in the following sequence:

  1. IReplObjHandler::Setup tells the desktop provider module what object to deserialize and enables the desktop provider module to allocate any resource needed for deserialization.
  2. IReplObjHandler::SetPacket sends packets to the desktop provider module so that it can recreate the object.

    Packets are sent in the exact same number, size, and sequence. The service manager calls this method repeatedly until the last packet is received from the device.

  3. IReplObjHandler::Reset enables the desktop provider module to free any used resources.

    The service manager calls this method when deserialization is completed.

When the service manager writes an object to the desktop store, it calls IReplStore::UpdateItem. This prompts the desktop provider module to open the object and update the HREPLITEM handle with a time stamp or version number, thus ensuring that the object is not marked as changed on the desktop.

The following code example shows how to implement IReplStore::UpdateItem.

STDMETHODIMP_(void) CStore::UpdateItem
(
    HREPLFLD    hFolder,    // Handle of a folder
    HREPLITEM   hItemDst,   // Handle of the destination object
    HREPLITEM   hItemSrc    // Handle to the source object
)
{
    CFolder *pFolder = (CFolder *)hFolder;
    CItem   *pItemDst = (CItem *)hItemDst;
    CItem   *pItemSrc = (CItem *)hItemSrc;

    if ( pItemSrc )
    {
        pItemDst->m_ftModified = pItemSrc->m_ftModified;
    }
    else 
    {
        // Implementation should update whatever it has used to validate
        // object changes, such as a time stamp, by reading it from the         // object.

        // Update the time stamp.
        // pItemDst->m_ftModified = time stamp read from object.
    }
}

Depending on the type of application, a desktop provider module may synchronize objects coming from a device as deletions. For example, when a user deletes an e-mail message on a device, the message is moved to the Deleted Item folder and marked as changed. The desktop provider module receives the changed object and automatically attempts to delete the message on the desktop. In response, IReplObjHandler::SetPacket returns one of the following errors: