使用 IStream
有许多技巧文档讲述如何将任意一种数据转化成 variant 的数据类型以将它们传递给一个COM接口。
不管怎么样,许多VCL构件都有以流的方式工作的方法和属性。关键就是 TOLEStream 和 TStreamAdapter 的使用。
IStream 被定义在 ActiveX 单元,TStreamAdapter 被定义在 Classes 单元,TOLEStream 则被定义在 Axctrls 单元中。
下面的包裹类将为你提供你所需要的全部东西。(注意:不要将这些函数转化成属性,这样做可能会让你企图调用 IStream 方法,尽管它不是中读的,但是至少我这样做就遇到访问冲突的错误)
Uses Classes, ActiveX, Axctrls;
Type TInterfaceStream = Class ( TMemoryStream )
Public
Procedure LoadFromIStream(Source : IStream);
Function GetIStream : IStream;
end;
Procedure TInterfaceStream.LoadFromIStream(Source : IStream);
var
Adapt : TOLEStream;
Buff : Byte;
I : Integer;
begin
ADapt := TOLEStream.Create(Source);
Adapt.Position := 0;
Self.Clear;
Self.Position := 0;
For I := 0 to Adapt.Size do
begin
Adapt.Read(Buff, 1);
Self.Write(Buff, 1);
end;
Self.Position := 0;
end;
Function TInterfaceStream.GetIStream : IStream;
var
Adapt : TStreamAdapter;
tPos : Int64;
begin
Adapt := TStreamAdapter.Create(Self);
Adapt.Seek(0, 0, tPos);
Result := Adapt as IStream;
end;
现在我们可以很简单地使用 IStream. 假如,你有一个 COM 对象方法需要返回一个 IStream,
那你只需要简单地声明一个private的 TInterfaceStream 成员变量。( 这里我们估且将称它为 FStream ),
在 initialize 时初始化它, 然后照下面的做法实现自己的方法:
Function TSampleCOMObj.Mehtod1 : IStream
begin
// Here's where you load whatever actually goes into the stream
result := FStream.GetIStream;
end;
将 TInterfaceStream 作为局部变量可能有些棘手。因为可能存在应用程序使用它之前它的内存就已经被释放掉的隐患。因此将它声明成一个 private 成员会更安全.
应用程序中只需要做下面的事
Procedure Form1.Button1OnClick(Sender : TObject);
var
Server : ISampleCOMObj;
temp : IStream;
ResultStream : TInterfaceStream;
begin
Server := CreateCOMObject(Class_TSampleCOMObj) as ISampleComObj;
temp := Server.method1;
ResultStream := TinterfaceStream.Create;
ResultStream.Clear;
resultStream.Position := 0;
resultstream.LoadFromIStream(Temp);
// do whatever it is you want with the data in the stream;
end;