在C++、Delphi等高级语言应用程序中,使用流进行输入输出操作已经成为了不可缺少的部分。长时间用惯了Delphi,偶尔用一下C,总觉得直接使用文件函数和内存管理函数很不方便,于是便写了几个C语言流函数,考虑到有时要用到接口流IStream,如我在《在C语言Windows应用程序中使用GDI+》介绍的C语言GDI+图像操作函数就用到了IStream,所以便修改成了本文介绍的内容。

    下面是是我用C写的有关流的结构和函数代码文件,文件中与流操作无关的内容都进行了删除:

    定义头文件:

/**************************************************************************/
*
* Module Name:
*
*   Common_c.h
*
* 湖北省公安县统计局  毛泽发  2009.10
*
/**************************************************************************/

#ifndef __COMMON_C_H
#define __COMMON_C_H

#include <windows.h>
#include <pshpack8.h>   /* set structure packing to 8 */

/******************************************************************************
* 功能:分配锁定的全局内存                                                    *  
* 参数:size:要求分配的内存长度                                              *  
*       isZreo:是否清零分配的内存                                            *  
* 返回:分配成功的内存指针,失败NULL                                          *
******************************************************************************/
LPVOID AllocGlobal(DWORD size, BOOL isZreo);
#define	AllocMem(size)		AllocGlobal(size, FALSE)

/******************************************************************************
* 功能:重新分配锁定的全局内存                                                *
* 参数:ptr:由AllocGlobal或者ReAllocGlobal返回的内存指针                     *
*  		newSize:新的内存长度                                                 *
*		isZreo:是否清零分配的内存                                            *
* 返回:重新分配的内存指针;如果失败且ptr为有效内存,返回ptr,否则返回NULL    *
* 备注:1、newSize=0也返回NULL;                                              *
*		2、因为失败后有可能返回原地址ptr,可使用宏GetMemSize获取实际内存长度  *
******************************************************************************/
LPVOID ReAllocGlobal(LPVOID ptr, DWORD newSize, BOOL isZreo);
#define	ReAllocMem(ptr, newSize)	ReAllocGlobal(ptr, newSize, FALSE)

/******************************************************************************
* 功能:释放分配的全局内存                                                    *  
* 参数:ptr:由AllocGlobal或者ReAllocGlobal返回的内存指针                     *  
* 返回:成功TRUE                                                              *
******************************************************************************/
BOOL FreeGlobal(LPVOID ptr);
#define	FreeMem(ptr)		FreeGlobal(ptr)

#define	GetMemSize(ptr)		GlobalSize(GlobalHandle(ptr))

typedef enum                /* 打开文件方式 */
{
    FileOpenCreate,         /* 建立新文件读写,文件已存在则截断 */
	FileOpenRead,           /* 打开已存在文件供读 */
    FileOpenWrite,          /* 打开已存在文件供写 */
    FileOpenReadWrite       /* 打开已存在文件供读写 */
}FileOpenMode;

typedef enum                /* 文件共享方式 */
{
	FileShareNone,          /* 不共享 */
	FileShareRead,          /* 允许后续打开读 */
	FileShareWrite,         /* 允许后续打开写 */
	FileShareReadWrite      /* 允许后续打开读写 */
}FileShareMode;

/******************************************************************************
* 功能:打开文件                                                              *
* 参数:fileName:文件名称                                                    *
*		mode:打开文件方式                                                    *
*		share:文件共享方式                                                   *
* 返回:成功文件句柄,失败NULL或者(HANDLE)(-1)                                *
******************************************************************************/
HANDLE FileOpen(LPCTSTR fileName, FileOpenMode mode, FileShareMode share);

/******************************************************************************
* 功能:建立一个可读写且不共享的新文件,如果文件已经存在则截断                *
* 参数:fileName:文件名称                                                    *
* 返回:成功文件句柄,失败NULL或者(HANDLE)(-1)                                *
******************************************************************************/
HANDLE FileCreate(LPCTSTR fileName);

/******************************************************************************
* 功能:关闭文件                                                              *
* 参数:handle:文件句柄                                                      *
* 返回:成功TRUE                                                              *
******************************************************************************/
BOOL FileClose(HANDLE handle);

/******************************************************************************
* 功能:从文件读取数据                                                        *
* 参数:handle:文件句柄                                                      *
*		buffer:缓冲区指针                                                    *
*		count:要求读取的字节数                                               *
* 返回:实际读取的字节数,出错-1                                              *
******************************************************************************/
LONG FileRead(HANDLE handle, VOID* buffer, LONG count);

/******************************************************************************
* 功能:写入数据到文件                                                        *
* 参数:handle:文件句柄                                                      *
*		buffer:缓冲区指针                                                    *
*		count:写入的字节数                                                   *
* 返回:实际写入的字节数,出错-1                                              *
******************************************************************************/
LONG FileWrite(HANDLE handle, const VOID* buffer, LONG count);

