Recent

Author Topic: Issue with Win32 TSaveDialog.DefaultExt  (Read 7231 times)

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #15 on: August 19, 2023, 01:27:45 pm »
I factored out all the logic of appending DefaultExt into a plain fpc program.
Code: Pascal  [Select][+][-]
  1. program test;
  2. {$mode objfpc}
  3. {$H+}
  4.  
  5. uses
  6.   sysutils;
  7.  
  8. const
  9.  
  10.   Filter = 'YAML|*.yml;*.yaml|All files|*';
  11.  
  12. var
  13.   FilterIndex: Integer;
  14.   DefaultExt: String = 'yml';
  15.  
  16.  
  17. procedure SetDefaultExt(var AValue: string);
  18. begin
  19.   if (AVAlue<>'') and (AValue[1]<>'.') then
  20.     AValue:='.'+AValue;
  21. end;
  22.  
  23.  
  24. function ExtractFilterValues(const Filter: String): TStringArray;
  25. var
  26.   Arr: TStringArray;
  27.   i: Integer;
  28. begin
  29.   Result := nil;
  30.   Arr := Filter.Split('|'{$if fpc_fullversion >= 30202}, TStringSplitOptions.ExcludeLastEmpty{$endif});
  31.   SetLength(Result, Length(Arr) div 2);
  32.   for i := Low(Arr) to High(Arr) do
  33.   begin
  34.     if Odd(i) then Result[i div 2] := Arr[i];
  35.   end;
  36. end;
  37.  
  38. function GetExtensionFromFilterAtIndex(const Filter: String; Index: Integer): String;
  39. {
  40.   Returns a file extension from a filter as used in TOpen/TSaveDialog
  41.   - it will return the extension (including the leading period) that matches the index (index starts at 1)
  42.   - it will return an empty string if the extension contains a wildcard, or on any failure
  43.   - filters have the format of:
  44.     'Text files (*.txt)|*.txt|'+
  45.     'Pascal files (*.pp;*.pas)|*.pp;*.pas|'+
  46.     'All files (*.*)|*.*'
  47.   - if a given extension is a composite (like '*.pp;*.pas') it will return the first one from the list
  48. }
  49. var
  50.   i: Integer;
  51.   FilterArr, CurrFilterArr: TStringArray;
  52.   CurrFilter, S: String;
  53. begin
  54.   Result := '';
  55.   if Index < 1 then
  56.     Exit;
  57.   FilterArr := ExtractFilterValues(Filter);
  58.   Dec(Index); //adjust for zero-base FilterArr;
  59.   if Index > High(FilterArr) then
  60.     Exit;
  61.   CurrFilter := FilterArr[Index];
  62.   CurrFilterArr := CurrFilter.Split(';'{$if fpc_fullversion >= 30202}, TStringSplitOptions.ExcludeLastEmpty{$endif});
  63.   for i := Low(CurrFilterArr) to High(CurrFilterArr) do
  64.   begin
  65.     S := ExtractFileExt(CurrFilterArr[i]);
  66.     //if S is something like '*.p?;*.pas;' return the first one without a wildcard in the extension: e.g. '.pas'
  67.     if (Pos('?',S) = 0) and (Pos('*',S) = 0) then
  68.       Exit(S);
  69.   end;
  70. end;
  71.  
  72. function FileExists(S: String): Boolean; begin result:=false;end;
  73.  
  74. function CheckFile(var AFilename: string): boolean;
  75. var
  76.   Dir, Ext: string;
  77. begin
  78.   Result:=true;
  79.   if (DefaultExt<>'') and (ExtractFileExt(AFilename)='')
  80.   and (not FileExists(AFilename)) then begin
  81.     Ext := GetExtensionFromFilterAtIndex(Filter, FilterIndex);
  82.     if (Length(Ext) > 0) then
  83.       AFileName := AFileName + Ext
  84.     else
  85.       AFilename:=AFilename+DefaultExt;
  86.   end;
  87.   //ofOverwritePrompt -> is done in the interface
  88.   {
  89.   if (ofPathMustExist in Options)
  90.   and (not DirPathExists(ExtractFileDir(AFilename))) then begin
  91.     Result:=false;
  92.     MessageDlg(rsfdPathMustExist,
  93.                Format(rsfdPathNoExist,[ExtractFileDir(AFilename)]),
  94.                mtError,[mbCancel],0);
  95.     exit;
  96.   end;
  97.   if (ofFileMustExist in Options)
  98.   and (not CheckFileMustExist(AFileName)) then begin
  99.     // CheckFileMustExists shows message dialog
  100.     Result:=false;
  101.     exit;
  102.   end;
  103.   if ofNoReadOnlyReturn in Options then begin
  104.     if FileExistsUTF8(AFilename) then
  105.       Result := FileIsWritable(AFilename)
  106.     else begin { File does not exist - check directory }
  107.       Dir := ExtractFileDir(AFilename);
  108.       if Dir = '' then
  109.         Dir := '.';
  110.       Result := DirectoryIsWritable(Dir);
  111.     end;
  112.     if not Result then begin
  113.         MessageDlg(rsfdFileReadOnlyTitle,
  114.                    Format(rsfdFileReadOnly,[AFileName]),
  115.                    mtError,[mbCancel],0);
  116.         exit;
  117.     end;
  118.   end;
  119.   }
  120. end;
  121.  
  122. procedure CheckResult(Orig, Exp, Found: String; AFilterIndex: Integer);
  123. begin
  124.   write(format('Fn as input: %-8s, FilterIndex: %d. Result: Fn = %s',[Orig, AFilterIndex, Found]));
  125.   if (Exp = Found) then
  126.     writeln(' -> OK')
  127.   else
  128.     writeln(' -> FAIL: expected ',Exp);
  129. end;
  130.  
  131. var
  132.   Fn: String;
  133.  
  134. begin
  135.   SetDefaultExt(DefaultExt);
  136.   writeln('DefaultExt = "',DefaultExt,'"');
  137.   writeln('Filter = "',Filter,'"');
  138.  
  139.   Fn := 'foo';
  140.   FilterIndex := 1;
  141.   CheckFile(Fn);
  142.   CheckResult('foo','foo.yml', Fn, 1);
  143.  
  144.   Fn := 'foo.lua';
  145.   FilterIndex := 1;
  146.   CheckFile(Fn);
  147.   CheckResult('foo.lua','foo.lua', Fn, 1);
  148.  
  149.   Fn := 'foo';
  150.   FilterIndex := 2;
  151.   CheckFile(Fn);
  152.   CheckResult('foo','foo.yml', Fn, 2);
  153.  
  154.   Fn := 'foo.lua';
  155.   FilterIndex := 2;
  156.   CheckFile(Fn);
  157.   CheckResult('foo.lua','foo.lua', Fn, 2);
  158. end.

