在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所用的引用计数变量隐藏起来了,以防止误操作。