#1 2012-08-08 17:57:34

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

"Access violation" or "Out of memory" during ExportPDF()

Hi all!

I'm new in Synopse PDF Engine but as I see it's pretty well package smile I've started to use SPDFE in one of my project to generate simple reports and I have big problem...

My code:

procedure TFZamkniecia_CykleOrganizacji.pGenerujPociagiPrzewoznikow(IdCykluOrgZamk: Integer);
var
  i: Integer;
  j: Integer;
  PDF: TGDIPages;
  Txt: String;
  CyklObowOd: String;
  CyklObowDo: String;
  Lp: Integer;
  k: Integer;
  r: Integer;
  NazwaPliku: String;
  NrZarzadzenia: String;
  DataZarzadzenia: String;
  p: String;
  TypZmiany: Integer;
  KomZastFound: Integer;
  KomZastBeg: String;
  KomZastEnd: String;
  ZmiTrasBeg: String;
  ZmiTrasEnd: String;
begin

  adospPZ_PR.Active := False;
  adospPZ_PR.Parameters.ParamByName('@IdCykluOrgZamk').Value := IdCykluOrgZamk;
  adospPZ_PR.Parameters.ParamByName('@IlePociagow').Value := 0;
  adospPZ_PR.Active := True;
  pbc.Max := OT.NullToZero(adospPZ_PR.Parameters.ParamByName('@IlePociagow').Value);

  if adospPZ_PR.RecordCount = 0 then
  begin
    Application.MessageBox('Nie znaleziono żadnych pociągów do wygenerowania', PChar(Caption), MB_ICONWARNING);
    Exit;
  end
  else if adospPZ_PR.RecordCount = 1 then
    p := 'przewoźnika'
  else
    p := 'przewoźników';

  memLog.Lines.Add('Rozpoczynam generowanie pociągów dla ' + IntToStr(adospPZ_PR.RecordCount) + ' ' + p + ' ...');
  memLog.Lines.Add(' ');
  Application.ProcessMessages;

  pbc.Max := 0;
  RichEdit.Text := '';

  for i := 0 to adospPZ_PR.RecordCount - 1 do
  begin

    TypZmiany := -1;

    if CancelGenerate then
      Exit;

    memLog.Lines.Add('Przewoźnik: ' + adospPZ_PR['NazwaPrzewoznika']);
    Application.ProcessMessages;

    adospPZ_LP.Active := False;
    adospPZ_LP.Parameters.ParamByName('@CentralaPrzewoznika').Value := adospPZ_PR['CentralaPrzewoznika'];
    adospPZ_LP.Parameters.ParamByName('@IdCykluOrgZamk').Value := IdCykluOrgZamk;
    adospPZ_LP.Active := True;

    cdsPZ_LP1.Active := False;
    cdsPZ_LP1.Active := True;
    adospPZ_LP.RecordSet := adospPZ_LP.NextRecordSet(r);
    cdsPZ_LP2.Active := False;
    cdsPZ_LP2.Active := True;

    memLog.Lines.Add('Liczba pociągów przewoźnika: ' + IntToStr(cdsPZ_LP1.RecordCount));
    memLog.Lines.Add(' ');

    Application.ProcessMessages;

    PDF := TGDIPages.Create(Self);
    try
      try
        //naglowek START
        PDF.Caption := 'Projekt zastępczego rozkładu jazdy - ZASTĘPCZE I DODATKOWE POCIĄGI';

        PDF.BeginDoc;

        PDF.Font.Name := 'Times New Roman';

        PDF.SaveLayout;

        PDF.Font.Name := 'Tahoma';

        PDF.DrawBMP(logo.Picture.Bitmap, 0, 190);

        PDF.TextAlign := taRight;

        PDF.AddTextToHeader(DateTimeToStr(Now));
        PDF.AddLineToHeader(false);

        PDF.AddLineToFooter(false);

        PDF.TextAlign := taRight;
        PDF.AddPagesToFooterAt('Strona %d z %d', PDF.RightMarginPos);

        PDF.TextAlign := taCenter;
        PDF.Font.Size := 7;
        PDF.Font.Color := clGray;
        PDF.AddTextToFooter('Spółka wpisana do rejestru przedsiębiorców prowadzonego przez Sąd Rejonowy dla m.st. Warszawy w Warszawie ');
        PDF.AddTextToFooter('XIII Wydział Gospodarczy Krajowego Rejestru Sądowego pod numerem ');
        PDF.AddTextToFooter('KRS 0000037568. NIP 113-23-16-427, REGON 017319027 ');
        PDF.AddTextToFooter('Kapitał zakładowy 13 043 747 000,00 w całości wpłacony.');

        PDF.TextAlign := taCenter;

        PDF.Font.Style := [fsBold];
        PDF.Font.Size := 9;
        PDF.Font.Color := clBlack;
        PDF.DrawText('CENTRUM ZARZĄDZANIA RUCHEM KOLEJOWYM');
        PDF.DrawText('Wydział ds. Organizacji Zamknięć Torowych i Indywidulanego Rozkładu Jazdy');
        PDF.Font.Style := [];
        PDF.DrawText('03-734 Warszawa, ul. Targowa 74, tel.: +48 (0-22) 473-35-65, fax: +48 (0-22) 473-39-00');
        PDF.Font.Color := clBlue;
        PDF.DrawText('mail@mail.pl');

        PDF.Font.Style := [fsBold, fsUnderline];
        PDF.Font.Size := 16;
        PDF.Font.Color := clBlack;
        PDF.NewLine;
        PDF.DrawText('PROJEKT ZASTĘPCZEGO ROZKŁADU JAZDY');

        PDF.Font.Style := [fsBold];
        PDF.Font.Size := 14;
        PDF.NewHalfLine;
        NrZarzadzenia := OT.NullToValue(ADOQ_Cykle['NrZarzadzenia'], 'BRAK NUMERU ZARZĄDZENIA');
        DataZarzadzenia := OT.NullToValue(ADOQ_Cykle['DataZarzadzenia'], 'BRAK DATY ZARZĄDZENIA');
        PDF.DrawText(NrZarzadzenia + ' z dnia ' + DataZarzadzenia);

        PDF.RestoreSavedLayout;

        PDF.NewLine;

        CyklObowOd := ADOQ_Cykle['ObowOd'];
        CyklObowDo := ADOQ_Cykle['ObowDo'];

        PDF.Font.Size := 12;
        Txt := 'IDDRZ Warszawa - z powodu zamknięć torowych na sieci PKP PLK S.A.' +
        ' w terminie od ' + CyklObowOd + ' do ' + CyklObowDo +
        ' zarządzam organizację ruchu dla następujących pociągów:';
        PDF.DrawText(Txt);

        PDF.Font.Style := [fsBold];
        PDF.Font.Size := 16;
        PDF.Font.Color := clBlack;
        PDF.NewLine;
        PDF.DrawTitle(adospPZ_PR['NazwaPrzewoznika'], true);

        //naglowek - END

        { *********************************** }

        pbp.Position := 0;

        PDF.LineSpacing := lsOneAndHalf;

        PDF.Font.Style := [];
        PDF.Font.Size := 12;
        PDF.TextAlign := taJustified;

        Lp := 0;
        for j := 0 to cdsPZ_LP1.RecordCount - 1 do
        begin

          if CancelGenerate then
            Exit;

          if TypZmiany <> cdsPZ_LP1['TypZmiany'] then
          begin
            TypZmiany := cdsPZ_LP1['TypZmiany'];
            Lp := 0;
            PDF.SaveLayout;
            PDF.Font.Style := [fsBold];
            PDF.Font.Size := 12;
            PDF.Font.Color := clBlack;
            case TypZmiany of
              0: PDF.DrawTitle('I. Pociągi zastępcze w organizacji zamknięciowej bez zmian w trasie pociągu', false);
              1: PDF.DrawTitle('II. Pociągi zastępcze w organizacji zamknięciowej ze skróconą relacją', false);
              2: PDF.DrawTitle('III. Pociągi zastępcze w organizacji zamknięciowej ze zmienioną relacją', false);
              3: PDF.DrawTitle('IV. Pociągi dodatkowe organizacji zamknięciowej', false);
            end;
            PDF.RestoreSavedLayout;
          end;

          cdsPZ_LP2.Filtered := False;
          cdsPZ_LP2.Filter := 'IdZam=' + VarToStr(cdsPZ_LP1['IdZam']);
          cdsPZ_LP2.Filtered := True;

          memLog.Lines[memLog.Lines.Count-1] := 'Postęp generowania pociągów przewoźnika: ' + IntToStr(Round(((j+1) / cdsPZ_LP1.RecordCount) * 100)) + '%';
          pbp.Position := Round(((j+1) / cdsPZ_LP1.RecordCount) * 100);

          pbc.Position := pbc.Position + 1;
          Application.Processmessages;

          //pociagi
          Inc(Lp);

          //naglowek
          Txt := '    ' + IntToStr(Lp) + ')  ';
          Txt := Txt + 'Nr pociągu: ';
          Txt := Txt + OT.NullToValue(cdsPZ_LP1['NrPociagu'], '?') + '; ';
          Txt := Txt + 'rodzaj pociągu: ';
          Txt := Txt + OT.NullToValue(cdsPZ_LP1['Rodzaje'], '?') + '; ';
          Txt := Txt + 'ID zamówienia: ';
          Txt := Txt + IntToStr(cdsPZ_LP1['IdZam']) + '; ';
          Txt := Txt + 'relacja: ';
          Txt := Txt + OT.NullToValue(cdsPZ_LP1['StacjaOdZamk'], '?') + ' - ' + OT.NullToValue(cdsPZ_LP1['StacjaDoZamk'], '?');

          if
          (cdsPZ_LP1['StacjaOdPierw'] <> cdsPZ_LP1['StacjaOdZamk'])
          or
          (cdsPZ_LP1['StacjaDoPierw'] <> cdsPZ_LP1['StacjaDoZamk'])
          then
            Txt := Txt + ' (' + OT.NullToValue(cdsPZ_LP1['StacjaOdPierw'], '?') + ' - ' + OT.NullToValue(cdsPZ_LP1['StacjaDoPierw'], '?') + '); '
          else
            Txt := Txt + '; ';

          Txt := Txt + 'kursuje: ';
          Txt := Txt + OT.NullToValue(cdsPZ_LP1['Opis'], '?') + '; ';
          //naglowek

          //trasa
          KomZastFound := 0;
          KomZastBeg := '';
          KomZastEnd := '';
          ZmiTrasBeg := '';
          ZmiTrasEnd := '';
          Txt := Txt + 'trasa: ';
          for k := 0 to cdsPZ_LP2.RecordCount - 1 do
          begin

            if CancelGenerate then
              Exit;

            if OT.NullToValue(cdsPZ_LP2['NazwaStacjiZamk'], '') <> '' then
            begin
              //komunikacja zastepcza
              if cdsPZ_LP2['KomZast']=1 then
                Inc(KomZastFound);
              if KomZastFound = 1 then
              begin
                KomZastBeg := '[';
                KomZastEnd := ']';
              end
              else
              begin
                KomZastBeg := '';
                KomZastEnd := '';
              end;

              //zmieniona trasa
              if OT.NullToZero(cdsPZ_LP2['NrPoprzZamk']) = 0 then
              begin
                ZmiTrasBeg := '<';
                ZmiTrasEnd := '>';
              end
              else
              begin
                ZmiTrasBeg := '';
                ZmiTrasEnd := '';
              end;

              if (KomZastFound = 0) or (KomZastFound = 1) then
              begin

                Txt := Txt + ZmiTrasBeg + KomZastBeg + OT.NullToValue(cdsPZ_LP2['NazwaStacjiZamk'], '?') + ' ' + OT.NullToValue(cdsPZ_LP2['PrzyjazdZamk'], '?');
                if (k > 0) and (k < cdsPZ_LP2.RecordCount - 1) then
                  Txt := Txt + '/' + OT.NullToValue(cdsPZ_LP2['OdjazdZamk'], '?');

                Txt := Txt + KomZastEnd + ZmiTrasEnd;

                if
                (OT.NullToZero(cdsPZ_LP2['RoznicaPrzyjazd'])<>0)
                or
                (OT.NullToZero(cdsPZ_LP2['RoznicaOdjazd'])<>0)
                then
                begin
                  Txt := Txt + ' (' + FloatToStr(cdsPZ_LP2['RoznicaPrzyjazd']);
                  if (k > 0) and (k < cdsPZ_LP2.RecordCount - 1) then
                     Txt := Txt + '/' + FloatToStr(cdsPZ_LP2['RoznicaOdjazd']) + '); '
                  else
                    Txt := Txt + '); ';
                end
                else
                  Txt := Txt + '; ';

              end;
              
            end;

            cdsPZ_LP2.Next;
          end;
          //trasa

          PDF.DrawText(Txt);
          PDF.NewHalfLine;

          TypZmiany := cdsPZ_LP1['TypZmiany'];

          //pociagi
          cdsPZ_LP1.Next;
        end;
        
        PDF.NewLine;
        PDF.Font.Style := [fsBold, fsUnderline];
        PDF.Font.Size := 10;
        PDF.DrawText('Informacje:');
        PDF.Font.Style := [];
        PDF.Font.Size := 10;
        PDF.DrawText('Podkreslenie nazwy stacji w trasie oznacza komunikację zastępczą. Pochylenie nazwy stacji w trasie oznacza zmianę trasy pociągu.');

        { *********************************** }

        PDF.EndDoc;

        NazwaPliku := IntToStr(IdCykluOrgZamk) + '_' +
          StringReplace(Trim(CyklObowOd), '.', '-', [rfReplaceAll, rfIgnoreCase]) + '_' +
          StringReplace(Trim(CyklObowDo), '.', '-', [rfReplaceAll, rfIgnoreCase]) + '_' +
          UpperCase(adospPZ_PR['CentralaPrzewoznika']) +
          '_ZMIANA_ORGANIZACJI_RUCHU.pdf';

        //Zapis
        if not PDF.ExportPDF(
          ExtractFilePath(Application.ExeName) + 'Zamkniecia\' +
          NazwaPliku,
          false,
          false
        ) then
          Application.MessageBox('Nieudane generowanie pliku PDF', PChar(Caption), MB_ICONERROR)
        else
        begin

          Inc(LProjekty);
          SetLength(Projekty, LProjekty);
          Projekty[LProjekty-1].Zamkniecia := False;
          Projekty[LProjekty-1].NazwaPliku := NazwaPliku;
          Projekty[LProjekty-1].UmowaPas := (adospPZ_PR['P'] and  1);
          Projekty[LProjekty-1].NazwaPrzew := OT.NullToValue(adospPZ_PR['NazwaPrzewoznika'], '?');
          Projekty[LProjekty-1].EmailPrzew := OT.NullToValue(adospPZ_PR['EmailZastProjekt'], '');

        end;

        pbp.Position := 0;

        if cbPokazPDF.Checked then
          PDF.ShowPreviewForm;
      except
        on E: Exception do
          Application.MessageBox(PChar(E.Message), PChar(Caption), MB_ICONERROR);
      end;
    finally
      FreeAndNil(PDF);
    end;

    memLog.Lines.Add(' ');

    adospPZ_PR.Next;

  end;

  pbc.Position := 0;