This outputs for me with 3.2.2:
Code: [Select]
C:\Users\Bart\LazarusProjecten\ConsoleProjecten>test
DefaultExt = ".yml"
Filter = "YAML|*.yml;*.yaml|All files|*"
Fn as input: foo     , FilterIndex: 1. Result: Fn = foo.yml -> OK
Fn as input: foo.lua , FilterIndex: 1. Result: Fn = foo.lua -> OK
Fn as input: foo     , FilterIndex: 2. Result: Fn = foo.yml -> OK
Fn as input: foo.lua , FilterIndex: 2. Result: Fn = foo.lua -> OK

And the same with fpc main of today.

Bart
« Last Edit: August 19, 2023, 01:39:36 pm by Bart »

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #16 on: August 19, 2023, 01:49:24 pm »
My conclusion is that the fualt is not in the logic that appends DefaulttExt.

So, now we need to check what the AFilename parameter of CheckFile contains in the scenario where it goes wrong (filter = '*' and typing 'n.lua' in dialog).

Also, we need to examine if this only happens with Vista dialogs.

Bart

wp

  • Hero Member
  • *****
  • Posts: 12772
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #17 on: August 19, 2023, 02:59:23 pm »
Tried to bisect the commits for the guilty revision and found one where the buggy behaviour changed. Its commit note, however, looked rather innocent (changes in IDE only). So, when I later revisited the same commit, the issue was suddenly gone. And when I restore today's main I cannot reproduce the issue again. Very strange...

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #18 on: August 19, 2023, 06:18:36 pm »
@wp: since you at least sometimes can reproduce the item, can you inspect what the AFilename param is in CheckFile.
If it is alread wrong there, it might be Windows itself (we supply the DefaultExt tot the IFileDialog interface), which means nothing we can do about that (except for creating a workaround).

And when you can reproduce can you see if it happens also if VistDialogs are disabled?
(Just make CanUseVistaDialogs return False always, either by hacking it or setting the DisableVistaDialogs define.)

It would be nice if Alexey himself would do this, as he seems to be able to reproduce consistently...

