Recent

Author Topic: [SOLVED] TSaveDialog  (Read 573 times)

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
[SOLVED] TSaveDialog
« on: June 17, 2026, 08:57:08 am »
Hi Folks,

Target: Win 64 Bit

quick Question: How is TSaveDialog handling OneDrive/SharePoint-Paths?

Background: Currently, i'm writing a program, which will offer a TSaveDialog to the User.
Is there anything to consider, if the User chooses a OneDrive-Folder vs. e.g. c:\Temp?
« Last Edit: June 18, 2026, 12:33:45 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

Thaddy

  • Hero Member
  • *****
  • Posts: 19398
  • Glad to be alive.
Re: TSaveDialog and OneDrive
« Reply #1 on: June 17, 2026, 12:11:13 pm »
I can select and save to my local OneDrive folder but sync only takes place when OneDrive synchronizes. So it is not immediately visible to others or your other devices, e.g. OneDrive\Public needs to be synced first. TSaveDialog itself does not care how you save.....
« Last Edit: June 17, 2026, 12:50:57 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Thaddy

  • Hero Member
  • *****
  • Posts: 19398
  • Glad to be alive.
Re: TSaveDialog and OneDrive
« Reply #2 on: June 17, 2026, 12:28:20 pm »
Possible if you save the file over the Microsoft Graph OneDrive API (Basically https):
- fpjson + fpHttpClient+OpenSSl/TLS1.3+OAuth2. (Google API TGoogleOauth2 works for OneDrive tokens too)
Once you have the OAUTH2 token, the code is as easy as this:
Code: Pascal  [Select][+][-]
  1. procedure UploadToOneDrive(const LocalFile, RemotePath, AccessToken: string);
  2. var
  3.   Client: TFPHTTPClient;
  4.   Stream: TFileStream;
  5.   Url: string;
  6. begin
  7.   Url := 'https://graph.microsoft.com/v1.0/me/drive/root:/' +
  8.          RemotePath + ':/content';
  9.  
  10.   Client := TFPHTTPClient.Create(nil);
  11.   Stream := TFileStream.Create(LocalFile, fmOpenRead or fmShareDenyWrite);
  12.   try
  13.     Client.AddHeader('Authorization', 'Bearer ' + AccessToken); // through OAUTH2
  14.     Client.AddHeader('Content-Type', 'application/octet-stream');
  15.     Client.RequestBody := Stream;
  16.     Client.HTTPMethod('PUT', Url);
  17.   finally
  18.     Stream.Free;
  19.     Client.Free;
  20.   end;
  21. end;

I will see if I can add the OAuth2 code, I must have some code around  for re-use.
This code will synchronize. Note the path must be canonical and special characters need to be escaped.

Basically almost all you need can be taken from this article by Michael van Canneyt:
https://www.freepascal.org/~michael/articles/googleapi/googleapi.pdf since with my above code you already have the OneDrive specifics.
Similar code would work with SharePoint.

- if you save to the local drive the normal way you need to synchronize and that is not easy to force from code.
- if you save over rest/https  using  Microsoft Graph OneDrive API, synchronization is guaranteed.

Maybe you can save large files directly on the local OneDrive and then synchronize by sending a small file over https? (May speed things up)
« Last Edit: June 17, 2026, 12:57:39 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: TSaveDialog and OneDrive
« Reply #3 on: June 17, 2026, 02:03:43 pm »
Thx Thaddy for the answers.

