在应用服务器TLB文件中,设置一个接口函数其中一个参数是TStringStream.请问在TLB众多的参数类型中,那个类型是对应TStringStream类型的呢。

解决方案 »

  1.   

    http://blog.csdn.net/aiirii/archive/2004/11/29/197386.aspx在Com, Dcom, Com+中經常要用到variant, 而在delphi 中的文件操作之類中, 更多的用到Stream, 有時, 需要適當的互換!Variant --> Streamvar ov: OleVariant;
      ms: TStream; p: Pointer;
    begin
      ov := dmMain.ComConnection.AppServer.TimeZone;
      ms := TMemoryStream.Create;
      ms.Position := 0;
      p := VarArrayLock(ov);
      ms.Write(p^, VarArrayHighBound(ov, 1)); //這句可否改進?
      VarArrayUnlock(ov);  ms.Position := 0;
      ...
      ms.Free;
    end;Stream --> Variantfunction TTCanteenSvr.Get_TimeZone: OleVariant;
    var
      AStream: TStream;
      MyBuffer: Pointer;
    begin
      try
        AStream := TFileStream.Create(, fmOpenRead);
        Result := VarArrayCreate([0, AStream.Size - 1], VarByte);
        MyBuffer := VarArrayLock(Result);
        AStream.ReadBuffer(MyBuffer^, AStream.Size);
        VarArrayUnlock(Result);
      finally
        AStream.Free;
      end;
      

  2.   

    我是先在客户端把STREAM进行压缩。压缩方法是这样子的:
    ys:=TCompressionStream.Create(clMax,outstream);
    ys.CopyFrom(instream,0);
    ys.Free;
    jy:=TDeCompressionStream.Create(outstream);
    jy.Position:=0;
    然后把压缩后的流转换成VARIANT传递到应用服务器端。应用服务器端接收到以后先把VARIANT转换成STREAM,然后把STREAM解压缩。语句如下:
    //对压缩流outstream进行解压
      jy:=TDeCompressionStream.Create(ysstream);    //ysstream是解压后的流
      jy.Position:=0;
      //读出流内容
      jyRead := jy.Read(buf, ysstream.Size);   //这句就报错了。而且就报“ERROR”,没报别的。
    但是我试过,如果其中少了对流压缩和解压的过程,那么过程就很顺利。
      

  3.   

    更正一下ysstream是等待压缩的流
      

  4.   

    应该说将流数据转换成Variant类型是一个比较好的处理办法。
      

  5.   

    如果有需要我可以提供一段实例代码给你(Delphi版的),当时是为了经VB中通过Com传递多种数据文件而写的。里面提供有压缩和解压缩,同时也包括读写文件。
      

  6.   

    {不好意思没有任何说明
    下面是代码}
    unit FilePacket;{$WARN SYMBOL_PLATFORM OFF}interfaceuses
      ComObj, ActiveX, FilePacket_TLB, StdVcl;type
      TFilePacket = class(TAutoObject, IFilePacket)
      protected
        procedure ReadFilePacket(const FileName: WideString;
          var Packet: OleVariant); safecall;
        procedure ReadFilePacket2(const FileName: WideString;
          var Packet: OleVariant); safecall;
        procedure ReadFile(const FileName: WideString;
          var Packet: OleVariant); safecall;
        function WriteFileStream(var Stream: OleVariant;
          const FileName: WideString): SYSINT; safecall;
        function WriteFile(var Stream: OleVariant;
          const FileName: WideString): SYSINT; safecall;
        procedure ReadFile2(const FileName: WideString;
          var Packet: OleVariant); safecall;
        procedure PackStream(var Stream: OleVariant); safecall;
        procedure UnPackStream(var Stream: OleVariant); safecall;
        { Protected declarations }
      end;implementationuses ComServ,Zlib,Classes,SysUtils,Variants,windows;procedure TFilePacket.ReadFilePacket(const FileName: WideString; var Packet: OleVariant);
    var
      ZStream: TCompressionStream;
      TempStream:TFileStream;
      InStream:TMemoryStream;
      BStream:TMemoryStream;
      Param:OleVariant;
      p:Pointer;
      pj:Pointer;
      bSize:int64;
    begin
      InStream:=TMemoryStream.Create;
      BStream:=TMemoryStream.Create;
      TempStream:=TFileStream.Create(String(FileName),fmOpenRead);
      try
         ZStream:=TCompressionStream.Create(cldefault, InStream);
         try
            ZStream.CopyFrom(TempStream,0);
         finally
            ZStream.Free;
         end;
         Param:=VarArrayCreate([0,InStream.Size-1+sizeof(bSize)],varByte);
         p:=VarArrayLock(Param);
         try
            pj:=Addr(bSize);
            bSize:=TempStream.Size;
            BStream.Write(pj^,sizeof(bSize));
            BStream.Position:=sizeof(bSize);
            InStream.Position:=0;
            BStream.CopyFrom(InStream,InStream.Size);
            bstream.Position:=0;        BStream.Read(p^,BStream.Size);
         finally
            VarArrayUnlock(Param);
         end;
      finally
         InStream.Free;
         BStream.Free;
         TempStream.Free;
      end;
      if not DeleteFile(PChar(AnsiString(FileName))) then
      begin
         Sleep(1000);
         DeleteFile(PChar(AnsiString(FileName)));
      end;
      Packet:=Param;
    end;
    procedure TFilePacket.ReadFilePacket2(const FileName: WideString; var Packet: OleVariant);
    var
      ZStream: TCompressionStream;
      TempStream:TFileStream;
      InStream:TMemoryStream;
      BStream:TMemoryStream;
      Param:OleVariant;
      p:Pointer;
      pj:Pointer;
      bSize:int64;
    begin
      InStream:=TMemoryStream.Create;
      BStream:=TMemoryStream.Create;
      TempStream:=TFileStream.Create(String(FileName),fmOpenRead);
      try
         ZStream:=TCompressionStream.Create(cldefault, InStream);
         try
            ZStream.CopyFrom(TempStream,0);
         finally
            ZStream.Free;
         end;
         Param:=VarArrayCreate([0,InStream.Size-1+sizeof(bSize)],varByte);
         p:=VarArrayLock(Param);
         try
            pj:=Addr(bSize);
            bSize:=TempStream.Size;
            BStream.Write(pj^,sizeof(bSize));
            BStream.Position:=sizeof(bSize);
            InStream.Position:=0;
            BStream.CopyFrom(InStream,InStream.Size);
            bstream.Position:=0;        BStream.Read(p^,BStream.Size);
         finally
            VarArrayUnlock(Param);
         end;
      finally
         InStream.Free;
         BStream.Free;
         TempStream.Free;
      end;
      Packet:=Param;
    end;
    procedure TFilePacket.ReadFile2(const FileName: WideString; var Packet: OleVariant);
    var
      TempStream:TFileStream;
      Param:OleVariant;
      p:Pointer;
    begin
      TempStream:=TFileStream.Create(String(FileName),fmOpenRead);
      try
         Param:=VarArrayCreate([0,TempStream.Size-1],varByte);
         p:=VarArrayLock(Param);
         try
            TempStream.Position:=0;
            TempStream.Read(p^,TempStream.Size);
         finally
            VarArrayUnlock(Param);
         end;
      finally
         TempStream.Free;
      end;
      if not DeleteFile(PChar(AnsiString(FileName))) then
      begin
         Sleep(1000);
         DeleteFile(PChar(AnsiString(FileName)));
      end;
      Packet:=Param;
    end;
    procedure TFilePacket.ReadFile(const FileName: WideString; var Packet: OleVariant);
    var
      TempStream:TFileStream;
      Param:OleVariant;
      p:Pointer;
    begin
      TempStream:=TFileStream.Create(String(FileName),fmOpenRead);
      try
         Param:=VarArrayCreate([0,TempStream.Size-1],varByte);
         p:=VarArrayLock(Param);
         try
            TempStream.Position:=0;
            TempStream.Read(p^,TempStream.Size);
         finally
            VarArrayUnlock(Param);
         end;
      finally
         TempStream.Free;
      end;
      Packet:=Param;
    end;
      

  7.   

    unsigned(僵哥),你贴的程序哪有解压缩部分啊!
      

  8.   

    程序片断自己理解
    客户端:
    var
      Strm: TMemoryStream;
      tempOleVariant: OleVariant;
      Err: WordBool;
      tempcc: Integer;
    begin
       if LvArea.Selected <> nil then
          tempcc := PAreaNodeInf(LvArea.Selected.Data).CC
       else if TvArea.Selected <>  nil then
          tempcc := PAreaNodeInf(TvArea.Selected.Data).CC
       else
       begin
          Screen.Cursor := crDefault;
          Showmessage('请选择地区!');
          Exit;
       end;
       OpenDialog1.Filter :=  'jpg files (*.jpg)|*.jpg|JPEG files (*.JPEG)|*.JPEG';
       OpenDialog1.Execute;
       if OpenDialog1.FileName <> '' then
       begin
          if MessageDlg('确定要更新该图片吗?',mtInformation,[mbYes,mbNo],0) = mrYes then
          begin
             SCreen.Cursor := crHourGlass;
             Strm := TMemoryStream.Create;
             try
                Strm.LoadFromFile(OpenDialog1.FileName);
                StreamToVariant(Strm,tempOleVariant);
                DataModule1.sktcnn.AppServer.UpdateAreaImg(tempcc,tempOleVariant,False,Err);
                if Not Err then
                begin
                   Image1.Picture := Nil;
                   Image1.Picture.LoadFromFile(OpenDialog1.FileName);
                end;
             finally
                Strm.Free
             end;
             SCreen.Cursor := crDefault;
          end;
       end;
    End;
    服务器端:
    procedure TrdmSys.UpdateAreaImg(cArea_cc: Integer;
      var cArea_Img: OleVariant; cIsClear: WordBool; var vErr: WordBool);
    var
      nPicStream: TMemoryStream;
      SqlStr,MSg: WideString;
    begin
       if cIsClear then
       begin
          SqlStr := 'Update Area set Area_Image=Null' +
                    ' Where  Area_CC ='+ Inttostr(cArea_cc);
          CmdRecs(adocmd,SqlStr,vErr,Msg);
          if vErr then
             Form1.AddErrStr(SqlStr,Msg);
          Exit;
       end;
       nPicStream:=TMemoryStream.Create;
       nPicStream.Clear;
       VariantToStream(cArea_Img,nPicStream);
       nPicStream.Position := 0;
       SqlStr := 'Update Area set Area_Image=:pic' +
                    ' Where  Area_CC ='+ Inttostr(cArea_cc);
       with adocmd do
       begin
          CommandText := SqlStr;
          Parameters.ParamByName('pic').LoadFromStream(nPicStream,ftVarBytes);
          try
             Execute;
             vErr := False;
          except
          on E :exception do
          begin
             vErr := True;
             Form1.AddErrStr(SqlStr,E.Message);
          end;
          end;
       end;
    end;
    另外付函数procedure StreamToVariant(Stream: TMemoryStream; var v: OleVariant);
    var
       p: pointer;
    begin
       v := VarArrayCreate([0, Stream.Size - 1], varByte);
       p := VarArrayLock(v);
       Stream.Position := 0;
       Stream.Read(p^, Stream.Size);
       VarArrayUnlock(v);
    end;procedure VariantToStream(const v: olevariant; Stream: TMemoryStream);
    var
       p: pointer;
    begin
       Stream.Position := 0;
       Stream.Size := VarArrayHighBound (v, 1) - VarArrayLowBound (v, 1) + 1;
       p := VarArrayLock (v);
       Stream.Write (p^, Stream.Size);
       VarArrayUnlock (v);
       Stream.Position := 0;
    end;
      

  9.   

    还是改传IStream吧.
    你在三层里面,远程调用参数应该是oleauto约定的参数类型,这样才能方便传递.
    Variant不是楼主想象那样自动而聪明的东西....在DELPHI里面,可以很方便的使用TStreamAdapter
      

  10.   

    {唉,当时因为连续回复不能超过三次,所以那么长的代码只贴出了一半,现在将其补全}
    function TFilePacket.WriteFileStream(var Stream: OleVariant;
      const FileName: WideString): SYSINT;
    var
      TempStream:TMemoryStream;
      OutStream:TFileStream;
      ZStream: TDecompressionStream;
      BStream:TMemoryStream;
      p:Pointer;
      bSize:int64;
      pj:Pointer;
    begin
      Result:=-1;
      TempStream:=TMemoryStream.Create;
      BStream:=TMemoryStream.Create;
      p:=VarArrayLock(Stream);
      try
         TempStream.Write(p^,VarArrayHighBound(Stream,1)+1);
         OutStream:=TFileStream.Create(String(FileName),fmCreate);
         pj:=Addr(bSize);
         TempStream.Position:=0;
         TempStream.Read(pj^,sizeof(bSize));
         TempStream.Position:=sizeof(bSize);
         if TempStream.Size >0 then BStream.CopyFrom(TempStream,TempStream.Size-sizeof(bSize));
         BStream.Position:=0;
         ZStream:=TDecompressionStream.Create(BStream);
         zstream.Position:=0;
         try
            if bSize>0 then OutStream.CopyFrom(ZStream,bSize);
         finally
            ZStream.Free;
            OutStream.Free;
         end;
      finally
         VarArrayUnlock(Stream);
         BStream.Free;
         TempStream.Free;
      end;
      Result:=0;
    end;
    function TFilePacket.WriteFile(var Stream: OleVariant;
      const FileName: WideString): SYSINT;
    var
      OutStream:TFileStream;
      p:Pointer;
    begin
      Result:=-1;
      p:=VarArrayLock(Stream);
      OutStream:=TFileStream.Create(String(FileName),fmCreate);
      try
         OutStream.Write(p^,VarArrayHighBound(Stream,1)+1);
      finally
         VarArrayUnlock(Stream);
         OutStream.Free;
      end;
      Result:=0;
    end;
    {
    我在处理这个问题的时候是先,将这个大小写入压缩流前面,然后在解压缩前,先读取该数值,然后不用yestream.Size,而用那个读取出来的数据。先是压缩流:}
    procedure TFilePacket.PackStream(var Stream: OleVariant);
    var
      ZStream: TCompressionStream;
      InStream:TMemoryStream;
      TempStream:TMemoryStream;
      BStream:TMemoryStream;
      Param:OleVariant;
      p:Pointer;
      pi:Pointer;
      pj:Pointer;
      bSize:int64;
    begin
      InStream:=TMemoryStream.Create;
      BStream:=TMemoryStream.Create;
      TempStream:=TMemoryStream.Create;
      pi:=VarArrayLock(Stream);
      try
         TempStream.Write(pi^,VarArrayHighBound(Stream,1)+1);//这里是实际的数据流
         ZStream:=TCompressionStream.Create(cldefault, InStream);
         try
            ZStream.CopyFrom(TempStream,0);//将实际数据流压缩
         finally
            ZStream.Free;
         end;
         Param:=VarArrayCreate([0,InStream.Size-1+sizeof(bSize)],varByte);
         p:=VarArrayLock(Param);
         try
            pj:=Addr(bSize);
            bSize:=TempStream.Size;//获取实际流的长度
            BStream.Write(pj^,sizeof(bSize));//写入实际流的长度
            BStream.Position:=sizeof(bSize);
            InStream.Position:=0;
            BStream.CopyFrom(InStream,InStream.Size);//接着实际流长度数据后面写入压缩流
            bstream.Position:=0;
            BStream.Read(p^,BStream.Size);
         finally
            VarArrayUnlock(Param);
         end;
      finally
         VarArrayUnlock(Stream);
         InStream.Free;
         TempStream.Free;
         BStream.Free;
      end;
      Stream:=Param;
    end;{读数据流(解压缩):}
    procedure TFilePacket.UnPackStream(var Stream: OleVariant);
    var
      TempStream:TMemoryStream;
      OutStream:TMemoryStream;
      ZStream: TDecompressionStream;
      BStream:TMemoryStream;
      Param:OleVariant;
      p:Pointer;
      po:Pointer;
      bSize:int64;
      pj:Pointer;
    begin
      TempStream:=TMemoryStream.Create;
      BStream:=TMemoryStream.Create;
      OutStream:=TMemoryStream.Create;
      p:=VarArrayLock(Stream);
      try
         TempStream.Write(p^,VarArrayHighBound(Stream,1)+1);//还原为数据流
         pj:=Addr(bSize);
         TempStream.Position:=0;
         TempStream.Read(pj^,sizeof(bSize));//读出实际流的大小
         TempStream.Position:=sizeof(bSize);//移动指针到压缩流的起始位置
         if TempStream.Size>0 then BStream.CopyFrom(TempStream,TempStream.Size-sizeof(bSize));//读出压缩
         BStream.Position:=0;
         ZStream:=TDecompressionStream.Create(BStream);//解压缩
         zstream.Position:=0;
         try
            OutStream.CopyFrom(ZStream,bSize);//还入实际流的长度,而不是使用BStream或ZStream的Size属性
            Param:=VarArrayCreate([0,OutStream.Size-1],varByte);
            po:=VarArrayLock(Param);
            try
               OutStream.Position:=0;
               OutStream.Read(po^,OutStream.Size);
            finally
               VarArrayUnlock(Param);
            end;
         finally
            ZStream.Free;
         end;
      finally
         VarArrayUnlock(Stream);
         BStream.Free;
         OutStream.Free;
         TempStream.Free;
      end;
      Stream:=Param;
    end;
    initialization
      TAutoObjectFactory.Create(ComServer, TFilePacket, Class_FilePacket,
        ciMultiInstance, tmApartment);
    end.
      

  11.   

    halfdream(哈欠)大侠,远程调用参数。我没有找到OLEAUTO这个类型
      

  12.   

    FT..
    楼主,你把那个参数定义成IStream类型吧。
    DELPHI里面,可以转换IStream标准接口与VCL 的TStream类。。
    var
      a:TStreamAdapter;
      ms:TMemoryStream;
    begin
      ms:=TMemoryStream.Create;  a:=TStreamAdapter.Create(ms);
      

  13.   

    在TLB文件中没有IStream类型啊。能说具体点吗
      

  14.   

    在TLB文件中没有和IStream类型对应的类型啊,应选哪个类型呢。
      

  15.   

    把TLB中的类型声明成IUNKNOWN或VARIANT都可以。。调用的时候,传ISTREAM进去。。
      

  16.   

    我现在在TLB中把类型声明成IUNKNOWN。我把ISTREAM传到服务器端后,怎么把它转换成TSTREAM类型呢。多谢了!
      

  17.   

    可以使用TOleStream
    AXCTRLS单元
      

  18.   

    我说大侠,你能不能说具体点。我的意思是说,在TLB中怎么设置对应的类型。如果设置成IUNKNOWN类型后,服务器端的IUNKNOWN怎么转换成TSTREAM呢。能不能给出示范的原代码!
      

  19.   

    这么多天了,还以为楼主已经解决...
    比如:在类型库编译器里面加一个方法叫TestStream,加两个参数,
    第一个InStream,类型为IUnknown*
    第二个info,类型为BSTR*,OUT参数..于是就生成下面这样..
    procedure TestStream(const InStream: IUnknown; out Info: WideString); safecall;服务端可以这样...
    //------------------------------------------
    procedure TTestXXXXX.TestStream(const InStream: IUnknown;
      out Info: WideString);
    var
      stream:TOleStream;//TOLESTREAM继承自TSTREAM,也就是说
                        //可以类似TMemoryStream,TStringStream那样用它.
    begin
      stream:=TOleStream.Create(InStream as IStream);
      Info:='服务器收到流,大小:'+IntTostr(stream.Size);
      stream.Free;
    end;
    //---------------客户端测试代码可以这样...var
      aintf:ITestXXXXX;
      stream:TStreamAdapter;//流适配器
      fo:TStringStream;//随便试一种流..
      info:WideString;
    begin  fo:=TStringStream.Create('哈欠到此一游');
      stream:=TStreamAdapter.Create(fo);  aintf:=CoTestXXXXX.Create;
      aintf.TestStream(stream,info);
      aintf:=nil;
      ShowMessage(info);//输出从服务器返回的信息...
    end;
      

  20.   

    我应用了Types单元,但IStream这个类型还是不认。为什么,是DELPHI问题吗?
      

  21.   

    ISTREAM定义在ACTIVEX单元。。USES 它。。
      

  22.   

    aintf.TestStream(stream,info); 我试了你上面的一段程序。
    在调用服务器端函数的时候会出现“Type not allowed in variant Dispatch call”的错误。好像不能用IUNKNOW这个类型。
      

  23.   

    我是调试运行通过的程序才贴上来的.....Dispatch call..????
    怎么会出这个错误?
    这是使用variant方式调用才会提示的信息...楼主是怎么试的?如果楼主的参数是用的VARIANT型,需要先强制转换成IUnknown类型,再AS运算成IStream
      

  24.   

    我是用IUNKNOWN类型的。我先把客户端调用的代码,以及服务器端的函数参数类型贴出来。请大侠帮我看看!
    客户端:
      //对instream进行压缩
      ys:=TCompressionStream.Create(clMax,outstream);
      ys.CopyFrom(instream,0);
      ys.Free;
      CsVariant:=TStreamAdapter.Create(outstream);
      DM1.SocketConnection1.AppServer.ExecStream(CsVariant,d1,n1); //这句就报“Dispatch call”
      
    服务器端:
      function Tzr.ExecStream(const StreamName: IUnknown; const D_Key,
      N_Key: WideString): WideString;
      

  25.   

    哦。。原来你用的是SocketConnection1,用它是不支持这样传接口类型的参数。。
    使用DCOM,或者COM+是支持的。。
    var
      stream:IStream;
      fo:TStringStream;
      info:WideString;begin  fo:=TStringStream.Create('哈欠到此一游');
      stream:=TStreamAdapter.Create(fo);  DCOMConnection1.Connected:=true;
      DCOMConnection1.AppServer.TestStream(stream,info);
      DCOMConnection1.Connected:=false;  ShowMessage(info);
      

  26.   

    那大侠知道否。在Socketconnetion中传递Stream类型。在TLB中设置什么相应的类型呢。
      

  27.   

    为什么一定要stream呢,转换成string好了。就是字节流嘛。
    zlib解压缩的时候不是很方便,要设一个循环,具体见《Mastering Delphi7》docount :=decomstream.read(buffer,count):while(count<>0)
      

  28.   

    为什么一定要stream呢,转换成string好了。就是字节流嘛。
    ===========================
    使用StringStream吧。