Bart
« Last Edit: August 19, 2023, 06:42:45 pm by Bart »

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #19 on: August 19, 2023, 07:05:17 pm »
Reproduced it:
Typed: abacadabra -> abacadabra.pp
Typed: abacadabra.txt -> abacadabra.txt
Typed: abacadabra.lua -> abacadabra.lua.pp

It happens for non-registered extension it seems.
Also the AFilename parameter passed to CheckFile already has the erroneous extension.

And it does not happen with non-Vista dialogs.

So, it's Windows that does it to us.

Notice that setting ofExtensionDifferent in Vista dialog does the exact opposite of what it is meant to do: it enforces that the extension is in facgt on of the extensions in the filter or DefaultExt.

Bart

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #20 on: August 19, 2023, 07:24:07 pm »
Notice that setting ofExtensionDifferent in Vista dialog does the exact opposite of what it is meant to do: it enforces that the extension is in facgt on of the extensions in the filter or DefaultExt.

From the MS Docs:
FOS_STRICTFILETYPES
Quote
In the Save dialog, only allow the user to choose a file that has one of the file name extensions specified through IFileDialog::SetFileTypes.

From TWin32WSOpenDialog.GetVistaOptions:
Code: Pascal  [Select][+][-]
  1. if ofExtensionDifferent in Options then Result := Result or FOS_STRICTFILETYPES;

We seem to have the logic reversed.
And, if I understand the MS docs correclty: this setting does not apply to TOpenDialog, yet we apply it anyway.

Bart

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #21 on: August 19, 2023, 08:35:15 pm »
We seem to have the logic reversed.
Fixed that  in commit ed3e2610.

And, if I understand the MS docs correclty: this setting does not apply to TOpenDialog, yet we apply it anyway.

There is a ToDo in TWin32WSOpenDialog.ProcessVistaDialogResult about ofExtensionDifferent.
It seems Vista always enforces the behaviour of FOS_STRICTFILETYPES for OpenDialog??

Behavious after commit ed3e2610:

All tests with Filter=Pascal|*.pas;*.pp;*.p|All files|*

OpenDialog: (ofExtensionDifferent in Options)=TRUE:
Code: [Select]
FilterIndex=1

Typed: x
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pp"

Typed: x.txt
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt"

Typed: x.lua
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pp"


FilterIndex=2

Typed: x
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pp"

Typed: x.txt
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt"

Typed: x.lua
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pp"


OpenDialog: (ofExtensionDifferent in Options)=FALSE:
Code: [Select]
OpenDialog1.FilterIndex=1

Typed: x
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pp"

Typed: x.txt
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt.pp"

Typed: x.lua
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pp"

OpenDialog1.FilterIndex=2

Typed: x
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pp"

Typed: x.txt
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt.pp"

Typed: x.lua
OpenDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pp"

SaveDialog: (ofExtensionDifferent in Options)=TRUE:
Code: [Select]
FilterIndex=1

Typed: x
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pas"

Typed: x.txt
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt"

Typed: x.lua
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pas"


FilterIndex=2
Typed: x
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x"

Typed: x.txt
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt"

Typed: x.lua
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua"

SaveDialog: (ofExtensionDifferent in Options)=FALSE:
Code: [Select]
FilterIndex = 1

Typed: x
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.pas"

Typed: x.txt
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt.pas"

Typed: x.lua
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua.pas"



FilterIndex=2

Typed: x
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x"

Typed: x.txt
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.txt"

Typed: x.lua
SaveDialog1.FileName="C:\Users\Bart\LazarusProjecten\x.lua"

This seems to resolve the original issue with TSaveDialog?

OpenDialog with ofExtensionDifferent:
- adds DefaultExt if no extension is given
- allows any registered extension
- if not registered extension adds DefaultExt

OpenDialog without ofExtensionDifferent:
- adds DefaultExt unless extension in selected filterlist (and treats '*' as not having an extension)

SaveDialog with ofExtensionDifferent:
- adds first extension from current selected filter if no extension given (x -> x.pas, not x.pp; and if filter = '*', treats it as no extension, so adds no extension)
- allows registered extension that is not in current selected filter
- also adds first extension from current selected filter, if extension is not in that filter (and treats '*' different than in the above cases)

SaveDialog without ofExtensionDifferent:
- adds first extension from current selected filter if extension is not in the curent selected filter
- allows anything if current selected filter = '*'


Bart

wp

  • Hero Member
  • *****
  • Posts: 12772
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #22 on: August 19, 2023, 11:00:00 pm »
Maybe I don't understand, but it is not working as I'd expect.

I often use the "All files" filter to see all files in the list. I understand the DefaultExt as the extension to be added if I don't type an extension. But when I do type an extension it should be used and the DefaultExt should not be added.