end;

I don't know why but when calling PDF.ExportPDF() I've got Access Violation in procedure:

procedure TPdfWrite.Save;
var L: integer;
begin
  L := B-@Tmp;
  inc(fDestStreamPosition,L);
  fDestStream.Write(Tmp,L); //<-- here comes AV
  B := @Tmp;
end;

or Out of memory in procedure:

function THeapMemoryStream.Realloc(var NewCapacity: Integer): Pointer;
// allocates memory from Delphi heap (FastMM4/SynScaleMM) and not windows.Global*()
// and uses bigger growing size -> a lot faster
var i: PtrInt;
begin
  if NewCapacity>0 then begin
    i := Seek(0,soFromCurrent); // no direct access to fSize -> use Seek() trick
    if NewCapacity=Seek(0,soFromEnd) then begin // avoid ReallocMem() if just truncate
      result := Memory;
      Seek(i,soFromBeginning);
      exit;
    end;
    NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);
    Seek(i,soFromBeginning);
  end;
  Result := Memory;
  if NewCapacity <> Capacity then begin
    if NewCapacity = 0 then begin
      FreeMem(Memory);
      Result := nil;
    end else begin
      if Capacity = 0 then
        GetMem(Result, NewCapacity) else
        if NewCapacity > Capacity then // only realloc if necessary (grow up)
          ReallocMem(Result, NewCapacity) else
          NewCapacity := Capacity; // same capacity as before
      if Result = nil then
        raise EStreamError.Create('THeapMemoryStream'); // memory allocation bug
    end;
  end;