/******************************************************************************
* 功能:移动文件数据指针                                                      *
* 参数:handle:文件句柄                                                      *
*		offset:移动的字节数,正数向后移,负数向前移                          *
*		origin:移动方式(0开始位置;1当前位置;2结尾)                         *
* 返回:当前数据指针位置,出错-1                                              *
******************************************************************************/
INT64 FileSeek(HANDLE handle, INT64 offset, DWORD origin);

/******************************************************************************
* 功能:设置文件长度                                                          *
* 参数:handle:文件句柄                                                      *
*		size:要求的文件长度                                                  *
*		count:要求读取的字节数                                               *
* 返回:成功TRUE                                                              *
******************************************************************************/
BOOL FileSetSize(HANDLE handle, INT64 size);

/******************************************************************************
*   定义流结构Stream。结构与IStream兼容,可直接转换为IStream使用,因此有关流  *
* 操作的方法以函数指针形式定义在结构中。                                      *
*                                                                             *
*   如果作为IStream使用流,要配对调用lpVtbl->AddRef和lpVtbl->Release,调用    *
* lpVtbl->QueryInterface时,也相当于调用了一次lpVtbl->AddRef。                *
*                                                                             *
*   可调用与各种流相关的建立函数建立流,用毕要调用结构中Destroy方法进行销毁。 *
* 如果强制转换或者通过lpVtbl->QueryInterface赋值给IStream变量后,不能再调用   *
* Destroy方法(由最后一次lpVtbl->Release自动销毁)。                          *
*																		      *
*   由于各种流操作采取相同的方法,有些函数和数据类型并不适用于所有流:如有关  *
* 对流写入的函数应用于只读性质的流(如资源流和以只读方式建立的文件流)会失败;*
* INT64类型表示参数也不适合所有流,如内存流和资源流最大长度只能为长整形,     *
* 超出范围会操作失败等。                                                      *
******************************************************************************/

typedef struct Stream   Stream, *PStream;

struct Stream
{

	CONST_VTBL IStreamVtbl *lpVtbl; /* IStream 结构指针 */
	VOID	*data;                  /* 数据结构指针 */

	/*** 销毁流结构(转换为Istream使用后不要调用)。***/
	VOID 	(*Destroy)(PStream stream);
	/*** 关闭流。由Destroy内部调用,如果具体的流没提供该函数,则为NULL ***/
	VOID	(*ShutDown)(PStream stream);
	/*** 清除流数据。成功返回TRUE ***/
	BOOL 	(*Clear)(PStream stream);
	/* 读取count字节数据到buffer,返回实际读取字节数,出错返回-1 */
	LONG 	(*Read)(PStream stream, VOID* buffer, LONG count);
	/* 将buffer的count字节数据写入流,返回实际写入字节数,出错返回-1 */
	LONG 	(*Write)(PStream stream, const VOID* buffer, LONG count);
	/* 以origin方式移动流指针offset字节,返回当前流指针位置。(参见FileSeek函数) */
	INT64 	(*Seek)(PStream stream, INT64 offset, DWORD origin);
	/*** 从source的当前指针位置拷贝count字节到当前流指针处,count<=0拷贝source
	   当前指针位置到结束的全部数据,成功返回TRUE ***/
	BOOL 	(*CopyFrom)(PStream stream, PStream source, INT64 count);
	/*** 获取流长度 ***/
	INT64 	(*GetSize)(PStream stream);
	/* 设置流长度为newSize,成功返回TRUE */
	BOOL 	(*SetSize)(PStream stream, INT64 newSize);
	/*** 获取流的当前指针位置 ***/
	INT64 	(*GetPosition)(PStream stream);
	/*** 设置流的当前指针位置为newPosition,返回实际指针位置 ***/
	INT64 	(*SetPosition)(PStream stream, INT64 newPosition);
	/*** 保存流数据到dest当前指针位置,成功返回TRUE ***/
	BOOL	(*SaveToStream)(PStream stream, PStream dest);
	/*** 保存流数据到文件fileName,成功返回TRUE ***/
	BOOL	(*SaveToFile)(PStream stream,  LPCTSTR fileName);
	/*** 覆盖装入source的全部数据,成功返回TRUE ***/
	BOOL	(*LoadFromStream)(PStream stream, PStream source);
	/*** 覆盖装入文件fileName的全部数据,成功返回TRUE ***/
	BOOL	(*LoadFromFile)(PStream stream,  LPCTSTR fileName);

};

