Recent

Author Topic: OpenDocument('Filename') - doesn't ?  (Read 779 times)

J-G

  • Hero Member
  • *****
  • Posts: 1209
OpenDocument('Filename') - doesn't ?
« on: July 11, 2026, 04:47:09 pm »
I've written many utilities that create .CSV files (usially called 'OutFile') and once the file has been [closed], I call 'OpenDocument(OutFile)' and this opens Excel (if not already open) and the file is shown.

That is until I used it in my latest project.  I've checked that I do have LCLIntf in the [Uses] (but I suspect that it wouldn't compile if that were not the case) -  and compared my current code with that in a previous project that does 'Open' the file.

Current Project :
Code: Pascal  [Select][+][-]
  1.  
  2.   OutFile := datapath+'Tri_Data '+IntToStr(TOS)+' '+Tri_Name[TT];
  3.   CreateCSVFile(OutFile,True);
  4.  [...]
  5.   System.close(CSVFile);
  6.   OpenDocument(OutFile);
  7.  

Old Project :
Code: Pascal  [Select][+][-]
  1.  
  2.    OutFile := ReportPath+'Banking-'+IntToStr(DataYear)+'.CSV';
  3.    SYSTEM.assign(CSVFile,OutFile);
  4.   reWrite(CSVFile);
  5.   [...]
  6.   SYSTEM.close(CSVFile);
  7.   OpenDocument(OutFile);
  8.  

As you can see there are minor differences but nothing that should affect the action - I've simply moved the Assign and reWrite to a common proc called 'Create' which adds a TimeStamp (making the name unique, thus avoiding a 'File Open' error) and the '.CSV' extension.

This came to my notice because I thought that I'd just not written the code to create the file but then saw that the file did in fact exist - The point about opening the file confirms that it has been successful  - although I could create a 'flag' to indicate such, it may be so shortlived that the user would miss it !

Can anyone suggest what I must be missing?
« Last Edit: July 11, 2026, 05:00:15 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

paweld

  • Hero Member
  • *****
  • Posts: 1696
Re: OpenDocument('Filename') - doesn't ?
« Reply #1 on: July 11, 2026, 05:07:48 pm »
You didn't include the file extension (csv) in the file name (the OutFile variable), and OpenDocument opens files using the default applications; if there is no extension, there is no default application.

And if the CreateCSVFile procedure modifies the file name, you should either convert it into a function and return the new file name as the output, or set the file name parameter to var so that the OutFole variable contains the new name after the procedure is executed.
Best regards / Pozdrawiam
paweld

J-G

  • Hero Member
  • *****
  • Posts: 1209
Re: OpenDocument('Filename') - doesn't ?
« Reply #2 on: July 11, 2026, 05:41:13 pm »
Your responce was probably written before my [Edit] which added the caviat that the 'Create' proc did in fact add the extension  BUT  -  you are correct in that I hadn't made it a 'var'  :-[

Oddly enough, the file that was written DID have the extenstion (along with the time stamp) - witness the screen grab attached.

Here's the 'Create' proc :  (as it is NOW)
Code: Pascal  [Select][+][-]
  1. procedure CreateCSVFile(Var FN : String;TS : Boolean);    // TS = 'Time-Stamped'
  2. Var
  3.   F : String;
  4.   x : byte;
  5. begin
  6.   if TS then
  7.     f := FN+TimeStamp+'.CSV'
  8.   else
  9.     f := FN+'.CSV';
  10.  
  11.   Assign(CSVFile,f);
  12.   {$I-} rewrite(CSVFile); {$I+}
  13.   X := IOResult;
  14.   if X <> 0 then  //IOResult <> 0 then
  15.     begin
  16.       showMessage('CSV File open. Close and retry');
  17.     end;
  18. end;
  19.  

It still has the check for a 'File Open' error though the chance of the TS not being unique is virtually impossible - - - - and the 'Debuging' X is still in place  -  neither of those should be relevant of course.

I have re-compiled and tested but Excel is still not being opened  %)

« Last Edit: July 11, 2026, 05:43:07 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

paweld

  • Hero Member
  • *****
  • Posts: 1696
