トップ回答者
Open/SaveFileDialogのカレントディレクトリについて

質問
-
お世話になります。
SaveFileDialogで相対パスを利用すると、XP環境(WinSvr2003も?)でのみカレントディレクトリが変更され、
結果として意図しないパスを参照しています。
これは既知の事象なので、回避策などは聞きませんが、
お聞きしたいのは3点です
①なぜWinXPで発生してVista以降では発生しないのでしょうか?
②.Net Framework2.0、3.5で発生を確認していますが、他のバージョンでもやはりXP上だと再現するのでしょうか
③MSの公式サイトにこの事象について言及したものが確認できませんでしたが(RestoreDirectoryプロパティについては記載がありましたが)、
特定のOSで発生したりすることを考えると、.Netのバグでしょうか?もしくはOSの何かの仕様に依存しているのでしょうか。
回答
-
OpenFileDialog および SaveFileDialog は Windows Vista で追加された IFileDialog という新しいコモンダイアログの API を利用します。
Windows XP では従来の GetOpenFileName および GetSaveFileName という API を使うのでその実装の差だと考えられます。
(.NET のバージョンに依存しない)
仕様か不具合かと問われると何とも言いかねます。
<以下参考>
AutoUpgradeEnabled プロパティ を false に設定すれば新しい API を使いません。ただ、このプロパティは .NET 2.0 SP1 以上でのみ利用可能であるため、.NET 2.0 SP なし環境での動作が必要な場合、リフレクションでそのプロパティが存在するかどうか確認してから設定する必要。なお、今回の XP 風だと問題が発生するという状況において、プロパティを false に設定するメリットはないと思われます。
- 編集済み AzuleanMVP, Moderator 2014年5月1日 2:26
- 回答としてマーク jun-f 2014年5月1日 2:37
-
SaveFileDialogは、実体はGetSaveFileName関数またはIFileSaveDialogインターフェイスを使用しています。どちらもOS(厳密にはシェルになるのかしら)が提供している機能です(なので、.NETのSaveFileDialogで表示するダイアログとほかのアプリで表示する保存ダイアログが同じ見た目になります。カスタムする余地はありますが)。
このうち、GetSaveFileName関数は昔から存在している関数であり、一方IFileSaveDialogインターフェイスはVista以降に追加されたよりリッチなダイアログを提供できる仕組みになっています。
SaveFileDialogでは両方を利用できるように、AutoUpgradeEnabledプロパティを提供しており、これがtrueでかつOSがVista以降の場合は自動的にIFileSaveDialogを使ってダイアログを出すように実装されています。そしてこのプロパティは既定でtrueです。
で、GetSaveFileName関数にはOPENFILENAME structureという構造体を渡すのですが、この構造体の中にOFN_NOCHANGEDIRというフラグがあり、これでカレントディレクトリの変更を戻すかどうか指定できます。SaveFileDialogのRestoreDirectoryプロパティはこのフラグをラップしています。つまり、少なくともGetSaveFileName関数を使わざるを得ないXPでカレントディレクトリが既定で変更されるのは仕様です。
// IFileSaveDialogの方は、類似メンバがあるのに変わらないのはどうなんだろう。既定で変更しないになってるだけならともかく、RestoreDirectory = falseにしても変更されないのは仕様か不具合か、またどのレベルでの問題か、判断できない。
蛇足ながら、カレントディレクトリに依存するアプリケーションというのは、バッチ処理的なコンソールアプリに限定すべきだと私は考えています。
- 回答としてマーク jun-f 2014年5月1日 2:37
すべての返信
-
OpenFileDialog および SaveFileDialog は Windows Vista で追加された IFileDialog という新しいコモンダイアログの API を利用します。
Windows XP では従来の GetOpenFileName および GetSaveFileName という API を使うのでその実装の差だと考えられます。
(.NET のバージョンに依存しない)
仕様か不具合かと問われると何とも言いかねます。
<以下参考>
AutoUpgradeEnabled プロパティ を false に設定すれば新しい API を使いません。ただ、このプロパティは .NET 2.0 SP1 以上でのみ利用可能であるため、.NET 2.0 SP なし環境での動作が必要な場合、リフレクションでそのプロパティが存在するかどうか確認してから設定する必要。なお、今回の XP 風だと問題が発生するという状況において、プロパティを false に設定するメリットはないと思われます。
- 編集済み AzuleanMVP, Moderator 2014年5月1日 2:26
- 回答としてマーク jun-f 2014年5月1日 2:37
-
SaveFileDialogは、実体はGetSaveFileName関数またはIFileSaveDialogインターフェイスを使用しています。どちらもOS(厳密にはシェルになるのかしら)が提供している機能です(なので、.NETのSaveFileDialogで表示するダイアログとほかのアプリで表示する保存ダイアログが同じ見た目になります。カスタムする余地はありますが)。
このうち、GetSaveFileName関数は昔から存在している関数であり、一方IFileSaveDialogインターフェイスはVista以降に追加されたよりリッチなダイアログを提供できる仕組みになっています。
SaveFileDialogでは両方を利用できるように、AutoUpgradeEnabledプロパティを提供しており、これがtrueでかつOSがVista以降の場合は自動的にIFileSaveDialogを使ってダイアログを出すように実装されています。そしてこのプロパティは既定でtrueです。
で、GetSaveFileName関数にはOPENFILENAME structureという構造体を渡すのですが、この構造体の中にOFN_NOCHANGEDIRというフラグがあり、これでカレントディレクトリの変更を戻すかどうか指定できます。SaveFileDialogのRestoreDirectoryプロパティはこのフラグをラップしています。つまり、少なくともGetSaveFileName関数を使わざるを得ないXPでカレントディレクトリが既定で変更されるのは仕様です。
// IFileSaveDialogの方は、類似メンバがあるのに変わらないのはどうなんだろう。既定で変更しないになってるだけならともかく、RestoreDirectory = falseにしても変更されないのは仕様か不具合か、またどのレベルでの問題か、判断できない。
蛇足ながら、カレントディレクトリに依存するアプリケーションというのは、バッチ処理的なコンソールアプリに限定すべきだと私は考えています。
- 回答としてマーク jun-f 2014年5月1日 2:37