在C语言应用程序中使用兼容IStream的流

本文介绍了一个C语言实现的流操作库,包括文件流、内存流和资源流,并提供了与IStream兼容的接口。同时展示了如何在Windows应用程序中使用这些流进行文件读写和GDI+图像处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值