Re: OpenDocument('Filename') - doesn't ?
« Reply #3 on: July 11, 2026, 05:52:31 pm »
The procedure is missing the assignment of the new path to a variable - modify it as shown below:
Code: Pascal  [Select][+][-]
  1.     procedure CreateCSVFile(Var FN : String;TS : Boolean);    // TS = 'Time-Stamped'
  2.     Var
  3.       F : String;
  4.       x : byte;
  5.     begin
  6.       if TS then
  7.         f := FN+TimeStamp+'.CSV'
  8.       else
  9.         f := FN+'.CSV';
  10.  
  11.       FN := f; // add this line
  12.      
  13.       Assign(CSVFile,f);
  14.       {$I-} rewrite(CSVFile); {$I+}
  15.       X := IOResult;
  16.       if X <> 0 then  //IOResult <> 0 then
  17.         begin
  18.           showMessage('CSV File open. Close and retry');
  19.         end;
  20.     end;
  21.      
Best regards / Pozdrawiam
paweld

J-G

  • Hero Member
  • *****
  • Posts: 1209
Re: OpenDocument('Filename') - doesn't ?
« Reply #4 on: July 11, 2026, 06:13:03 pm »
D'Oh!  -  sometimes I simply can't see the Wood for the Trees !! :-[

A marginally better solution (I think) would be to use the variable that I now have :

This is the cleaned up proc
Code: Pascal  [Select][+][-]
  1. procedure CreateCSVFile(Var FN : String;TS : Boolean);    // TS = 'Time-Stamped'
  2. begin
  3.   if TS then
  4.     FN := FN+TimeStamp+'.CSV'
  5.   else
  6.     FN := FN+'.CSV';
  7.  
  8.   Assign(CSVFile,FN);
  9.   {$I-} rewrite(CSVFile); {$I+}
  10.   if IOResult <> 0 then
  11.     showMessage('CSV File open. Close and retry');
  12. end;
  13.  

Now that FN is a Var, it can be correctly treated as such  -  and (more to the point)  IT WORKS !!

Thanks @paweld  -  another pair of eyes (without fore-knowledge) was what was needed  ;D
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zvoni

  • Hero Member
  • *****
  • Posts: 3466
Re: OpenDocument('Filename') - doesn't ?
« Reply #5 on: July 13, 2026, 09:02:52 am »
D'Oh!  -  sometimes I simply can't see the Wood for the Trees !! :-[

A marginally better solution (I think) would be to use the variable that I now have :

This is the cleaned up proc
Code: Pascal  [Select][+][-]
  1. procedure CreateCSVFile(Var FN : String;TS : Boolean);    // TS = 'Time-Stamped'
  2. begin
  3.   if TS then
  4.     FN := FN+TimeStamp+'.CSV'
  5.   else
  6.     FN := FN+'.CSV';
  7.  
  8.   Assign(CSVFile,FN);
  9.   {$I-} rewrite(CSVFile); {$I+}
  10.   if IOResult <> 0 then
  11.     showMessage('CSV File open. Close and retry');
  12. end;
  13.  

Now that FN is a Var, it can be correctly treated as such  -  and (more to the point)  IT WORKS !!

Thanks @paweld  -  another pair of eyes (without fore-knowledge) was what was needed  ;D

Nitpicking: I'd rather rewrite this Procedure as a Function, returning a Boolean True indicating Creating CSV was successful
The "var"-argument of the FileName stays as it is
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

J-G

  • Hero Member
  • *****
  • Posts: 1209
Re: OpenDocument('Filename') - doesn't ?
« Reply #6 on: July 13, 2026, 10:40:41 am »
Nitpicking: I'd rather rewrite this Procedure as a Function, returning a Boolean True indicating Creating CSV was successful
The "var"-argument of the FileName stays as it is
I appreciate the fact that you admit to 'Nitpicking' - and I am known as a 'pedant' so that is also one of my traits  %)

However, (just out of interest)  what would be the benefit ?

I think that I understand how to do such a conversion and assume that the user would still be presented with a dialogue detailing what action to take but I can't really see any 'benefit'.
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

cdbc

  • Hero Member
  • *****
  • Posts: 2923
    • http://www.cdbc.dk
Re: OpenDocument('Filename') - doesn't ?
« Reply #7 on: July 13, 2026, 12:16:51 pm »
Hi
With a function, you'd get the 'Success' / 'Failure' back as a boolean, while at the same time making the function widgetset-agnostic ~ GUI/TUI...
My 2 cent's worth:
Code: Pascal  [Select][+][-]
  1. function CreateCSVFile(Var FN : String;TS : Boolean): boolean;    // TS = 'Time-Stamped' | result = success
  2. begin
  3.   if TS then
  4.     FN := FN+TimeStamp+'.CSV'
  5.   else
  6.     FN := FN+'.CSV';
  7.  
  8.   Assign(CSVFile,FN);
  9.   {$I-} rewrite(CSVFile); {$I+}
  10.   Result:= (IOResult = 0);
  11.   if Result then begin
  12.     /// write your stuff here ///
  13.     system.Close(CSVFile);
  14.   end else system.Close(CSVFile);
  15. end;
  16.  

ex.:
Code: Pascal  [Select][+][-]
  1. if CreateCSVFile() then /// success
  2. else ShowMessage('Oouupppss -- CSV File open. Close and retry');
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Zvoni

  • Hero Member
  • *****
  • Posts: 3466
Re: OpenDocument('Filename') - doesn't ?
« Reply #8 on: July 13, 2026, 12:42:49 pm »
Hi
With a function, you'd get the 'Success' / 'Failure' back as a boolean, while at the same time making the function widgetset-agnostic ~ GUI/TUI...
My 2 cent's worth:
Code: Pascal  [Select][+][-]
  1. function CreateCSVFile(Var FN : String;TS : Boolean): boolean;    // TS = 'Time-Stamped' | result = success
  2. begin
  3.   if TS then
  4.     FN := FN+TimeStamp+'.CSV'
  5.   else
  6.     FN := FN+'.CSV';
  7.  
  8.   Assign(CSVFile,FN);
  9.   {$I-} rewrite(CSVFile); {$I+}
  10.   Result:= (IOResult = 0);
  11.   if Result then begin
  12.     /// write your stuff here ///
  13.     system.Close(CSVFile);
  14.   end else system.Close(CSVFile);
  15. end;
  16.  

ex.:
Code: Pascal  [Select][+][-]
  1. if CreateCSVFile() then /// success
  2. else ShowMessage('Oouupppss -- CSV File open. Close and retry');
Regards Benny

Exactly because of that.
The ShowMessage is a "hard interrupt" of the flow of code.
+1 cdbc
If i have code, that might or might not fail i usually put it in a function returning Success/Failure-Indicator, because IMO it's the callers task to "interpret" the result.
That way you can handle any "Messages" (whichever they are) "gracefully" without interrupting the User in a hard way.

In your version as a procedure with the ShowMessage inside it:
The moment the User clicks "OK" of the Showmessage, code-execution continues, in your case it continues from the point the procedure was called,
maybe producing unintended effects

Well, except it's the way you want to do it. Your Program, your Call.

oh, and cdbc: You have duplicate code..  :D :D :D

adjusted (though untested)
Code: Pascal  [Select][+][-]
  1. function CreateCSVFile(Var FN : String;TS : Boolean): boolean;    // TS = 'Time-Stamped' | result = success
  2. begin
  3.   Result:=False;  //I like to initialize Result explicitely, though i'm aware, Boolean defaults to 0/False
  4.   if TS then
  5.     FN := FN+TimeStamp+'.CSV'
  6.   else
  7.     FN := FN+'.CSV';
  8.  
  9.   Assign(CSVFile,FN);
  10.   {$I-} rewrite(CSVFile); {$I+}
  11.   Result:= (IOResult = 0);
  12.   if Result then begin
  13.     /// write your stuff here ///    
  14.   end;
  15.   system.Close(CSVFile);
  16. end;
« Last Edit: July 13, 2026, 12:49:42 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

cdbc

  • Hero Member
  • *****
  • Posts: 2923
    • http://www.cdbc.dk
Re: OpenDocument('Filename') - doesn't ?
« Reply #9 on: July 13, 2026, 02:03:52 pm »
Hi
Yeah, I threw that in for good measure, can't remember these ol' mechanics that well...  :D
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Zvoni

  • Hero Member
  • *****
  • Posts: 3466
Re: OpenDocument('Filename') - doesn't ?
« Reply #10 on: July 13, 2026, 02:17:13 pm »
However, (just out of interest)  what would be the benefit ?

Extending my answer above a bit.

Imagine the following:
In your code, that CALLS the Function, you could basically implement it as a kind of "endless" loop.
1) Enter Loop
2) call the function to create the CSV
3a) If Function-Result=Success then break the loop
3b) If Function-Result = Failure, notify User, maybe even offering a CHOICE to use a different filename, a different location, close Excel to "free" the filelock, or cancel the whole operation (in which case you break the loop), whatever
4) Goto 1)