/******************************************************************************
*   CreateStream建立并返回一个流结构框架,供编写新流时调用,strSize和dataSize *
* 分别为流结构和数据结构长度(数据结构第一个成员必须是一个整形的引用计数变量)。*
*   该函数只初始化了IStreamVtbl及部分流方法(Stream结构中用***作注释的函数)。  *
******************************************************************************/
PStream CreateStream(INT strSize, INT dataSize);

/******************************************************************************
* 功能:建立文件流(是否只读取决于mode参数)                                    *
* 参数:fileName:文件名称                                                    *
*		mode:打开文件方式                                                    *
*		share:文件共享方式                                                   *
* 返回:成功返回文件流结构指针,失败返回NULL                                  *
******************************************************************************/
PStream CreateFileStream( LPCTSTR fileName, FileOpenMode mode, FileShareMode share);

/******************************************************************************
* 功能:建立内存流                                                            *
* 返回:成功返回内存结构流指针,失败返回NULL                                  *
******************************************************************************/
PStream CreateMemoryStream(VOID);

/******************************************************************************
* 功能:建立资源流(只读的)                                                    *
* 参数:hModule:资源所在模块句柄,NULL为当前应用程序                         *
*		resName or resID:资源名称或者资源ID                                  *
*		type:资源类型                                                        *
* 返回:成功返回资源流结构指针,失败返回NULL                                  *
******************************************************************************/
PStream CreateResourceStream(HMODULE hModule, LPCTSTR resName, LPCTSTR type);
PStream CreateResourceStreamFromID(HMODULE hModule, INT resID, LPCTSTR type);

#include <poppack.h>    /* pop structure packing back to previous state */
#endif

    通用的文件和内存管理函数代码文件:

/**************************************************************************/
*
* Module Name:
*
*   Common.c
*
* 湖北省公安县统计局  毛泽发  2009.10
*
/**************************************************************************/

#include "Common_c.h"

LPVOID AllocGlobal(DWORD size, BOOL isZreo)
{
	return GlobalLock(GlobalAlloc(isZreo? GHND : GMEM_MOVEABLE, size));
}

LPVOID ReAllocGlobal(LPVOID ptr, DWORD newSize, BOOL isZreo)
{
	HGLOBAL newHandle;
	HGLOBAL handle = GlobalHandle(ptr);
	if (handle)
    {
		GlobalUnlock(handle);
		newHandle = GlobalReAlloc(handle, newSize, isZreo? GHND : GMEM_MOVEABLE);
		if (newHandle == NULL)
			newHandle = handle;
		return GlobalLock(newHandle);
	}
	return NULL;
}

BOOL FreeGlobal(LPVOID ptr)
{
    HGLOBAL handle = GlobalHandle(ptr);
    if (handle)
    {
        GlobalUnlock(handle);
		return GlobalFree(handle) == NULL? TRUE : FALSE;
    }
	return FALSE;
}

