Delphi7 从资源文件中载入GDI+对象

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;