Instead of a Boolean-Result, you could even return the IOResult directly, though i admit, i'm not familiar with its values.
I'd hazard a guess, there is a difference in IOResult, say between "File is Open in Excel" and "File is write protected"
in that case you can notify the User, what the "Problem" is exactly ("Close the damn File which is probably open in Excel" vs. "someone put the writeprotected bit on it. Clean up the Mess")
« Last Edit: July 13, 2026, 02:22:19 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

J-G

  • Hero Member
  • *****
  • Posts: 1209
Re: OpenDocument('Filename') - doesn't ?
« Reply #11 on: July 13, 2026, 03:02:56 pm »
Hmmmm - - -   I suspect that you (both) have mis-understood what the Proc is intended to do.

I often wish to create .CSV files for very disparate data but ALL will need the CSV File to be created. You have both added into to the 'Create' Proc a section to 'Write' data to it - ie.
Code: Pascal  [Select][+][-]
  1.  
  2. if Result then begin
  3.     /// write your stuff here ///
  4.     system.Close(CSVFile);
  5.   end
  6.  
That defeats my object.  The amount of processing of data needed at  /// write your stuff here /// could well be 10 or 1000 lines - and be very different for each application.  In this project there is actually only one needed but in other projects I have many different potential files.

I considered setting up a 'generic' 'Create File' proc to be a benefit over writing an 'Open File' for each different need.