My question targets: is TSaveDialog reading the "local" Path of the chosen Folder, or does it return the Sharepoint-Path?
I'm asking because that got me into huge problems with some of my VBA (Excel)-Scripts, and it was a huge PITA to get it right,
because of the different Directory-Separator ("\" vs. "/").

EDIT:
OK. Found something
Unit ShlObj, and there SHGetSpecialFolderPath with CSIDL_PERSONAL-Constant

Which returns the local path

I'll set this to resolved
« Last Edit: June 17, 2026, 02:15: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

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog and OneDrive
« Reply #4 on: June 17, 2026, 02:35:40 pm »
OK, now this is driving me bonkers....

Why is TSaveDialog complaining "....the file does not exist..." when i hit "Save"????
Of course the file doesn't exist, since i want to save it.
Huh?

So, which one of those cryptic options do i have to set?
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

paweld

  • Hero Member
  • *****
  • Posts: 1676
Re: [Reopened] TSaveDialog and OneDrive
« Reply #5 on: June 17, 2026, 02:53:02 pm »
Code: Pascal  [Select][+][-]
  1. SaveDialog1.Options := SaveDialog1.Options - [ofFileMustExist];
Best regards / Pozdrawiam
paweld

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog and OneDrive
« Reply #6 on: June 17, 2026, 03:27:24 pm »
Code: Pascal  [Select][+][-]
  1. SaveDialog1.Options := SaveDialog1.Options - [ofFileMustExist];
Hi pawel.
Nope, that is not selected in OI (and i just tested it doing it from code like you wrote).

Same Result: It's as if the SaveDialog thinks it's a TOpenDialog

Did the same with vanilla-project.
New Project, throw a TSaveDialog on the Form, a TButton
everything with Default-Values
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var s:String;
  3. begin
  4.   if SaveDialog1.Execute Then
  5.     s:=SaveDialog1.FileName;
  6. end;      
Message "File doesn't exist. Make sure it exists...blablab" comes on clicking on "Save", which should let the Execute-Method return.
I never reach the line with "s:=....."


EDIT: Though you are on the correct path.
Just looked into the source in filedialog.inc - TOpenFile.CheckFile (around Line 545)
As far as i can see, it's the only location it gets checked resp. that Message is displayed
Code: Pascal  [Select][+][-]
  1. if (ofFileMustExist in Options)
  2.   and (not CheckFileMustExist(AFileName)) then begin
  3.     // CheckFileMustExists shows message dialog
  4.     Result:=false;
  5.     exit;
  6.   end;    
Since it's an "And"-Operation, it implies that ofFileMustExist IS in Options
So, why does my setting (OI and from Code) get ignored?
« Last Edit: June 17, 2026, 04:03:06 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

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog and OneDrive
« Reply #7 on: June 17, 2026, 04:13:49 pm »
Can't find anything in Bugtracker, except something from over 15 years ago

Can't imagine this bug (if it is a bug) would survive this long
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

Thaddy

  • Hero Member
  • *****
  • Posts: 19398
  • Glad to be alive.
Re: [Reopened] TSaveDialog
« Reply #8 on: June 17, 2026, 05:12:17 pm »
check the filemode: does it include fmCreate? E.g. fmCreate or OpenWrite
This will either create or overwrite a file. Assuming underlying TFileStream:
https://www.freepascal.org/docs-html/rtl/classes/tfilestream.create.html

The TSaveDialog does not set any TFileStream options itself: it merely checks if the ofXXX options are satisfied, NOT the TFileStream fmXXX options.
« Last Edit: June 17, 2026, 05:20:49 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog
« Reply #9 on: June 18, 2026, 08:15:29 am »
check the filemode: does it include fmCreate? E.g. fmCreate or OpenWrite
This will either create or overwrite a file. Assuming underlying TFileStream:
https://www.freepascal.org/docs-html/rtl/classes/tfilestream.create.html

The TSaveDialog does not set any TFileStream options itself: it merely checks if the ofXXX options are satisfied, NOT the TFileStream fmXXX options.
That's the thing: No Filestream is even prepared, nevermind created.
The Message comes after clicking on "Save" in the SaveDialog, meaning: During the "Execute"-Method, before it returns to my own code

EDIT: Progress!
ON a hunch, in the SaveDialog i moved/choose "c:\Temp" instead of my OneDrive and voila: No Error-Message. Execute returns True
But instead, SaveDialog.FileName is now empty....
What now??
There is something seriously wrong

EDIT2: Right. On a Vanilla-Project (Form, Button, SaveDialog)
it's definitely the OneDrive, specifically the "My Documents"-Folder.
If i choose any Folder, that's not a SubFolder of my OneDrive, SaveDialog.FileName returns the FileName, otherwise i get the above ErrorMessage (File not found)

Feels like access-rights or something.....

EDIT3
Further testing:
Any Folder below "c:Users\xxxx.xxx\OneDrive - MyCompany" returns the Error-Message "File Not found"
Folder "c:Users\xxxx.xxx\OneDrive - MyCompany" and any Folder above/outside returns True for Execute and returns the FileName.

Hmm....all SubFolders of "c:Users\xxxx.xxx\OneDrive - MyCompany" are synced to the Sharepoint.
Sounds like Trouble with Pathnames

I remember executing an Excel-Macro inside my OneDrive-Documents-Folder, and it returned that "sharepoint"-Notation for ThisWorkbook.Path
« Last Edit: June 18, 2026, 09:02:58 am 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

Thaddy

  • Hero Member
  • *****
  • Posts: 19398
  • Glad to be alive.
Re: [Reopened] TSaveDialog
« Reply #10 on: June 18, 2026, 09:06:33 am »
You need the absolute path to the OneDrive folder and that differs from the path Windows shows you as default. In my case it is c:\users\thadd\onedrive
objects are fine constructs. You can even initialize them with constructors.

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: [Reopened] TSaveDialog
« Reply #11 on: June 18, 2026, 09:22:52 am »
In TSaveDialog, one needs to choose add/remove options that might ignite precheck, such as: ofOverwritePrompt, ofNoTestFileCreate, ofAutoPreview, etc.

Anyway, in working with (could be) cloud files, I use code below to check. Perhaps useful.

Code: Pascal  [Select][+][-]
  1. function FncFileAvailableLocally(const PrmFName: String): Boolean;
  2. var
  3.   Attrs: DWORD;
  4. begin
  5.   Result := False;        
  6.   Attrs := GetFileAttributesW(PWideChar(UnicodeString(PrmFName)));
  7.   if (Attrs <> INVALID_FILE_ATTRIBUTES) then
  8.     Result := (Attrs and FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0)
  9.         and (Attrs and FILE_ATTRIBUTE_OFFLINE = 0);
  10. end;    
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog
« Reply #12 on: June 18, 2026, 09:46:17 am »
You need the absolute path to the OneDrive folder and that differs from the path Windows shows you as default. In my case it is c:\users\thadd\onedrive

That's the Thing: I did have it.
I even hardcoded the Full Path in code (Without a SaveDialog)
"c:\Users\zvoni\OneDrive MyCompany\Documents\Test.txt" and sent it to a Saving routine (Filestream), and received the same Error: File not Found
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

Zvoni

  • Hero Member
  • *****
  • Posts: 3435
Re: [Reopened] TSaveDialog
« Reply #13 on: June 18, 2026, 09:54:15 am »
In TSaveDialog, one needs to choose add/remove options that might ignite precheck, such as: ofOverwritePrompt, ofNoTestFileCreate, ofAutoPreview, etc.

Anyway, in working with (could be) cloud files, I use code below to check. Perhaps useful.

Code: Pascal  [Select][+][-]
  1. function FncFileAvailableLocally(const PrmFName: String): Boolean;
  2. var
  3.   Attrs: DWORD;
  4. begin
  5.   Result := False;        
  6.   Attrs := GetFileAttributesW(PWideChar(UnicodeString(PrmFName)));
  7.   if (Attrs <> INVALID_FILE_ATTRIBUTES) then
  8.     Result := (Attrs and FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0)
  9.         and (Attrs and FILE_ATTRIBUTE_OFFLINE = 0);
  10. end;    
No such options active
Vanilla-Project, Default-Options  Resize and ViewDetail, everything else off

EDIT
Quote
In TSaveDialog, one needs to choose add/remove options that might ignite precheck, such as: ofOverwritePrompt, ofNoTestFileCreate, ofAutoPreview, etc.
For laughs, i actually activated "ofNoTestFIleCreate", and the Message is gone, but when passing the returned FileName to my saving Routin (FileStream), i get an EFCreateError

If i stay outside the synced Folders everything works
« Last Edit: June 18, 2026, 10:02:41 am 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

Xenno

  • Full Member
  • ***
  • Posts: 131
    • BS Programs
Re: [Reopened] TSaveDialog
« Reply #14 on: June 18, 2026, 10:04:36 am »
"... add/remove ..."

Something like this:

Code: Pascal  [Select][+][-]
  1. SaveDialog1.Options := SaveDialog1.Options - [ofFileMustExist, ofOverwritePrompt, ofAutoPreview] + [ofNoValidate, ofNoTestFileCreate];
Lazarus 4.6, Windows 10, https://www.youtube.com/@bsprograms
If I want to share, I give. If I want money, I sell. I don't set traps.

 

TinyPortal © 2005-2018