I want to test this in AlexTP's project, modified as follows:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   SaveDialog1.InitialDir:= ExtractFileDir(Application.ExeName);
  4.   SaveDialog1.Options:= [ofOverwritePrompt,ofPathMustExist,ofEnableSizing,ofDontAddToRecent,ofViewDetail];
  5.   SaveDialog1.Filter:= 'All files|*.*|YAML|*.yml;*.yaml|Pas files|*.pas';
  6.   SaveDialog1.FilterIndex := 1;  // all files
  7.   SaveDialog1.DefaultExt:= 'yml';
  8.   SaveDialog1.FileName:= '';
  9.   if SaveDialog1.Execute then
  10.     caption:= 'chosen: '+ExtractFileName(SaveDialog1.FileName)
  11.   else
  12.     caption:= 'cancel';
  13. end;
I type "unit.pas" in the edit box. I'd expect the filename to remain unchanged, but the dialog always adds the .yml extension making the filename a "unit.pas.yml" - in fact, there is no way for me to keep "unit.pas", whatever I do:
- Change all files mask to '*.*' or '*' or '*.*;*' or '*;*.*'
- Add or remove ofExtensionDifferent.

This was tested on Win11, Laz/main (most current revision) + FPC 3.2.2. Cannot test with FPC/main - this comibination does not build ATM.

EDIT
Sorry - I had added/removed ofExtensionDifferent in the Object Inspector, but this was overridden by the Button Onclick code. Now it works like you describe. BUT: All my applications (and probably those of many users) assume that an extension typed will be respected - i.e. ofExtensionDifferent must be set by default now.
       
« Last Edit: August 19, 2023, 11:21:44 pm by wp »

wp

  • Hero Member
  • *****
  • Posts: 12772
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #23 on: August 19, 2023, 11:05:40 pm »
It happens for non-registered extension it seems.
What is a "non-registered extension"? An extension which is not associated with a file type in the Registry? In this case I'd have a problem: I never "register" the .pas extension because i have two delphi and several Lazarus versions on my disk and i don't want to open any of them after a double-click on a pas file because it will not be the version that I need. But when I save a file and type a .pas extension I want the file to be saved like this no matter what the filter settings of the file dialog are.

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #24 on: August 20, 2023, 01:26:48 pm »
Well, AFAICT it is Windows itself that adds the DefaultExt.
I did not test what happens when DefaultExt is empty.

Lazarus logic is simple: if DefaultExt is not empty and the filename returned has no extension:
- add the first valid extension of that filter.
- if the current filter does not have a valid extension: adds DefaultExt

So, if you set DefaultExt to empty string, Lazarus won't add anything by itself.
Windows will however apply a valid extension from the current selected filter, wether or not ofExtensionDifferent is set (I checked the result in TWin32WSOpenDialog.ProcessVistaDialogResult), where we simply query the IFileDialog for it's Filename(s).

