0

I have ported a C++Builder 6 application to compile with C++Builder 11.

One issue I have found in testing is that the TOpenDialog behaves differently between the two versions.

The C++Builder 6 version changes the current directory when Open is clicked while the C++Builder 11 version leaves the current directory unchanged.

I have tried setting the OpenDialog Options to ensure that they do not include ofNoChangeDir but this makes no difference.

Both C++Builder 6 and 11 versions are running on Windows 10.

I would like to make the C++Builder 11 version change the current directory on Open so that everything downstream will work in the same way, but so far through clearing and setting options I have had no luck.

I could just change the current directory after OpenDialog->Execute() returns but this seems a bit cludgy when there are Options that should dictate the dialog behavior.

// Check the current directory before and after the OpenDialog executes ...
String CurrentDirectory = GetCurrentDir();

OpenDialog1->Options.Clear();
OpenDialog1->Options << ofHideReadOnly << ofEnableSizing;  // seems to be the default

if (OpenDialog1->Execute())
{
  // do whatever
}

CurrentDirectory = GetCurrentDir(); // no change!? :|
Mark Di Val
  • 81
  • 1
  • 7
  • Not related to your issue, but `OpenDialog1->Options.Clear();` has no effect. You must use `OpenDialog1->Options = TOpenOptions();` instead. Which you can then combine with the subsequent line in a single statement: `OpenDialog1->Options = TOpenOptions() << ofHideReadOnly << ofEnableSizing;` – Remy Lebeau Jul 27 '22 at 05:17
  • Hi Remy - I just now tried that syntax and it made no difference. The current directory is unchanged. I got the OpenDialog->Options.Clear(); syntax from the Embarcadero example code here: https://docwiki.embarcadero.com/CodeExamples/Sydney/en/TApplicationIcon_(C%2B%2B) – Mark Di Val Jul 27 '22 at 05:43
  • I didn't say it would fix your issue. I was simply pointing out a bug in your code. The Embarcadero sample is wrong. Calling `Options.Clear()` reads the `Options` into a temporary object, then `Clear()`'s the temporary, but does not assign the temporary back to the `Options`. Same with `Options << ofHideReadOnly << ...`, BTW . Modifying the `Options` in code can only be done using the `=` assignment operator. – Remy Lebeau Jul 27 '22 at 05:56

1 Answers1

1

The difference in behavior is because the two versions are using different Win32 APIs under the hood.

In C++Builder 6, TOpenDialog uses GetOpenFileNameA(), which has an OFN_NOCHANGEDIR flag that IS NOT enabled by default, hence the working directory changes unless ofNoChangeDir is specified in the Options.

Whereas in C++Builder 11, TOpenDialog uses IFileOpenDialog 1 on Vista+, which has a FOS_NOCHANGEDIR flag that IS enabled by default, hence the working directory does not change. However, TOpenDialog disables FOS_NOCHANGEDIR if ofNoChangeDir is not specified in the Options. It's possible that the dialog is ignoring this for safety reasons, though. So, in your situation, it is best to just set the working directory yourself after TOpenDialog::Execute() exits. 2

1: on pre-Vista systems, or under certain configurations that the VCL can't support using IFileOpenDialog, TOpenDialog will use GetOpenFileNameW() instead - but that will just use IFileOpenDialog internally on Vista+.

2: you really shouldn't be relying on the working directory to begin with. There are other factors that can change the working directory at runtime. You should always use absolute paths only.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I agree that it is generally better for an application to not rely on the current working directory to read or write files. My situation with this port from BCB6 is a prime example of the reasons for this. My ported software does rely on relative (current directory) paths for reading and writing a number of files and so I was hoping to find a quick way to make the TOpenDialog in CB11 behave the same way, and consider the redesign for absolute paths at a later date. Manually setting the current directory after TOpenDialog->Execute() has the desired effect in this regard. – Mark Di Val Jul 27 '22 at 08:35
  • Out of curiosity I have spent a while looking over Vcl.Dialogs.pas, Vcl.Dialogs.hpp, ShObjIdl_core.h, and System.UITypes.hpp to get a feel for what is under the hood. I note that in procedure TFileDialogWrapper.AssignOptions that some options appear to be defined in the array while others are like placeholders. Could this be why some options - like fdoNoChangeDir - can't be changed? – Mark Di Val Jul 27 '22 at 08:35