end;

As you can see my report doesn't contain any difficult things.

Thanks for your help!

Last edited by Wooya (2012-11-15 12:19:58)


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#2 2012-08-08 18:27:50

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Could you find out a shorter code to reproduce the issue, without any dependency?

Or at least send the corresponding .emf  content of this page via email at webcontact01 at synopse dot info ?

Offline

#3 2012-08-08 19:12:08

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

I've noticed that AV and OoM happens when I'm using data from MS SQL database. So I think that I can't reproduce this issue without any dependencies. Please tell me how to generate and save .emf content then I'll send it to you.

Thanks for reply!

EDIT: Strange but ShowPreviewForm() shows PDF content correctly...

EDIT2: I've noticed AV and OoM happens when those texts appear in DrawTitle():

        PDF.DrawTitle('Lubelski Węgiel "Bogdanka" Spółka Akcyjna w Bogdance');
        PDF.DrawTitle('Zakład Inżynierii Kolejowej Leśkiewicz Kosmala Spółka Jawna');

That's in polish. Default code page CP-1250 (also at MS SQL side). My Delphi is 2007 Architect, MS SQL 2005, PDF Engine 1.15

EDIT3: Here's sample PDF which was succesfully generated with code posted above: http://in-rock.pl/downloads/5_2012-10-1 … _RUCHU.pdf