(It's an annoying feature that also makes that you cannot by default save something in Notepad with anything other than a .txt extension, unless you select the All files filter in the save dialog)

I don't think we can change that.

I hope that current behaviour is compatible with Delphi.

Bart
« Last Edit: August 21, 2023, 11:24:56 pm by Bart »

wp

  • Hero Member
  • *****
  • Posts: 12772
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #25 on: August 21, 2023, 12:21:19 am »
OMG - I think I will not be able to remember this...

I wrote a small test project - maybe you have similar one - which varies the parameters for the TOpenDialog and the TSaveDialog interactively and displays the generated filename. I compiled it with Laz/main, Laz 2.2.6 and with Delphi XE11.3 Community Edition (the application compiles with Delphi 7 as well, however, delivers different results).

I did not check all of the parameter combinations (there might be thousands of them...). Here is just an excerpt of my (incomplete) analysis file(included in the attached zip)  comparing the case "DefaultExt=pas; FilterIndex for "all files" with mask "*.*", with/without option ExtensionDifferent" for the SaveDialog:

Code: [Select]
--------------------------------------------------------------------------------
DEFAULT EXTENSION 'pas', all files (*.*)
--------------------------------------------------------------------------------
TSaveDialog; all files mask='*.*'; DefaultExt='pas'; FilterIndex=1; ExtensionDifferent = False

                                    Laz/main        Laz 2.2.6       Delphi
                                    ------------    -------------   ------------
  Test #1: FileName=test       -->  'test.pas'      'test.pas'      'test.pas'
  Test #2: FileName=test.pas   -->  'test.pas'      'test.pas'      'test.pas'
  Test #3: FileName=test.pp    -->  'test.pp.pas'   'test.pp'       'test.pp'
  Test #4: FileName=test.yml   -->  'test.yml.pas'  'test.yml'      'test.yml'
  Test #5: FileName=test.abc   -->  'test.abc.pas'  'test.abc'      'test.abc'
 
TSaveDialog; all files mask='*.*'; DefaultExt='pas'; FilterIndex=1; ExtensionDifferent = True

                                    Laz/main        Laz 2.2.6       Delphi
                                    ------------    -------------   ------------
  Test #1: FileName=test       -->  'test.pas'      'test.pas'      'test.pas'   
  Test #2: FileName=test.pas   -->  'test.pas'      'test.pas'      'test.pas'   
  Test #3: FileName=test.pp    -->  'test.pp'       'test.pp.pas'   'test.pp.pas'
  Test #4: FileName=test.yml   -->  'test.yml'      'test.yml.pas'  'test.yml.pas'
  Test #5: FileName=test.abc   -->  'test.abc'      'test.abc.pas'  'test.abc.pas'
As you can see, the result for Laz 2.2.6 and Delphi are in agreement. But the current main version gets the same results only when the ExtensionDifferent is flipped - well, exactly what you did.

But since Laz/main breaks here compatibility with prior versions and with Delphi, I think this change should be reverted.

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #26 on: August 21, 2023, 02:51:24 pm »
But since Laz/main breaks here compatibility with prior versions and with Delphi, I think this change should be reverted.

I strongly disagree.

Read the documentation of MS on FOS_STRICTFILETYPES: "In the Save dialog, only allow the user to choose a file that has one of the file name extensions specified through IFileDialog::SetFileTypes."
So, this option restricts extensions to be only one of the extensions in the Filter or DfeaultExt property. It restricts the user form typing a filename that he/she wants.

Delphi says about ofExtensionDifferent: This flag is turned on at runtime whenever the selected filename has an extension that differs from DefaultExt. If you use this flag in an application, remember to reset it.
This is not what the MS Docs say IMO, nor is it how it behaved in the past IIRC. (I would have to check with Delphi 7.)
(The FOS_STRICTFILETYPES flag is new to the Vista dialogs though, it did not exist before. Pre-Vista this flag was mapped to the OFN_EXTENSIONDIFFERENT flag of the LPOPENFILENAME struct.)

Our help says: Allows a file name with an extension which does not match the filters or default extension in a file dialog. (which is the opposite of what FOS_STRICTFILETYPES does)

AFAIK the FOS_STRICTFILETYPES is not set by Windows as a reaction to what the user types.

Does Delphi really behave as the dosc say? In your example: with ofExtensionDifferent turned off, type test.abc (which will retunr test.abc as filename in your example): is ofExtensionDifferent now set in Options?
And how about this then: "If you use this flag in an application, remember to reset it.", if it really works as they say (select a different extension and the flag will be set), why do you not have te reset this then the next time you execute the dialog. Why only if you ever set it at designtime? It makes absolutely no sense to me at all.

Bart

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #27 on: August 21, 2023, 03:30:04 pm »
Just noticed that Delphi uses TFileDialogOption for their Vcl.Dialogs.TCustomFileDialog, which is their abstarct base class for " Vista or later Windows operating systems style file dialogs".

"fdoStrictFileTypes: The file extension of a saved file being must match the selected file type."

Conclusion 1 of all this: there is no 1-on-1 translation between TOpenOption.ofExtensionDifferent and any of the Vista flags.
Conclusion 2: applying FOS_STRICTFILETYPES if ofExtensionDifferent is set, makes no sense whatsoever.

We'll either have to live with it, or also implement TFileDialogOption.

Life sucks ...

Bart

TRon

  • Hero Member
  • *****
  • Posts: 4321
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #28 on: August 21, 2023, 06:52:13 pm »
Life sucks ...
That should read:
Quote
Life sucks ... when using windows.

There /is/ a simple solution ... :P  ;)
Today is tomorrow's yesterday.

Bart

  • Hero Member
  • *****
  • Posts: 5558
    • Bart en Mariska's Webstek
Re: Issue with Win32 TSaveDialog.DefaultExt
« Reply #29 on: August 21, 2023, 09:52:08 pm »
Quote
Life sucks ... when using windows.

There /is/ a simple solution ... :P  ;)

Not really, since we have to support Windows and be as Delphi compatible as possible (without implementing their bugs as well)  ;D

Bart

 

TinyPortal © 2005-2018