The issue about "hard interrupt" had not occured to me and I'm still not sure what negative effect it might have - in my 'use' pattern.  The effect that I see is that the user is alerted to the fact that a file with the same name is already 'Open' - which they may well have totally forgotten -  so they simply close it and request a new one; or they may use the data that is already known. Either way, it's no great issue.

As I've said previously, using a Time-stamp is a means by which duplicate file-names can be automatically avoided, but there are occasions when that is more cumbersome.

I am aware that there are newer ways of creating/opening files without resorting to the {$I-} {$I+} system but - as with getting from A to B - the best route is the one that you already know well  ;D

I've just received your extended response @Zvoni but I hope that my further explanation of my thinking makes that less relevant - I'll agree that the 'failure' may not be due to the file actually being open in Excel; but that has been the case in practice - and yes I do have knowledge of the IOResult return codes  - I go back far enough to have a list, my 'Go To' Reference is the Turbo Pascal 4 Manual  ::)

« Last Edit: July 13, 2026, 03:06:49 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

Zvoni

  • Hero Member
  • *****
  • Posts: 3466
Re: OpenDocument('Filename') - doesn't ?
« Reply #12 on: July 13, 2026, 04:00:06 pm »
Hmmmm - - -   I suspect that you (both) have mis-understood what the Proc is intended to do.

I often wish to create .CSV files for very disparate data but ALL will need the CSV File to be created. You have both added into to the 'Create' Proc a section to 'Write' data to it - ie.
Code: Pascal  [Select][+][-]
  1.  
  2. if Result then begin
  3.     /// write your stuff here ///
  4.     system.Close(CSVFile);
  5.   end
  6.  
That defeats my object.  The amount of processing of data needed at  /// write your stuff here /// could well be 10 or 1000 lines - and be very different for each application.  In this project there is actually only one needed but in other projects I have many different potential files.

I considered setting up a 'generic' 'Create File' proc to be a benefit over writing an 'Open File' for each different need.

The issue about "hard interrupt" had not occured to me and I'm still not sure what negative effect it might have - in my 'use' pattern.  The effect that I see is that the user is alerted to the fact that a file with the same name is already 'Open' - which they may well have totally forgotten -  so they simply close it and request a new one; or they may use the data that is already known. Either way, it's no great issue.

As I've said previously, using a Time-stamp is a means by which duplicate file-names can be automatically avoided, but there are occasions when that is more cumbersome.

I am aware that there are newer ways of creating/opening files without resorting to the {$I-} {$I+} system but - as with getting from A to B - the best route is the one that you already know well  ;D

I've just received your extended response @Zvoni but I hope that my further explanation of my thinking makes that less relevant - I'll agree that the 'failure' may not be due to the file actually being open in Excel; but that has been the case in practice - and yes I do have knowledge of the IOResult return codes  - I go back far enough to have a list, my 'Go To' Reference is the Turbo Pascal 4 Manual  ::)
No worries.
As i said: It's your Program, it's your call. And if you are familiar with it, all the better.

