[Lazarus] WriteLn back to the GUI

Sven Barth pascaldragon at googlemail.com
Thu Oct 24 09:46:29 CEST 2013


Am 23.10.2013 23:08, schrieb ListMember:
> On 2013-10-23 22:36, Sven Barth wrote:
>> I've attached my own version of EditText which I just adjusted. It 
>> works very similar to the original version I linked, but allows to 
>> use any TCustomEdit descendant (TMemo is one of them).
>>
>
> Thank you.
>
> But, I am still getting "exception class: 'External: SIGSEGV'" in here:
>
> function EditWrite(var F: TTextRec): Integer; far;
> begin
>   with F do
>   begin
>     BufPtr^[BufPos] := #0;
> PEditData(@F.UserData)^.Edit.SetSelTextBuf(PChar(BufPtr)); { <-- Here }
>     BufPos := 0;
>   end;
>   EditWrite := 0;
> end;
>
>>> But, why would I have to write 100+ lines of code just to capture the
>>> output of WriteLn.
>>>
>>> Plus, I keep getting segfaults when I close the application --something
>>> is calling InOutFunc when the app closes and still tries to write to a
>>> destroyed TMemo.
>>
>> You'll need to store the old value of "Output" and restore that 
>> before your form is destroyed.
>
> I tried it, but doesn't seem to work.
>
> Here is the exact code I am using your modified code:
>
> procedure TForm1.Button1Click(Sender: TObject);
> begin
>   try
>     AssignEdit(System.Input, Memo1);
>     Reset(System.Input);
>
>     AssignEdit(System.Output, Memo2);
>     Rewrite(System.Output);
>
>     try
>       DoPPExecute;
>     except
>       on E: Exception do begin
>         Sleep(0);
>       end;
>     end;
>   finally
>     //CloseFile(System.Input);
>     //CloseFile(System.Output);
>   end;
> end;
>
> Uncommenting the closefile() stuff doesn't make any difference.
Did you read (and understand) what I wrote? You need to "store the old 
value of "Output" and restore" it afterwards. This means for your button 
click event:

=== code begin ===

procedure TForm1.Button1Click(Sender: TObject);
var
   oldoutput, oldinput: TextFile;
begin
   oldinput := System.Input;
   oldoutput := System.Output;
   (* the assigns should be done before the try so that Input and Output 
have the correct values *)
   AssignEdit(System.Input, Memo1);
AssignEdit(System.Output, Memo2);
   try
     Reset(System.Input);
     Rewrite(System.Output);

     try
       DoPPExecute;
     except
       on E: Exception do begin
         Sleep(0);
       end;
     end;
   finally
     (* using CloseFile will ensure that all pending output is flushed *)
     CloseFile(System.Input);
     CloseFile(System.Output);
     System.Input := oldinput;
     System.Output := oldoutput;
   end;
end;

=== code end ===

This will work, I've tested it myself (though not with the compiler).
>
>>> I think I'll go with Leledumbo's solution --and yes, will alter the
>>> globals.pas in the compiler's source.
>>
>> Adding a callback to globals.pas will be the completely wrong way... 
>
> I hear you, loud and clear :)
>
> But, hearing you say that, doesn't mean I understand why it is so 
> --especially when it does not help me :)
>
> Could you please elaborate a little why it would the completely wrong 
> way?
"Writeln" is a procedure implemented by the compiler, but not in form of 
a function inside the compiler's source. If the compiler (in your case 
the compiler you compile the compiler with) encounters a "Writeln" it 
will parse its arguments and build up a more complex code sequence which 
will convert each argument to a string which is passed into the 
specified file ("Output" by default). So modifying "Writeln" inside the 
compiler's source that you use in your own program would only work for 
code that you'd compile with that compiler and then your callback 
function would be nonsense, because that callback would be at compile 
time and not at runtime.
>
> [this is from your other email in this thread]
>
>> Let's maybe get a few things straight first: what are you trying to 
>> achieve in the end? Do you want to capture FPC's output or do you 
>> want to redirect the console output of your own application?
>> If the first: Why don't you simply use the functionality of the OS to 
>> redirect the output to a file? Or do you start FPC from within your 
>> own application? In that case you could use the pipe mechanism of 
>> e.g. TProcess to capture the output (Lazarus does it the same way).
>
> Here is what I have done:
>
> I have copied all the stuff in the 'compiler' folder somewhere else 
> and altered the pp.lpi into pp.pas and made it part of my 
> DemoProject.lpi.
>
> I have renamed the main proc in pp.lpi to be DoPPExecute.
>
> It builds and compiles fine.
>
> It also runs, sort of fine.
>
> Except that, those WriteLn stuff doesn't because it's no more a 
> console app.
>
> This is the point I need to solve that WriteLn headache.
>
> Honestly, I was preapred for any other issue, but I never expected 
> WriteLn to such a sacred cow that I need to perform such elaborate 
> rituals to workaround it --even then it doesn't seem to work so far.
There aren't many issues, because the compiler is also compiled into the 
textmode IDE fp. Please note however that there might be memory leaks in 
case of compilation errors. Also you should take note that using a 
development version of the compiler (in this case 2.7.1) which is 
compiled by a release compiler with the release RTL (in this case 2.6.2 
I assume) *might* result in different results than if you compile the 
compiler with a 2.7.1 RTL. So I'd suggest you to completely build a 
2.7.1 compiler and than use that compiler together with its RTL to 
compile your own application which in turn uses the same compiler source.

And with that in mind I can also present you with another possible 
solution (though the text mode driver will do it's job correctly): the 
compiler unit "comphook" contains a few callbacks which are used by the 
textmode IDE to capture the compiler's output and a few further things. 
You can take a look at $fpc\ide\fpcompil.pas to see what you 
should/could do inside those callbacks (they are assigned at around line 
943).

Regards,
Sven




More information about the Lazarus mailing list