?
Solved

Passing bitmaps through COM

Posted on 2003-02-25
12
Medium Priority
?
276 Views
Last Modified: 2013-12-03
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.
0
Comment
Question by:WoodyJ007
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
12 Comments
 
LVL 1

Expert Comment

by:stepashka
ID: 8016082
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.
0
 
LVL 21

Accepted Solution

by:
ziolko earned 480 total points
ID: 8016118
thats the way I did file downloading through DCOM

function TRemoteAdmin.FileDownLoad(const FileName: WideString): OleVariant;
var fsize: LongInt;
    ms: TStream;
    P: Pointer;
    tmp: OleVariant;
begin
  Result:=UNASSIGNED;
  tmp:=UNASSIGNED;
  try
    ms:=TFileStream.Create(FileName,fmOpenRead);
    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='+FileName;
    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;

then on the DCOM client side:
var FileAsVariant: OleVariant;
  FileAsVariant:=DCOMConn.AppServer.DownLoad('somefile.extension');

and this should decode variant and write file:

      if VarIsArray(ret) then
        begin
          stream:=TFileStream.Create(
{destination path},fmCreate);
          try
            tmp:=string(ret[0]);
            cont:=ret[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;
            Result:=True;
          end;
        end;
      ret:=UNASSIGNED;
      VarClear(ret);


ziolko.
0
 

Author Comment

by:WoodyJ007
ID: 8016156
Thanks.  I'll give it a try and get back to you later.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 21

Expert Comment

by:ziolko
ID: 8016261
ooops of course: should be
var ret: OleVariant;
ret:=DCOMConn.AppServer.DownLoad('somefile.extension');

ziolko.
0
 

Author Comment

by:WoodyJ007
ID: 8016322
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;
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8016477
I'll get back to You tomorrow.
ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8023157
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.
0
 

Author Comment

by:WoodyJ007
ID: 8023886
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.
0
 

Author Comment

by:WoodyJ007
ID: 8024149
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.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8024188
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.
0
 

Expert Comment

by:ItsMe
ID: 8550429
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
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8555895
I'll post You sample app, if error persists debug project and let me know where error occurs
ziolko.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
Suggested Courses
Course of the Month13 days, 11 hours left to enroll

800 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question