HANDLE FileOpen(LPCTSTR fileName, FileOpenMode mode, FileShareMode share)
{
    DWORD access, shareMode;

    switch (mode)
    {
        case FileOpenRead:
            access = GENERIC_READ;
            break;
        case FileOpenWrite:
            access = GENERIC_WRITE;
            break;
        default:
            access = GENERIC_READ | GENERIC_WRITE;
    }
    switch (share)
    {
        case FileShareRead:
            shareMode = FILE_SHARE_READ;
            break;
        case FileShareWrite:
            shareMode = FILE_SHARE_WRITE;
            break;
        case FileShareReadWrite:
            shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
            break;
        default:
            shareMode = 0;
    }
	return CreateFile(fileName, access, shareMode, NULL,
        (mode == FileOpenCreate)? CREATE_ALWAYS : OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
}

HANDLE FileCreate(LPCTSTR fileName)
{
    return FileOpen(fileName, FileOpenCreate, FileShareNone);
}

BOOL FileClose(HANDLE handle)
{
    return CloseHandle(handle);
}

LONG FileRead(HANDLE handle, VOID* buffer, LONG count)
{
	ULONG bytesRead;

	return ReadFile(handle, buffer, count, &bytesRead, NULL)?
		bytesRead : -1;
}

LONG FileWrite(HANDLE handle, const VOID* buffer, LONG count)
{
    ULONG bytesWritten;

    return WriteFile(handle, buffer, count, &bytesWritten, NULL)?
        bytesWritten : -1;
}

INT64 FileSeek(HANDLE handle, INT64 offset, DWORD origin)
{
	LARGE_INTEGER off;
	off.QuadPart = offset;
	off.LowPart = SetFilePointer(handle, off.LowPart, &off.HighPart, origin);
	return off.QuadPart;
}

BOOL FileSetSize(HANDLE handle, INT64 size)
{
    return FileSeek(handle, size, 0) == size?
        SetEndOfFile(handle) : FALSE;
}

    流函数代码文件(包括IStream、文件流、内存流及资源流函数代码):

/**************************************************************************/
*
* Module Name:
*
*   Streams.c
*
* 湖北省公安县统计局  毛泽发  2009.12
*
/**************************************************************************/

#include "Common_c.h"
#include <stdio.h>

#define	MEMORYDELTA		0x2000

typedef struct
{
	INT refCount;	/* IStream 的引用计数变量 */
}StreamData;

/* IStream method */

static HRESULT STDMETHODCALLTYPE QueryInterface(IStream *This,
    REFIID riid, VOID **ppvObject)
{
	if (lstrcmp((LPTSTR)riid, (LPTSTR)&IID_IStream) == 0 ||
		lstrcmp((LPTSTR)riid, (LPTSTR)&IID_IUnknown) == 0)
	{
		*ppvObject = This;
		This->lpVtbl->AddRef(This);
		return S_OK;
    }
	*ppvObject = NULL;
	return E_NOINTERFACE;
}

static ULONG STDMETHODCALLTYPE AddRef(IStream *This)
{
	((StreamData*)((PStream)This)->data)->refCount ++;
	return ((StreamData*)((PStream)This)->data)->refCount;
}

static ULONG STDMETHODCALLTYPE Release(IStream *This)
{
	if (((StreamData*)((PStream)This)->data)->refCount > 0)
		((StreamData*)((PStream)This)->data)->refCount --;
	if (((StreamData*)((PStream)This)->data)->refCount == 0)
    {
		((PStream)This)->Destroy((PStream)This);
		return 0;
    }
	return ((StreamData*)((PStream)This)->data)->refCount;
}

static HRESULT STDMETHODCALLTYPE Read(IStream *This, VOID *pv, ULONG cb, ULONG *pcbRead)
{
    LONG numRead;

    if (pv == NULL)
        return STG_E_INVALIDPOINTER;
	numRead = ((PStream)This)->Read((PStream)This, pv, cb);
	if (pcbRead) *pcbRead = numRead;
    return numRead == -1? E_FAIL : S_OK;
}

static HRESULT STDMETHODCALLTYPE Write(IStream *This,
	const VOID *pv, ULONG cb, ULONG *pcbWritten)
{
    LONG numWritten;

    if (pv == NULL)
        return STG_E_INVALIDPOINTER;
    numWritten = ((PStream)This)->Write((PStream)This, pv, cb);
    if (pcbWritten) *pcbWritten = numWritten;
    return numWritten == -1? E_FAIL : S_OK;
}

static HRESULT STDMETHODCALLTYPE Seek(IStream *This,
	LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
    INT64 newPos;

    if (dwOrigin < STREAM_SEEK_SET || dwOrigin > STREAM_SEEK_END)
        return STG_E_INVALIDFUNCTION;
    newPos = ((PStream)This)->Seek((PStream)This, dlibMove.QuadPart, dwOrigin);
    if (plibNewPosition)
        plibNewPosition->QuadPart = newPos;
    return newPos == -1? E_FAIL : S_OK;
}

static HRESULT STDMETHODCALLTYPE SetSize(IStream *This, ULARGE_INTEGER libNewSize)
{
    return ((PStream)This)->SetSize((PStream)This, libNewSize.QuadPart)? S_OK : E_FAIL;
}

#define MAXBUFSIZE  0x00100000

static HRESULT STDMETHODCALLTYPE CopyTo(IStream *This, IStream *pstm,
	ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
{
    VOID* buffer;
	LONG bufSize, N, W, R;
	INT64 bytesRead, bytesWritten;
    HRESULT result;

	if (cb.QuadPart == 0) return S_OK;
    if (pstm == NULL) return E_UNEXPECTED;
    result = S_OK;
    bytesRead = bytesWritten = 0;
	bufSize = cb.QuadPart > MAXBUFSIZE? MAXBUFSIZE : cb.LowPart;
	buffer = AllocMem(bufSize);
	while (cb.QuadPart > 0 && result == S_OK)
	{
		N = cb.QuadPart > bufSize? bufSize : cb.LowPart;
		R = ((PStream)This)->Read((PStream)This, buffer, N);
		if (R <= 0)
        {
            if (R < 0) result = E_FAIL;
            break;
        }
		bytesRead += R;
		W = 0;
		result = pstm->lpVtbl->Write(pstm, buffer, R, (ULONG*)&W);
		bytesWritten += W;
		if (W != R) result = E_FAIL;
		cb.QuadPart -= R;
	}
	FreeMem(buffer);
    if (pcbWritten) pcbWritten->QuadPart = bytesWritten;
    if (pcbRead) pcbRead->QuadPart = bytesRead;
    return result;
}

static HRESULT STDMETHODCALLTYPE Commit(IStream *This, DWORD grfCommitFlags)
{
    return S_OK;
}

static HRESULT STDMETHODCALLTYPE Revert(IStream *This)
{
    return STG_E_REVERTED;
}

static HRESULT STDMETHODCALLTYPE LockRegion(IStream *This,
    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
    return STG_E_INVALIDFUNCTION;
}

static HRESULT STDMETHODCALLTYPE UnlockRegion(IStream *This,
    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
    return STG_E_INVALIDFUNCTION;
}

static HRESULT STDMETHODCALLTYPE Stat(IStream *This,
    STATSTG *pstatstg, DWORD grfStatFlag)
{
    if (pstatstg)
    {
        pstatstg->type = STGTY_STREAM;
        pstatstg->cbSize.QuadPart = ((PStream)This)->GetSize((PStream)This);
        pstatstg->mtime.dwLowDateTime = 0;
        pstatstg->mtime.dwHighDateTime = 0;
        pstatstg->ctime.dwLowDateTime = 0;
        pstatstg->ctime.dwHighDateTime = 0;
        pstatstg->atime.dwLowDateTime = 0;
        pstatstg->atime.dwHighDateTime = 0;
		pstatstg->grfLocksSupported = LOCK_WRITE;
    }
    return S_OK;
}

static HRESULT STDMETHODCALLTYPE Clone(IStream *This, IStream **ppstm)
{
    return E_NOTIMPL;
}

/* Stream method */

static BOOL Stream_Clear(PStream stream)
{
	return stream->SetSize(stream, 0);
}

static INT64 Stream_GetPosition(PStream stream)
{
	return stream->Seek(stream, 0, STREAM_SEEK_CUR);
}

static INT64 Stream_SetPosition(PStream stream, INT64 newPosition)
{
	return stream->Seek(stream, newPosition, STREAM_SEEK_SET);
}

static INT64 Stream_GetSize(PStream stream)
{
	INT64 pos = stream->Seek(stream, 0, STREAM_SEEK_CUR);
	INT64 result = stream->Seek(stream, 0, STREAM_SEEK_END);
	stream->Seek(stream, pos, STREAM_SEEK_SET);
	return result;
}

static BOOL Stream_CopyFrom(PStream stream, PStream source, INT64 count)
{
	ULARGE_INTEGER cb;

	if (count <= 0)
		count = source->GetSize(source) - source->GetPosition(source);
	cb.QuadPart = count;
	return CopyTo((IStream*)source, (IStream*)stream, cb, NULL, NULL) == S_OK;
}

static BOOL Stream_LoadFromStream(PStream stream, PStream source)
{
	if (stream->Clear(stream))
	{
		source->SetPosition(source, 0);
		return stream->CopyFrom(stream, source, 0);
	}
	return FALSE;
}

static BOOL Stream_LoadFromFile(PStream stream, LPCTSTR fileName)
{
	BOOL result = FALSE;
	PStream source = CreateFileStream(fileName, FileOpenRead, FileShareWrite);
	if (source)
	{
		result = stream->LoadFromStream(stream, source);
		source->Destroy(source);
	}
	return result;
}

static BOOL Stream_SaveToStream(PStream stream, PStream dest)
{
	stream->SetPosition(stream, 0);
	return stream->CopyFrom(dest, stream, 0);
}

static BOOL Stream_SaveToFile(PStream stream, LPCTSTR fileName)
{
	BOOL result = FALSE;
	PStream dest = CreateFileStream(fileName, FileOpenCreate, FileShareNone);
	if (dest)
	{
		result = stream->SaveToStream(stream, dest);
		dest->Destroy(dest);
	}
	return result;
}

static VOID Stream_Destroy(PStream stream)
{
	if (stream)
	{
		if (stream->ShutDown)
			stream->ShutDown(stream);
		free(stream->data);
		free(stream->lpVtbl);
		free(stream);
	}
}

PStream CreateStream(INT strSize, INT dataSize)
{
	PStream stream = (PStream)malloc(strSize);
	if (stream == NULL) return NULL;
	stream->lpVtbl = (IStreamVtbl*)malloc(sizeof(IStreamVtbl));
	if (stream->lpVtbl == NULL)
	{
		free(stream);
		return NULL;
	}
	stream->data = malloc(dataSize);
	if (stream->data == NULL)
	{
		free(stream->lpVtbl);
		free(stream);
		return NULL;
	}
	memset(stream->data, 0, dataSize);

	// 初始化IStream函数
	stream->lpVtbl->QueryInterface = QueryInterface;
	stream->lpVtbl->AddRef = AddRef;
	stream->lpVtbl->Release = Release;
	stream->lpVtbl->Read = Read;
	stream->lpVtbl->Write = Write;
	stream->lpVtbl->Seek = Seek;
	stream->lpVtbl->SetSize = SetSize;
	stream->lpVtbl->CopyTo = CopyTo;
	stream->lpVtbl->Commit = Commit;
    stream->lpVtbl->Revert = Revert;
    stream->lpVtbl->LockRegion = LockRegion;
	stream->lpVtbl->UnlockRegion = UnlockRegion;
	stream->lpVtbl->Stat = Stat;
	stream->lpVtbl->Clone = Clone;
	// 初始化部分Stream函数
	stream->Destroy = Stream_Destroy;
	stream->ShutDown = NULL;
	stream->Clear = Stream_Clear;
	stream->CopyFrom = Stream_CopyFrom;
	stream->GetPosition = Stream_GetPosition;
	stream->SetPosition = Stream_SetPosition;
	stream->GetSize = Stream_GetSize;
	stream->LoadFromStream = Stream_LoadFromStream;
	stream->SaveToStream = Stream_SaveToStream;
	stream->LoadFromFile = Stream_LoadFromFile;
	stream->SaveToFile = Stream_SaveToFile;

	return stream;
}

/* FileStream method */

typedef struct
{
	INT 	refCount;	/* IStream 的引用计数变量 */
	HANDLE	handle;	/* 文件句柄 */
}FileStreamData;

#define	FILE_HANDLE		((FileStreamData*)stream->data)->handle

static LONG FileStream_Read(PStream stream, VOID* buffer, LONG count)
{
	return FileRead(FILE_HANDLE, buffer, count);
}

static LONG FileStream_Write(PStream stream, const VOID* buffer, LONG count)
{
	return FileWrite(FILE_HANDLE, buffer, count);
}

static INT64 FileStream_Seek(PStream stream, INT64 offset, DWORD origin)
{
	return FileSeek(FILE_HANDLE, offset, origin);
}
/*
static INT64 FileStream_GetSize(PStream stream)
{
	ULARGE_INTEGER size;
	size.LowPart = GetFileSize(FILE_HANDLE, &size.HighPart);
	return size.QuadPart;
}
*/
static BOOL FileStream_SetSize(PStream stream, INT64 newSize)
{
	return FileSetSize(FILE_HANDLE, newSize);
}

static VOID FileStream_ShutDown(PStream stream)
{
	FileClose(FILE_HANDLE);
}

#define INVALIDHANDLE   (HANDLE)(-1)

PStream CreateFileStream(LPCTSTR fileName, FileOpenMode mode, FileShareMode share)
{
	PStream stream;
	HANDLE handle = FileOpen(fileName, mode, share);
	if (handle == NULL || handle == INVALIDHANDLE) return NULL;
	stream = CreateStream(sizeof(Stream), sizeof(FileStreamData));
	if (stream == NULL)
	{
		FileClose(handle);
		return NULL;
	}

	FILE_HANDLE = handle;

	stream->ShutDown = FileStream_ShutDown;
	stream->Read = FileStream_Read;
	stream->Write = FileStream_Write;
	stream->Seek = FileStream_Seek;
//	stream->GetSize = FileStream_GetSize;
	stream->SetSize = FileStream_SetSize;

	return stream;
}

/* MemoryStream method */

typedef struct
{
	INT		refCount;	/* IStream 的引用计数变量 */
	VOID* 	buffer;
	LONG 	position;
	LONG 	size;
	union
	{
		LONG 	capacity;
		HGLOBAL	hGlobal;
	};
}MemStreamData;

#define	MEMSTREAM	((MemStreamData*)stream->data)

static VOID MemStream_SetCapacity(PStream stream, LONG newCapacity)
{
	if (newCapacity > 0 && newCapacity != MEMSTREAM->size)
		newCapacity = (newCapacity + (MEMORYDELTA - 1)) & ~(MEMORYDELTA - 1);
	if (newCapacity != MEMSTREAM->capacity)
	{
		if (MEMSTREAM->buffer)
			MEMSTREAM->buffer = ReAllocMem(MEMSTREAM->buffer, newCapacity);
		else
			MEMSTREAM->buffer = AllocMem(newCapacity);
		MEMSTREAM->capacity = GetMemSize(MEMSTREAM->buffer);
	}
}
/*
static INT64 MemStream_GetSize(PStream stream)
{
	return (INT64)MEMSTREAM->size;
}
*/
static BOOL MemStream_SetSize(PStream stream, INT64 newSize)
{
	if ((LONG)newSize >= 0)
	{
		MemStream_SetCapacity(stream, (LONG)newSize);
		if ((LONG)newSize > MEMSTREAM->capacity)
			return FALSE;
		MEMSTREAM->size = (LONG)newSize;
		if (MEMSTREAM->position > MEMSTREAM->size)
			MEMSTREAM->position = MEMSTREAM->size;
		return TRUE;
	}
	return FALSE;
}

static LONG MemStream_Read(PStream stream, VOID* buffer, LONG count)
{
	LONG rCount;

	if (count >= 0)
	{
		rCount = MEMSTREAM->size - MEMSTREAM->position;
		if (rCount > 0)
		{
			if (rCount > count) rCount = count;
			memcpy(buffer, (char*)MEMSTREAM->buffer + MEMSTREAM->position, rCount);
			MEMSTREAM->position += rCount;
		}
        return rCount;
    }
	return -1;
}

static LONG MemStream_Write(PStream stream, const VOID* buffer, LONG count)
{
	LONG pos;

	if (count >= 0)
	{
		pos = MEMSTREAM->position + count;
		if (pos > 0)
		{
			if (pos > MEMSTREAM->size && !MemStream_SetSize(stream, pos))
				return -1;
			memcpy((char*)MEMSTREAM->buffer + MEMSTREAM->position, buffer, count);
			MEMSTREAM->position = pos;
		}
        return count;
	}
	return -1;
}

static INT64 MemStream_Seek(PStream stream, INT64 offset, DWORD origin)
{
	switch (origin)
	{
		case STREAM_SEEK_CUR:
			offset += MEMSTREAM->position;
			break;
		case STREAM_SEEK_END:
			offset += MEMSTREAM->size;
			break;
	}
	MEMSTREAM->position = (LONG)offset;
    if (MEMSTREAM->position < 0)
    {
        MEMSTREAM->position = 0;
        return -1;
    }
	return (INT64)MEMSTREAM->position;
}

static VOID MemStream_ShutDown(PStream stream)
{
	stream->Clear(stream);
}

static BOOL MemStream_SaveToStream(PStream stream, PStream dest)
{
	return dest->Write(dest, MEMSTREAM->buffer, MEMSTREAM->size) == MEMSTREAM->size;
}

static BOOL MemStream_LoadFromStream(PStream stream, PStream source)
{
	source->SetPosition(source, 0);
	if (!MemStream_SetSize(stream, source->GetSize(source)))
		return FALSE;
	if (MEMSTREAM->size != 0)
		return source->Read(source, MEMSTREAM->buffer, MEMSTREAM->size) == MEMSTREAM->size;
	return FALSE;
}

static PStream _CreateMemoryStream(VOID)
{
	PStream stream = CreateStream(sizeof(Stream), sizeof(MemStreamData));
	if (stream == NULL) return NULL;
	stream->Read = MemStream_Read;
	stream->Seek = MemStream_Seek;
//	stream->GetSize = MemStream_GetSize;
	stream->SaveToStream = MemStream_SaveToStream;

	return stream;
}

PStream CreateMemoryStream(VOID)
{
	PStream stream = _CreateMemoryStream();
	if (stream == NULL) return NULL;

	stream->ShutDown = MemStream_ShutDown;
	stream->Write = MemStream_Write;
	stream->SetSize = MemStream_SetSize;
	stream->LoadFromStream = MemStream_LoadFromStream;

	return stream;
}

/* ResourceStream method */

static LONG ResStream_Write(PStream stream, const VOID* buffer, LONG count)
{
	return -1;
}

static BOOL ResStream_SetSize(PStream stream, INT64 newSize)
{
	return FALSE;
}

static BOOL ResStream_LoadFromStream(PStream stream, PStream source)
{
	return FALSE;
}

static BOOL ResStream_LoadFromFile(PStream stream, LPCTSTR fileName)
{
	return FALSE;
}

static VOID ResStream_ShutDown(PStream stream)
{
	UnlockResource(MEMSTREAM->hGlobal);
	FreeResource(MEMSTREAM->hGlobal);
}

static PStream ResStream_Create(HMODULE hModule, LPCTSTR resName,  LPCTSTR type)
{
	PStream stream;
	HGLOBAL	hGlobal;
	HRSRC resInfo = FindResource(hModule, resName, type);
	if (resInfo == NULL)
		return NULL;

	stream = _CreateMemoryStream();
	if (stream == NULL) return NULL;

	MEMSTREAM->hGlobal = LoadResource(hModule, resInfo);
	MEMSTREAM->buffer = LockResource(MEMSTREAM->hGlobal);
	MEMSTREAM->size = SizeofResource(hModule, resInfo);

	stream->ShutDown = ResStream_ShutDown;
	stream->Write = ResStream_Write;
	stream->SetSize = ResStream_SetSize;
	stream->LoadFromStream = ResStream_LoadFromStream;
	stream->LoadFromFile = ResStream_LoadFromFile;

	return stream;
}

PStream CreateResourceStream(HMODULE hModule, LPCTSTR resName, LPCTSTR type)
{
	return ResStream_Create(hModule, resName, type);
}

PStream CreateResourceStreamFromID(HMODULE hModule, INT resID, LPCTSTR type)
{
	return ResStream_Create(hModule, (LPCTSTR)resID, type);
}

    由于前面的头文件中对各个函数的功能、参数、返回值及注意事项都作了较详尽的注释,所以本文只作代码展示得了。

    需要说明的是本文代码只适用于Windows应用程序,而且代码测试也只是在BCB2010中进行的。

    下面给出一个简单的Windows应用程序测试代码:

//---------------------------------------------------------------------------

#include "common_c.h"
#include "gdiplus_c.h"
#include <stdio.h>
#pragma hdrstop

#include <tchar.h>
//---------------------------------------------------------------------------

#pragma argsused

#define WNDCLASSNAME    TEXT("Maozefa_Form")

PGpImage image;

void WndPaint(HWND hWnd)
{
	HDC hDC;
	PAINTSTRUCT ps;
	PGpGraphics g;

	hDC = BeginPaint(hWnd, &ps);
	g = GraphicsCreate(hDC);             // GDI+ 画布
	GraphicsDrawImageXY(g, image, 0, 0);
	GraphicsDelete(g);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
        case WM_PAINT:
			WndPaint(hWnd);
			return 0;
		case WM_DESTROY:
			PostQuitMessage(0);
            break;
        default:
            break;
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}

HWND CreateMainWindow(LPTSTR caption, HINSTANCE hInstance, int width, int height)
{
    WNDCLASS WinClass;

    memset(&WinClass, 0, sizeof(WNDCLASS));
    WinClass.style = CS_VREDRAW | CS_HREDRAW;
    WinClass.hInstance = hInstance;
    WinClass.lpfnWndProc = WndProc;
    WinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WinClass.hbrBackground =  (HBRUSH)COLOR_WINDOW;
	WinClass.lpszClassName = WNDCLASSNAME;

    if (!RegisterClass(&WinClass))
		return NULL;

	return CreateWindowEx(WS_EX_CONTROLPARENT,
						  WNDCLASSNAME,
						  caption,
						  WS_CLIPSIBLINGS | WS_VISIBLE | WS_CLIPCHILDREN |
						  WS_BORDER | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU,
						  CW_USEDEFAULT, CW_USEDEFAULT, width, height,
						  NULL, NULL, hInstance, NULL);

}


WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	Stream *stream;
	IStream *iStream;
	MSG msg;
	HWND Handle = CreateMainWindow(TEXT("C语言IStream演示"), hInstance, 406, 312);
    if (Handle == NULL)
		return -1;

	Gdiplus_Startup();      // 启动Gdiplus
	// 使用文件流
//	stream = CreateFileStream(TEXT("56-3.jpg"), FileOpenRead, FileShareNone);

	// 使用内存流
	stream = CreateMemoryStream();
	stream->LoadFromFile(stream, TEXT("56-3.jpg"));

	// 使用资源流
	// 使用资源名称建立流
//	stream = CreateResourceStream(NULL, TEXT("jpg56_3"), RT_RCDATA);
	// 使用资源ID建立流,必须把jpgTest.rc的#define JPG56_3         300的注释去掉
//	stream = CreateResourceStreamFromID(NULL, 300, RT_RCDATA);

	// 强制转换为IStream操作,AddRef和Release必须配对使用
//	stream->lpVtbl->AddRef((IStream*)stream);
//	image = ImageFromStream((IStream*)stream, FALSE);	// 建立图像对象
//	stream->lpVtbl->Release((IStream*)stream);

	// 使用QueryInterface函数获取IStream指针,相当于调用了一次AddRef
	stream->lpVtbl->QueryInterface((IStream*)stream, &IID_IStream, (void**)&iStream);
	image = ImageFromStream(iStream, FALSE); 			// 建立图像对象
	iStream->lpVtbl->Release(iStream);

	// 转换为IStream操作后,不要调用stream->Destroy,否则会出错
//    stream->Destroy(stream);

	ShowWindow(Handle, nCmdShow);
	UpdateWindow(Handle);
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	ImageDelete(image);		// 删除图像对象
	Gdiplus_Shutdown();     // 释放Gdiplus

	return (int)msg.wParam;
}
//-----------------

----------------------------------------------------------

    代码中分别使用了3种流进行IStream测试,其中也用到了C语言版的GDI+函数(见《在C语言Windows应用程序中使用GDI+》),必须在工程中加入Gdiplus.lib(BCB2010自带)。

    使用资源流测试时,还需要写一个资源文件加入到工程中,下面是一个简单的RC文件:

//#define JPG56_3 300 JPG56_3 RCDATA "56-3.jpg"

    代码使用过程中,如有错误,或者你有好的建议,请发送邮件到我的信箱:maozefa@hotmail.com

    最后祝各位春节后工作愉快顺心!!!

后记(2010.3.10 11:40):对本文代码作了一些修改,主要是将IStream所用的引用计数变量隐藏起来了,以防止误操作。