Link to home
Start Free TrialLog in
Avatar of WoodyJ007
WoodyJ007

asked on

Passing bitmaps through COM

Any idea how to pass bitmaps through COM?

I have an automation server that is generating Bitmaps (TBitmap).

I want a client to call something like GetBitmap on the server.

I've experimented with IPicture but I can't seem to get it to work properly.

Examples would be good.

Thanks
Woody.
Avatar of stepashka
stepashka

IPicture will work only if you have an inproc (DLL) com server.

You should pack you bitmap into the variant array and path it to your client.
ASKER CERTIFIED SOLUTION
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of WoodyJ007

ASKER

Thanks.  I'll give it a try and get back to you later.
ooops of course: should be
var ret: OleVariant;
ret:=DCOMConn.AppServer.DownLoad('somefile.extension');

ziolko.
Will it work if I change it from a TFileStream to a THandleStream?

The Server code looks like this....

function TAIBallTest.GetBitmap(Port: Integer): OleVariant;
Var
   Bmp : TBitmap;
   FSize : LongInt;
   ms : TStream;
   P : Pointer;
   Tmp : OleVariant;
begin
   Bmp := Form1.GetBitmap(Port);

      Result := UNASSIGNED;
      tmp:=UNASSIGNED;

      try
        ms:=THandleStream.Create(Bmp.Handle);
        if ms = nil then
          begin
            Result:=NULL;
            Exit;
          end;
        ms.Position:=0;
      fsize:=ms.Size;
      Result:=VarArrayCreate([0,1],varVariant);
      Result[0]:='TOTAL='+IntToStr(fsize)+',CONTENT=BITMAP';
      tmp:=VarArrayCreate([1,fsize],varByte);
      P:=VarArrayLock(tmp);
      try
        ms.ReadBuffer(P^,fsize);
      finally
        VarArrayUnLock(tmp);
      end;
      Result[1]:=tmp;
      ms.Free;
      tmp:=UNASSIGNED;
      VarClear(tmp);
      except
         //
      end;
end;


I can't seem to figure out the client side (thats if I can use THandleStream at all)

So far...

Var
   Bitmap : OleVariant;
   stream : TStream;
   ResultBitmap : TBitmap;
   Tmp : String;
   FSize : LongInt;
   P : Pointer;
   cont : OleVariant;
begin
   ResultBitmap := TBitmap.Create;

   Bitmap := AIBall.GetBitmap(1);

   If VarIsArray(Bitmap) Then
   Begin
        stream:=ThandleStream.Create(ResultBitmap.Handle);
      try
           tmp:=string(Bitmap[0]);
           cont:=Bitmap[1];
           System.Delete(tmp,1,Pos('=',tmp));
           fsize:=StrToInt(Copy(tmp,1,Pos(',',tmp)-1));
           stream.Position:=0;
           P:=VarArrayLock(cont);
           try
             stream.WriteBuffer(P^,fsize);
           finally
             VarArrayUnLock(cont);
           end;
           stream.Size:=fsize;
         finally
           stream.Free;
         end;
       end;
     Bitmap:=UNASSIGNED;
     VarClear(Bitmap);

   ResultBitmap.SaveToFile('C:\Crapdump\b.bmp');

   ResultBitmap.Free;
I'll get back to You tomorrow.
ziolko.
You can try THandleStream but if this wont work simply use TStream and then ResultBitmap.LoadFromStream(), code will look something like this:

  ResultBitmap := TBitmap.Create;

  Bitmap := AIBall.GetBitmap(1);

  If VarIsArray(Bitmap) Then
  Begin
       stream:=TStream.Create;
     try
          tmp:=string(Bitmap[0]);
          cont:=Bitmap[1];
          System.Delete(tmp,1,Pos('=',tmp));
          fsize:=StrToInt(Copy(tmp,1,Pos(',',tmp)-1));
          stream.Position:=0;
          P:=VarArrayLock(cont);
          try
            stream.WriteBuffer(P^,fsize);
          finally
            VarArrayUnLock(cont);
          end;
          stream.Size:=fsize;
          ResultBitmap.LoadFromStream(stream);
        finally
          stream.Free;
        end;
      end;
    Bitmap:=UNASSIGNED;
    VarClear(Bitmap);

  ResultBitmap.SaveToFile('C:\Crapdump\b.bmp');

  ResultBitmap.Free

ziolko.
I can't seem to get this to work.  Your TFileStream code works fine but I don't really want to save files and load files when I send and receive.

I've tried using TMemoryStream but that doesn't seem to work either.  Below is the unit code I am currently using to test it. (simple form with two Images and a button)

Cheers
Woody

...

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    Function MakeImage1VariantArray : OleVariant;
    Procedure LoadVariantArrayIntoImage2(Var VArray : OleVariant);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.MakeImage1VariantArray: OleVariant;
Var
   Bmp : TBitmap;
   FSize: LongInt;
   MemStream : TMemoryStream;
   P : Pointer;
   vTmp : OleVariant;
begin
   Result := UNASSIGNED;

   // Get the bitmap
   Bmp := Image1.Picture.Bitmap;

      vTmp := UNASSIGNED;

      Try
        MemStream := TMemoryStream.Create;

      Bmp.SaveToStream(MemStream);

        MemStream.Position := 0;
        FSize := MemStream.Size;

        Result := VarArrayCreate([0,1], varVariant);

        Result[0] := 'TOTAL=' + IntToStr(FSize);

        vTmp := VarArrayCreate([1, FSize], varByte);
        P := VarArrayLock(vTmp);

        Try
               MemStream.ReadBuffer(P^, FSize);
        Finally
               VarArrayUnLock(vTmp);
        End;

        Result[1] := vTmp;

        MemStream.Free;
          VTmp:=UNASSIGNED;
        VarClear(vTmp);
      Except
         //
      End;
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
   vBitmap : OleVariant;
