1

I've developed a datasnap rest server application in RAD Studio 10.3.2. In one of my server methods I receive an image from the client app. The image data is a base64 encoded string as a json value. My method is something like this:

function TServerMethods1.getImage(JSONobj: TJSONObject): Boolean;
var
  OutputStream : TMemoryStream;
  InputStream  : TStringStream;
  theImage     : TBitmap;
begin
  var imageStr    :  string := JSONobj.GetValue('Image').Value;
  InputStream     := TStringStream.Create(imageStr);
//InputStream.saveToFile('C:\InputStream.txt');
  OutputStream    := TMemoryStream.Create;
  theImage        := TBitmap.Create;
  try
    InputStream.Position  := 0;
    TNetEncoding.Base64.Decode(InputStream, OutputStream);
  //OutputStream.saveToFile('C:\OutputStream.txt'); 
    OutputStream.Position := 0;
    theImage.LoadFromStream(OutputStream);  // in this line I get an access violation error!
  finally
    theStringStream.Free;
    theMemoryStream.Free;
  end;
  .
  .
  .
end;

When I build the project as a standalone firemonkey app (.exe file) everything works fine but when I build an ISAPI dll and deploy it in IIS I got an access violation error in the line that I added a comment to it. What's wrong? I'm really confused!

P.S.

  1. I saved both InputStream and OutputStream somewhere so that I get sure that I receive the stream and decode it properly and both streams are just fine.

  2. The variable theImage: TBitmap; is an object of FMX.Graphics.TBitmap class, because my stand-alone GUI is a firemonkey application.

Moj.H
  • 75
  • 12
  • Did you try with `TBitmap` from VCL? – Olivier Jul 20 '20 at 18:50
  • You can actually debug your ISAPI dll if you use the local IIS on your machine, and use the debugger to attach to the IIS and have a breakpoint in your DLL at the required spot. See https://stackoverflow.com/questions/5899773/ Debugging probably sheds light on what causes the AV, you may have to "Use debug DCU's" to get deeper in the VCL – H.Hasenack Jul 20 '20 at 20:13
  • @H.Hasenack This is the path that I traced into respectively: `TBitmap.GetImage` of `FMX.Graphics` unit, then `TCanvasGdiPlus.DoInitializeBitmap` function of `FMX.Canvas.GDIP` unit, then `TGPBitmap.Create` constructor in the `Winapi.GDIPOBJ`. Finally I got to `Winapi.GDIPAPI` unit. The function `class function TGdiplusBase.NewInstance: TObject;` has a one line of code inside: `Result := InitInstance(GdipAlloc(ULONG(instanceSize)));` I traced into `TObject.InitInstance` function and inside of it there is an `asm` code: `STOSD`. This is the place the AV occures. And I'm just more confused!!! – Moj.H Jul 21 '20 at 17:14
  • @Olivier How can I do that? Should I just add vcl units to `uses` list and use vcl `TBitmap`? My GUI application is a firemonkey app. When building the project as an ISAPI dll, is it possible to use vcl units too? – Moj.H Jul 21 '20 at 17:17
  • @Olivier I used vcl units. Actually TBitmap was not the correct one. Instead I used `Vcl.Imaging.jpeg` unit and that worked just fine. – Moj.H Jul 21 '20 at 17:41

1 Answers1

1

It seems that the TBitmap class of fmx has problems with ISAPI dll. So Instead of using FMX.Graphics I utilized TJPEGImage class of vcl. In order to achieve that I added Vcl.Imaging.jpeg to uses section of ServerMethodsUnit. Then I changed my previous function to this:

function TServerMethods1.getImage(JSONobj: TJSONObject): Boolean;
var
  OutputStream : TMemoryStream;
  InputStream  : TStringStream;
  theImage     : TJPEGImage;   // using TJPEGImage instead of FMX.Graphics.TBitmap
begin
  var imageStr    :  string := JSONobj.GetValue('Image').Value;
  InputStream     := TStringStream.Create(imageStr);
  OutputStream    := TMemoryStream.Create;
  theImage        := TJPEGImage.Create;
  try
    InputStream.Position  := 0;
    TNetEncoding.Base64.Decode(InputStream, OutputStream);
    OutputStream.Position := 0;
    theImage.LoadFromStream(OutputStream);  // Now this line works fine!
  finally
    theStringStream.Free;
    theMemoryStream.Free;
  end;
  .
  .
  .
end;

Now I can load the received image from memorystream and save it as a jpeg image file.

Moj.H
  • 75
  • 12