5.4.2 OLESTREAM and OLESTREAMVTBL

The OLESTREAM structure points to an OLESTREAMVTBL structure, which in turn points to the client-supplied Get and Put functions for stream input and output. These structures are defined in OLE.H as follows:

typedef struct _OLESTREAM

{

LPOLESTREAMVTBL lpstbl;

} OLESTREAM;

typedef struct _OLESTREAMVTBL

{

DWORD (CALLBACK *Get) (LPOLESTREAM, void FAR *, DWORD);

DWORD (CALLBACK * Put) (LPOLESTREAM, void FAR *, DWORD);

} OLESTREAMVTBL;

typedef OLESTREAMVTBL FAR* LPOLESTREAMVTBL;

Figure 31 shows the relationship between OLESTREAM and OLESTREAMVTBL structures:

Figure 31. Relationship between OLESTREAM, OLESTREAMVTBL, and Get and Put callback functions

You will need to create your own OLESTREAM wrapper data structure, keeping the OLESTREAM structure as the first member and adding any additional information needed by your client application. You can name the structure anything you like.

As shown in the following code example, CLIDEMO.EXE defines a structure called APPSTREAM, which includes the OLESTREAM structure as its first member:

typedef struct _APPSTREAM FAR *LPAPPSTREAM;

typedef struct _APPSTREAM {

OLESTREAM olestream;

int fh;

} APPSTREAM;

5.4.2.1 Stream Get and Put Functions

The client DLL uses the Get and Put functions (or your renamed variations) when loading and saving objects. When a client application calls the client DLL to save an object to a stream with the OleSaveToStream function, the client DLL calls the Put function pointed to in OLESTREAMVTBL. When loading an object from a stream, the client DLL calls OleLoadFromStream, which in turn calls the Get function pointed to in OLESTREAMVTBL.

A client application can customize stream functions for particular situations, and a client can make such changes as varying the permanent storage for an object—for example, a client could store an object in a database, instead of in a file with the rest of the document.

Client applications typically store objects in MS-DOS files, so the Get and Put callback functions are often implemented as sequences of _lread and _lwrite function calls (or _hread and _hwrite in the Windows 3.1 system).

Note Your implementation of the Get and Put callback functions need to be able to read or write data from the object's storage location in blocks potentially larger than 64K. If you are developing in the Windows 3.1 environment, this is not a problem as the _hread and _hwrite functions enable an application to read data of this size. However, under Windows 3.0, this support is not available.

As shown in the following code example, CLIDEMO.EXE creates two functions called ReadStream and WriteStream. Each of these functions test the size of the object to determine if the data is larger than 64K.

/

* ReadStream() - OLE Callback Function (Get)

*

* This function is pointed to from the OLESTREAM vtbl; it is Get.

* A branch is made based upon whether or not the read request is

* greater than 64K.

*

* returns DWORD - number of bytes actually read

*/

DWORD FAR PASCAL ReadStream // ENTRY:

(LPAPPSTREAM lpStream, // application stream pointer

LPSTR lpstr, // string pointer

DWORD cb) // byte count

{

if (cb < 0x00010000)

return _lread(lpStream->fh, lpstr, (WORD) cb);

else

return lread(lpStream->fh, lpstr, cb);

}

/*

* lread()

*

* This is function is essentially an _lread() that can read more

* than 64K. We need this due to the fact that objects and files may

* be greater than 64K. This function must be declared PASCAL so

* that it won't conflict with the _lread() function.

*

* returns DWORD - number of bytes actually read

*/

DWORD PASCAL lread // ENTRY:

(HANDLE hFile, // DOS file handle

void FAR *pBuffer, // buffer to be read into from

// hfile

DWORD dwBytes) // byte count

{ // LOCAL:

BYTE huge *hpBuffer = pBuffer; // buffer containing data read

DWORD dwByteCount = dwBytes; // number of bytes read

while (dwByteCount > MAXREAD)

{

if (_lread(hFile, hpBuffer, (WORD)MAXREAD) != MAXREAD)

return(dwBytes - dwByteCount);

dwByteCount -= MAXREAD;

hpBuffer += MAXREAD;

}

if ((dwByteCount -= (DWORD)_lread(hFile, hpBuffer,

(WORD)dwByteCount)))

return(dwBytes - dwByteCount);

return dwBytes; // return

}

/* lwrite()

*

* This function is essentially an _lwrite() which can handle writes

* greater than 64K. This function must be declared PASCAL so that

* it won't conflict with the _lwrite() function.

*

* Returns DWORD - number of bytes actually written

*/

DWORD PASCAL lwrite // ENTRY:

(HANDLE hFile, // DOS file handle

void FAR *pBuffer, // buffer to write to hfile

DWORD dwByt) // number of bytes

{ // LOCAL:

DWORD dwByteCount = dwBytes;// number of bytes to write

BYTE huge *hpBuffer = pBuffer; // buffer of data to write

while (dwByteCount > MAXREAD)

{

if (_lwrite(hFile, (LPSTR)hpBuffer, (WORD)MAXREAD) != MAXREAD)

return(dwBytes - dwByteCount);

dwByteCount -= MAXREAD;

hpBuffer += MAXREAD;

}

if ((dwByteCount -= _lwrite(hFile, (LPSTR)hpBuffer,

(WORD)dwByteCount)))

return(dwBytes - dwByteCount); // less bytes than requested read

return dwBytes; // return

}