It's just, that for me (and in that way IMO), such a ShowMessage inside a Procedure call, is like in OO-Programming the age-old discussion "a Child should never update the parent":
In your particular case, the CALLING code would be the parent, your Procedure the child.
Because in any way you look at it: Irrespective of the "Result" of your Procedure, Code-Execution WILL RETURN to the calling code and continue there.
Why did i nitpick on this?
The one thing giving it away for me is your "FN"-Proc-Argument, which you return to the caller (it's "var"), which to me implies you want to do something with it after its (potential) transformation!
And this is what i meant with "unintended effects" that can happen (though i don't know your code), when (not If) the code returns to the caller.
You pass the FileName, your Procedure transforms it, but it fails to create the CSV, for whatever reason (Already, open, Writeprotected file, writeprotected Folder!)
Your Proc tells the User "OOPPS" (The ShowMessage) and then returns to the Caller, shipping the (transformed) FileName back!
The Moment your execution returns to the calling code, the calling code doesn't know about the Error anymore (well, except if you use some "global" variable, but....that....honestly....brrrrr)

It's what i learned about "defensive" programming: put code that might fail into a function, returning a "state" (Try/Finally/Except not withstanding inside such a Function), but it's always the CALLER's duty to "judge" the Result

as to your argument, you might have 10 lines of code or 1000 LoC in that "//write stuff here"-Part, is a non-argument, because it comes AFTER the potential Error, which means you can happily "outsource" those 1000 Lines of Code to another Procedure again.
In a nutshell for such an approach: You would need a "generic" interface for such a Procedure, meaning: the Argument-In and optional Argument-out should be the same for all needed "variants"

As i said: Your Program, your Call.
Just different "philosophies" if you want...  ;D
« Last Edit: July 13, 2026, 04:12:14 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

cdbc

  • Hero Member
  • *****
  • Posts: 2923
    • http://www.cdbc.dk
Re: OpenDocument('Filename') - doesn't ?
« Reply #13 on: July 13, 2026, 04:32:04 pm »
Hi
I'm a bit bored in the heat, so how about:
Code: Pascal  [Select][+][-]
  1. type
  2.   TCSVWriter = procedure(aSender: TObject; aFilename: string; aFilehandle: system.text) of object;
  3.   ...
  4. function CreateCSVFile(Var FN : String;TS : Boolean; aWriter: TCSVWriter = nil): boolean;    // TS = 'Time-Stamped' | result = success
  5. begin
  6.   Result:=False;  //I like to initialize Result explicitely, though i'm aware, Boolean defaults to 0/False
  7.   if TS then
  8.     FN := FN+TimeStamp+'.CSV'
  9.   else
  10.     FN := FN+'.CSV';
  11.  
  12.   Assign(CSVFile,FN);
  13.   {$I-} rewrite(CSVFile); {$I+}
  14.   Result:= (IOResult = 0);
  15.   if Result then begin
  16.     if aWriter <> nil then aWriter(nil,FN,CSVFile);    
  17.   end;
  18.   system.Close(CSVFile);
  19. end;
Regards Benny

edit: I forgot midway, that is was a function, _not_ a method I was writing  :D
« Last Edit: July 13, 2026, 04:34:08 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

J-G

  • Hero Member
  • *****
  • Posts: 1209
Re: OpenDocument('Filename') - doesn't ?
« Reply #14 on: July 13, 2026, 05:23:26 pm »
The phrase "teaching old dogs new tricks" comes to mind here  :D

The vast majority of my learning to write Pascal goes way back to 1980 - I can't now recall which version of Turbo Pascal I first used but it was a revalation after the Nascom Basic that came with the Nascom II that I bought on June 1st that year !   I also had a short period learning COBOL so the 'readabilty' factor of Pascal was a strong influence, - - -  and I've never looked a C (in any guise) or LISP etc.

At the time (1980) I owned a Hardware/DIY shop and I wrote a 'Point of Sale' system as a 'till' - quite facinating my then Bank Manager who used to visit 'just to find out how it was working'. ie. well before the high street in general had POS systems.

Consequently my mind-set is probably fixated on methods which 'worked' - it's also why I still prefer the "if IOResult . . . " concept.

I've just looked at one of the first GUI programs I wrote when I came across Lazarus and see that I wrote the 'Create a CSV file' 9 separate times!  Being a firm beleiver in 'Code Reuse' I've written many re-usable routines that I simply pull into any new project  -  and Yes, I have created a 'Unit' to handle Date & Time functions but having had a few years off from programming I haven't progressed much further in that respect.  This 'CreateCSVFile' is just one of them.

@Zvoni  -  My argument about 10 or 1000 lines IS relevant because if the writing of data to the CSVFile is included in the 'Create' Proc then it is no longer a generic Proc.

It's always interesting to hear about other programmer's methodologies and I've certainly learned a great deal from discussions on this forum - though much of the information about the 'inner workings' of FPC & Lazarus do befuddle this old brain  %)
« Last Edit: July 13, 2026, 05:46:52 pm by J-G »
FPC 3.0.0 - Lazarus 1.6 &
FPC 3.2.2  - Lazarus 2.2.0 
Win 7 Ult 64

 

TinyPortal © 2005-2018