Zazhir 0 Posted January 17, 2023 (edited) I have a form that has some buttons to export a qry result to differents files formats. I'am using a TSaveDialog, that is located in the main Form [frmMainSIG]. The component works just fine, but when I click in more than one button that export to file, gives a access violation message. Tried to "clear" the component create at my main form [frmMainSIG]. I've tried the `Free` method and the `FreeAndNil`, but they don't destroy my component. The code of export to pdf ⬇ var Excel: variant; caminho, caminhoFicha, pastaFicha, edtCaminhoRelatorio: string; linha: integer; begin try if not frmMainSIG.frmSIG.dlgFileSave.Execute then exit; caminho := ExtractFilePath(frmMainSIG.frmSIG.dlgFileSave.Name) + ExtractFileName(frmMainSIG.frmSIG.dlgFileSave.FileName); edtCaminhoRelatorio := caminho; ShowMessage('Ficaremos inativos até a geração completas dos dados!'); pastaFicha := 'Imovel'; frmSig.jvAlertaProgress.MessageText := 'Iniciado!'; frmSig.jvAlertaProgress.Execute; frmExportarImovel.progressBarQry.Max := frmImovel.qryPesq.RecordCount; frmImovel.qryPesq.First; linha := 4; Excel := CreateOleObject('Excel.Application'); Excel.Visible := false; Excel.Workbooks.open(frmMainSIG.frmSIG.caminhoFicha + pastaFicha + '\modeloImovelSelecao.xlsx'); while not (frmImovel.qryPesq.Eof) do begin atualizaTela; Excel.WorkBooks[1].Sheets[1].Range['B'+inttostr(Linha+1),'J'+inttostr(Linha+1)].RowHeight := 35; Excel.ActiveSheet.Range['B'+inttostr(Linha+1)+':J'+inttostr(linha+1)].Borders.LineStyle := 1; Excel.WorkBooks[1].Sheets[1].Range['B'+inttostr(Linha+1),'J'+inttostr(Linha+1)].NumberFormat := '@'; Excel.ActiveSheet.Cells[Linha+1,2] := frmImovel.qryPesq.FieldByName('IMOV_ID_CODPREF').asString; Excel.ActiveSheet.Cells[Linha+1,3] := frmImovel.qryPesq.FieldByName('IMOV_TX_PROPRIETARIO').asString; Excel.ActiveSheet.Cells[Linha+1,4] := frmImovel.qryPesq.FieldByName('IMOV_TX_LOGRADOURO').asString; Excel.ActiveSheet.Cells[Linha+1,5] := frmImovel.qryPesq.FieldByName('IMOV_NR_NUMERO_PREDIAL').asString; Excel.ActiveSheet.Cells[Linha+1,6] := frmImovel.qryPesq.FieldByName('IMOV_TX_TIPO_IMOVEL').asString; Excel.ActiveSheet.Cells[Linha+1,7] := frmImovel.qryPesq.FieldByName('IMOV_NR_QUADRA').asString; Excel.ActiveSheet.Cells[Linha+1,8] := frmImovel.qryPesq.FieldByName('IMOV_NR_PISCINA').asString; Excel.ActiveSheet.Cells[Linha+1,9] := frmImovel.qryPesq.FieldByName('IMOV_NR_AREA_CONSTRUIDA_PREF').asString; Excel.ActiveSheet.Cells[Linha+1,10] := frmImovel.qryPesq.FieldByName('IMOV_NR_AREA_GERAL_COM_DESC_BEIRAL').asString; frmImovel.qryPesq.Next; linha := linha + 1; sleep(100); end; sleep(100); Excel.ActiveWorkbook.saveas(edtCaminhoRelatorio + ' RELATORIO_SIGATI' + '.xlsx'); sleep(1000); Excel.ActiveWorkbook.Worksheets[1].ExportAsFixedFormat(0, edtCaminhoRelatorio + ' RELATORIO.pdf',0,-1,0); Excel.Workbooks[1].Close; Excel.Quit; Excel := Unassigned; ShowMessage('Relatório gerado com Sucesso! 😊'); frmSig.jvAlertaProgress.MessageText := 'O Relatório foi Gerado com Sucesso!'; frmSig.jvAlertaProgress.Execute; progressBarQry.Position := 0; lblProgresso.Caption := '0 de 0'; lblProgresso.Refresh; if Application.MessageBox('Deseja abrir o arquivo?', 'Opção', MB_YESNO+MB_ICONINFORMATION) = mrYes then begin ShellExecute(0, 'open', PCHAR(frmMainSIG.frmSIG.dlgFileSave.FileName + ' RELATORIO.pdf'), nil, nil, SW_SHOWNORMAL); FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); end; FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); except on E: Exception do begin ShowMessage(E.Message); end; end; end; and the code to export to csv (excel file) var Excel: Variant; Linha, i : Integer; mostrar : boolean; caminho, edtCaminhoRelatorio, nome, extensao, saveDir: string; saveCSV: TSaveDialog; f: TextFile; begin if not frmImovel.qryPesq.IsEmpty then begin if Application.MessageBox('Deseja acompanhar o Excel carregando as informações?', 'Opção',MB_YESNO+MB_ICONINFORMATION) = mrYes then begin mostrar := true; showMessage('Não clique no Excel até que o procedimento termine, isso interrompe o carregamento.'); end else begin mostrar := false; showMessage('O Excel está oculto gerando as informações. Clique em "OK" para continuar. O sistema ficará desabilitado até que termine.'); end; frmSig.jvAlertaProgress.MessageText := 'Iniciado!'; frmSig.jvAlertaProgress.Execute; frmExportarImovel.progressBarQry.Max := frmImovel.qryPesq.RecordCount; frmImovel.qryPesq.First; Excel := CreateOleObject('Excel.Application'); Excel.Workbooks.Add; Excel.Visible := mostrar; Linha := 1; for i := 0 to frmImovel.qryPesq.FieldCount - 1 do Excel.WorkBooks[1].Sheets[1].Cells[Linha,i+1] := frmImovel.qryPesq.Fields[i].DisplayName; Linha := 2; while not frmImovel.qryPesq.Eof do begin for i := 0 to frmImovel.qryPesq.FieldCount - 1 do Excel.WorkBooks[1].Sheets[1].Cells[Linha,i+1] := frmImovel.qryPesq.Fields[i].Text; frmImovel.qryPesq.Next; Linha:=Linha+1; atualizaTela; end; Excel.Visible := false; sleep(100); // Salvar como CSV saveCSV:= TSaveDialog.Create(Self); saveCSV.Title:= 'Salvar como CSV'; saveCSV.Filter:= 'Arquivo CSV|*.csv'; saveCSV.DefaultExt:= 'csv'; saveCSV.FilterIndex:= 1; if saveCSV.Execute then begin AssignFile(f, saveCSV.FileName); end; Excel.ActiveWorkbook.saveas(saveCSV.FileName); Excel.Workbooks[1].Close; Excel.Quit; Excel := Unassigned; showMessage('Arquivo CSV salvo com sucesso!'); frmSig.jvAlertaProgress.MessageText := 'O Relatório foi Gerado com Sucesso!'; frmSig.jvAlertaProgress.Execute; progressBarQry.Position := 0; lblProgresso.Caption := '0 de 0'; lblProgresso.Refresh; if Application.MessageBox('Deseja abrir o arquivo?', 'Opção', MB_YESNO+MB_ICONINFORMATION) = mrYes then begin ShellExecute(Handle, 'open', PChar(saveCSV.FileName), nil, nil, SW_SHOWNORMAL); FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); end; FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); end else showMessage('Tabela não possui dados para serem exportados!'); end; After a click in this buttons, what I need to do is to destroy the frmMainSIG.frmSIG.dlgFileSave, to when I click in another button, the component are clean and ready to use! The line that "breaks" my code, only after a already generate the first file, is the if not frmImovel.qryPesq.IsEmpty then (first line). How can I do that, because the FreeAndNil method is not working for this case 😞 Edited January 17, 2023 by Zazhir Share this post Link to post
Lajos Juhász 293 Posted January 17, 2023 12 minutes ago, Zazhir said: After a click in this buttons, what I need to do is to destroy the frmMainSIG.frmSIG.dlgFileSave, to when I click in another button, the component are clean and ready to use! The line that "breaks" my code, only after a already generate the first file, is the if not frmImovel.qryPesq.IsEmpty then (first line). How can I do that, because the FreeAndNil method is not working for this case 😞 Please define "the component are clean and ready to use". You can reuse the dialog component without freeing it. In this case your freeing it and set the reference to nil (freeandnil) then try to access a nil object reference. You cannot do that. Just remove FreeAndNil. In case you would like to use a fresh dialog object just use a local variable instead of a global one then you can free it at the end of the procedure/method wherever this code snippet was copied from. 1 Share this post Link to post
programmerdelphi2k 237 Posted January 18, 2023 confused code! try create your "Excel" just one time... out any procedure! for example, before any use in your unit. Then, when all end, just free it! Quote // your unit using Excel obj ... implementation var Excel :variant; ... // your code to use it // when needs open other file, just close old-file and open a new-file. if needs new actions, just clear your Excel object... etc... OnCreate from "Form" // or initialization section Excel := CreateOleObject('Excel.Application'); // avoid create it many times if not really necessary do it!!! OnDestroy from "Form" // or finalization section Excel.Quit; Excel := Unassigned; // or any other way to free it 1 Share this post Link to post
programmerdelphi2k 237 Posted January 18, 2023 6 hours ago, Zazhir said: if Application.MessageBox('Deseja abrir o arquivo?', 'Opção', MB_YESNO+MB_ICONINFORMATION) = mrYes then begin ShellExecute(Handle, 'open', PChar(saveCSV.FileName), nil, nil, SW_SHOWNORMAL); // try execute external command after conclude your code-actions... any error here, your FreeAndNil() can dont be executed at all. FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); end; try some like this: Quote try //... LOpenMyCSVFile := Application.MessageBox('Deseja abrir o arquivo?', 'Opção', MB_YESNO+MB_ICONINFORMATION) = mrYes; ... finally FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); end; / if LOpenMyCSVFile then ShellExecute(Handle, 'open', PChar(saveCSV.FileName), nil, nil, SW_SHOWNORMAL); 1 Share this post Link to post
Lajos Juhász 293 Posted January 18, 2023 1 hour ago, programmerdelphi2k said: FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); What a great suggestion to free a component from a form. That's a huge NO. If it's in a try ... finally it must be a local reference not a global one. programmerdelphi2k as others wrote please make sure that your reply brings something to the topic here the goal is to help and not to reply to every post. If a reference is freed in a code it should be local: var dlgFileSave: TSaveDialog; begin dlgFileSave:=TSaveDialog.create(nil); try ... finally dlgFileSave.Free; end; end; The code to save csv is almost how it should be, the problem there is that the wrong reference is freed. Instead of frmMainSIG.frmSIG.dlgFileSave the saveCSV should be freed. var Excel: Variant; Linha, i : Integer; mostrar : boolean; caminho, edtCaminhoRelatorio, nome, extensao, saveDir: string; saveCSV: TSaveDialog; f: TextFile; begin if not frmImovel.qryPesq.IsEmpty then begin if Application.MessageBox('Deseja acompanhar o Excel carregando as informações?', 'Opção',MB_YESNO+MB_ICONINFORMATION) = mrYes then begin mostrar := true; showMessage('Não clique no Excel até que o procedimento termine, isso interrompe o carregamento.'); end else begin mostrar := false; showMessage('O Excel está oculto gerando as informações. Clique em "OK" para continuar. O sistema ficará desabilitado até que termine.'); end; frmSig.jvAlertaProgress.MessageText := 'Iniciado!'; frmSig.jvAlertaProgress.Execute; frmExportarImovel.progressBarQry.Max := frmImovel.qryPesq.RecordCount; frmImovel.qryPesq.First; Excel := CreateOleObject('Excel.Application'); Excel.Workbooks.Add; Excel.Visible := mostrar; Linha := 1; for i := 0 to frmImovel.qryPesq.FieldCount - 1 do Excel.WorkBooks[1].Sheets[1].Cells[Linha,i+1] := frmImovel.qryPesq.Fields[i].DisplayName; Linha := 2; while not frmImovel.qryPesq.Eof do begin for i := 0 to frmImovel.qryPesq.FieldCount - 1 do Excel.WorkBooks[1].Sheets[1].Cells[Linha,i+1] := frmImovel.qryPesq.Fields[i].Text; frmImovel.qryPesq.Next; Linha:=Linha+1; atualizaTela; end; Excel.Visible := false; sleep(100); // Salvar como CSV saveCSV:= TSaveDialog.Create(nil); try saveCSV.Title:= 'Salvar como CSV'; saveCSV.Filter:= 'Arquivo CSV|*.csv'; saveCSV.DefaultExt:= 'csv'; saveCSV.FilterIndex:= 1; if saveCSV.Execute then begin AssignFile(f, saveCSV.FileName); end; Excel.ActiveWorkbook.saveas(saveCSV.FileName); Excel.Workbooks[1].Close; Excel.Quit; Excel := Unassigned; showMessage('Arquivo CSV salvo com sucesso!'); frmSig.jvAlertaProgress.MessageText := 'O Relatório foi Gerado com Sucesso!'; frmSig.jvAlertaProgress.Execute; progressBarQry.Position := 0; lblProgresso.Caption := '0 de 0'; lblProgresso.Refresh; if Application.MessageBox('Deseja abrir o arquivo?', 'Opção', MB_YESNO+MB_ICONINFORMATION) = mrYes then ShellExecute(Handle, 'open', PChar(saveCSV.FileName), nil, nil, SW_SHOWNORMAL); finaly saveCSV.Free; end; end else showMessage('Tabela não possui dados para serem exportados!'); end; 2 1 Share this post Link to post
Zazhir 0 Posted January 18, 2023 Thanks for the help everyone!! 😄 quick update here: I've solved the problem!! What I has to do is just create a new component in every button (belive that's not the more efficent way, but it is the more simple that I found). just like that: procedure TfrmExportarImovel.btnPdfClick(Sender: TObject); var Excel: variant; caminho, caminhoFicha, pastaFicha, edtCaminhoRelatorio: string; linha: integer; savePdf: TSaveDialog; //new component created begin try savePdf:= TSaveDialog.Create(Self); //using a fresh and new component if savePdf.Execute then //.... except on E: Exception do begin ShowMessage(E.Message); end; end; end; Have done this for all the buttons that i use to export. 😉 Share this post Link to post
Fr0sT.Brutal 900 Posted January 18, 2023 7 minutes ago, Zazhir said: I've solved the problem!! and now you have memory leak Share this post Link to post
programmerdelphi2k 237 Posted January 18, 2023 8 hours ago, Lajos Juhász said: FreeAndNil(frmMainSIG.frmSIG.dlgFileSave); this code it's not mine! I just say "where" put it... on "try-finally" as I said on first post, "CODE CONFUSED"!!! Share this post Link to post