GDI+的Image及派生类中涉及到IStream流,在Delphi和C++Builder中广泛使用的TStream不能直接作为参数进行传递,VCL提供了一个TStreamAdapter类,用于把VCL流TStream转换为IStream。TStreamAdapter的构造过程原型如下:
constructor Create(Stream: TStream; Ownership: TStreamOwnership = soReference);
其中的TStreamOwnership枚举类型有2个值:soReference和,如果是soOwned,TStream对象由TStreamAdapter释放,否则由用户自己处理。请看下面的用流建立Image的Delphi代码:
var Stream: TMemoryStream; Adapter: TStreamAdapter; Image: TGpImage; begin Stream := TMemoryStream.Create; Stream.LoadFromFile('Test.jpg'); Adapter := TStreamAdapter.Create(Stream, soOwned); Image := TGpImage.Create(Adapter); try ..... finally Image.Free; end; end; 代码中,首先建立一个内存流,并从磁盘中装入一个图像文件,然后用TStreamAdapter将这个流封装起来,转换为IStream,供建立TGpImage使用。注意,我在建立TStreamAdapter对象时使用了soOwned,这样,由Adapter负责释放Stream,否则,必须在Image.Free后面Stream.Free。但是TStreamAdapter对象Adapter为什么没有释放代码呢?因为TStreamAdapter是个接口实现类,作为IStream传递给TGpImage.Create后,由系统自动跟踪释放,如果我们将它Free,会引起错误,如果非要显式释放它,必须用var I: IStream; I := Adapter; I := nil;的方法释放,而且必须在Image.Free之前,因为在Image.Free的同时,Adapter也随着IStream一起被释放掉了。
上面的代码在Delphi7 调试状态下会出现错误,在网上找了个C的代码,现在改为Pascal的,在个人机子上调试稳定:
function LoadGPImageFormRes(aHMoudle: DWORD; ResName, ResType: string): TGPImage; var HRes: HRSRC; sResName: string; sResType: string; Len: DWORD; lpRsrc: PByte; m_hMem: HGLOBAL; pMem: PByte; pstm: IStream; begin Result := nil; sResName := ResName; sResType := ResType; HRes := FindResource(HInstance, PChar(sResName), PChar(sResType)); if HRes <> 0 then begin Len := SizeofResource(HInstance, HRes); lpRsrc := PByte(LoadResource(HInstance, HRes)); try if lpRsrc <> nil then begin
m_hMem := GlobalAlloc(GMEM_FIXED, Len); pMem := Pbyte(GlobalLock(m_hMem)); CopyMemory(pMem, lpRsrc, Len); CreateStreamOnHGlobal(m_hMem, False, pstm); Result := TGPImage.Create(pstm); GlobalUnlock(m_hMem); pstm := nil; FreeResource(Dword(lpRsrc)); end; except if Assigned(Result) then begin FreeAndNil(Result); end; end;
end;
end;
|
请发表评论