EDIT4: I'm trying now to generate PDF reports without any text formating (no bold, no size, no titles) and it seems to working fine... neutral

Last edited by Wooya (2012-08-09 11:36:53)


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#4 2012-08-09 07:16:42

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

You have the Pages[] property in TGdiPages, and you can loop into all items and save the Objects[] which are in fact TMetaFile instances, one per page.

Therefore you'll have .emf files, one per page.

Offline

#5 2012-08-09 12:20:28

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Sorry, but could you post code here how to save pages & objects...

EDIT: ok, I know already how to do that  Will send you files in the minutes...
EDIT2: I've opened EMF files in IrfanView and Total Commander and both apps shows no errors about those files...
EDIT3:
Here AV rises at the moment:

function TPdfDocument.SaveToFile(const aFileName: TFileName): boolean;
var FS: TFileStream;
begin
  try
    FS := TFileStream.Create(aFileName,fmCreate);
    try
      SaveToStream(FS); //<-- here AV rises
      result := true;
    finally
      FS.Free;
    end;
  except
    on E: Exception do // error on file creation (opened in reader?)
      result := false;
  end;
end;

Last edited by Wooya (2012-08-09 12:22:25)


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#6 2012-08-09 18:24:27

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

After many hours of testing my conclusions are:
- propably my problem is an issue of CP-1250 codepage
- I can't use DrawTitle() function - causing AV and OoM (I suppose it's connected with conclusion above)
- less text formatting is better in my issue
- I think it's most important in my issue: I CAN'T USE POLISH CHARS IN PDF.Caption PROPERTY! This causes almost 100% AV