begin
   vBitmap := MakeImage1VariantArray;
   LoadVariantArrayIntoImage2(vBitmap);
end;

procedure TForm1.LoadVariantArrayIntoImage2(var VArray : OleVariant);
Var
   ResultBitmap : TBitmap;
   P : Pointer;
   FSize : LongInt;
   TmpStr : String;
   MemStream : TMemoryStream;
   Cont : OleVariant;
begin
     ResultBitmap := TBitmap.Create;

     If VarIsArray(VArray) Then
      Begin
        MemStream := TMemoryStream.Create;
         Try
           TmpStr := String(VArray[0]);
         Cont := VArray[1];
         System.Delete(TmpStr, 1, Pos('=', TmpStr));
         FSize := StrToInt(TmpStr);

         MemStream.Position := 0;
         P := VarArrayLock(Cont);
         Try
              MemStream.WriteBuffer(P^, FSize);
         Finally
              VarArrayUnLock(Cont);
         End;
         MemStream.Size := FSize;

         ResultBitmap.LoadFromStream(MemStream);

         Image2.Picture.Bitmap.Assign(ResultBitmap);
        Finally
         MemStream.Free;
      End;
   End;

   VArray := UNASSIGNED;
   VarClear(VArray);

     ResultBitmap.Free
end;

end.
I was forgetting to rewind the stream.

Thanks.



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    Function MakeImage1VariantArray : OleVariant;
    Procedure LoadVariantArrayIntoImage2(Var VArray : OleVariant);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.MakeImage1VariantArray: OleVariant;
Var
   Bmp : TBitmap;
   FSize: LongInt;
   Stream : TMemoryStream;
   P : Pointer;
   vTmp : OleVariant;
begin
   Result := UNASSIGNED;

   // Get the bitmap
   Bmp := Image1.Picture.Bitmap;

      vTmp := UNASSIGNED;

      Try
        Stream := TMemoryStream.Create;

      Bmp.SaveToStream(Stream);
        FSize := Stream.Size;
      Stream.Position := 0;

        Result := VarArrayCreate([0,1], varVariant);

        Result[0] := 'TOTAL=' + IntToStr(FSize);

        vTmp := VarArrayCreate([1, FSize], varByte);
        P := VarArrayLock(vTmp);

        Try
               Stream.ReadBuffer(P^, FSize);
        Finally
               VarArrayUnLock(vTmp);
        End;

        Result[1] := vTmp;

        Stream.Free;
          VTmp := UNASSIGNED;
        VarClear(vTmp);
      Except
         //
      End;
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
   vBitmap : OleVariant;
begin
   vBitmap := MakeImage1VariantArray;
   LoadVariantArrayIntoImage2(vBitmap);
end;

procedure TForm1.LoadVariantArrayIntoImage2(var VArray : OleVariant);
Var
   ResultBitmap : TBitmap;
   P : Pointer;
   FSize : LongInt;
   TmpStr : String;
   MemStream : TMemoryStream;
   Cont : OleVariant;
begin
     ResultBitmap := TBitmap.Create;

     If VarIsArray(VArray) Then
      Begin
        MemStream := TMemoryStream.Create;
         Try
           TmpStr := String(VArray[0]);
         Cont := VArray[1];
         System.Delete(TmpStr, 1, Pos('=', TmpStr));
         FSize := StrToInt(TmpStr);

         P := VarArrayLock(Cont);
         Try
              MemStream.WriteBuffer(P^, FSize);
         Finally
              VarArrayUnLock(Cont);
         End;
         MemStream.Size := FSize;
         MemStream.Position := 0;

         ResultBitmap.LoadFromStream(MemStream);

         Image2.Picture.Bitmap.Assign(ResultBitmap);
        Finally
         MemStream.Free;
      End;
   End;

   VArray := UNASSIGNED;
   VarClear(VArray);

     ResultBitmap.Free
end;

end.
only one line is missing in proceedure below

procedure TForm1.LoadVariantArrayIntoImage2(var VArray : OleVariant);
Var
  ResultBitmap : TBitmap;
  P : Pointer;
  FSize : LongInt;
  TmpStr : String;
  MemStream : TMemoryStream;
  Cont : OleVariant;
begin
    ResultBitmap := TBitmap.Create;

    If VarIsArray(VArray) Then
     Begin
       MemStream := TMemoryStream.Create;
        Try
          TmpStr := String(VArray[0]);
        Cont := VArray[1];
        System.Delete(TmpStr, 1, Pos('=', TmpStr));
        FSize := StrToInt(TmpStr);

        MemStream.Position := 0;
        P := VarArrayLock(Cont);
        Try
             MemStream.WriteBuffer(P^, FSize);
        Finally
             VarArrayUnLock(Cont);
        End;
        MemStream.Size := FSize;
        MemStream.Position:=0;  // <- You have to reset position to begining of stream, because bitmaps LoadFromStream begins reading from current position
        ResultBitmap.LoadFromStream(MemStream);

        Image2.Picture.Bitmap.Assign(ResultBitmap);
       Finally
        MemStream.Free;
     End;
  End;

  VArray := UNASSIGNED;
  VarClear(VArray);

    ResultBitmap.Free
end;


ziolko.
hi ziolko !
i've got a big problem with an active x which results a TBitmap as OleVariant. I tried
to use your function above to load it but it results "index out of range". i hope that
ypu can help me with that ? would be perfect if you could mail me: fuluppi@tiscali.de

thanks in advance!
ItsMe
I'll post You sample app, if error persists debug project and let me know where error occurs
ziolko.