With those restrictions I can produce an PDF from Delphi with SynPDF wink If I can help with debug this issue please ask what you need. BTW:  Thanks a lot for this great Delphi Open Source piece of code!

Last edited by Wooya (2012-08-09 19:09:03)


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#7 2012-08-10 11:59:06

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

I just tried both supplied .rar files.

With the latest version (from http://synopse.info/fossil site) of SynPDF + other units, I do not have any problem rendering the files with the following code:

  with TPdfDocument.Create do
  try
    for i := 0 to 24 do begin
      AddPage;
      M := TMetaFile.Create;
      M.LoadFromFile(IntToStr(i)+'.emf');
      Canvas.RenderMetaFile(M,Canvas.Page.PageHeight/M.Height);
      M.Free;
    end;
    FN := ChangeFileExt(paramstr(0),'.pdf');
    SaveToFile(FN);
    ShellExecute(Handle,nil,pointer(FN),nil,nil,SW_SHOWNORMAL);
  finally
    Free;
  end;

So it is very difficult to find what is wrong here.

CP-1250 is handled as expected.

Offline

#8 2012-09-07 09:25:11

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

So it's very strange, because I still got AV and OoM when saving PDF to file sad As I wrote above it mostly depends from using DrawTitle()... Can it be fault of Delphi 2007 Architect?


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#9 2012-09-07 11:41:22

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Did you try the latest version - from http://synope.info/fossil - which use SynUnicode types in SQlite3Pages unit?

Could you step in debugger mode, or at least give a stack trace (including asm) of the exact AV error?

Since we were not able to reproduce the issue, it is very concerning...

Offline

#10 2012-09-25 16:53:43

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Please check the fix just included in the trunk.

See http://synopse.info/forum/viewtopic.php?pid=5164#p5164

I hope it will fix your issue.

Feedback is welcome!

Offline

#11 2012-10-12 14:22:15

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Thanks.I'll check that fix and let you know that helps or not wink


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

#12 2012-10-15 07:06:02

Wooya
Member
From: Poland
Registered: 2012-08-08
Posts: 8
Website

Re: "Access violation" or "Out of memory" during ExportPDF()

Latest fixes solves my problems with SynPDF. Thanks a lot! big_smile


Some Delphi, some SQL, some PHP, some JS, some HTML, some CSS wink

Offline

Board footer

Powered by FluxBB