トップ回答者
設定ファイルや情報ファイルをどこに置いたらいいのでしょう? 実行ファイルの下に置きたいのですが。

質問
-
すいません、またまた初歩的な質問です。
VB6だと、デバッグ時もコンパイル後も相対関係は変わらないので、./KIHON/ABC.xls などとして基本になるファイルを
置いてましたが、VB.Netだと、コンパイル時は/bin/debug/がカレントディレクトリになるので、相対関係が異なっています。
プロジェクト内にフォルダを作って、その絶対パスを指定しても、
実際のパスとは異なるので意味がありませんよね。
実効ファイルの下に、設定ファイルや関連ファイルを納めたフォルダを置きたいのですが、どうするのが普通ですか?
Mydocumentsに置くとかいやですし。
ご教示お願いします。
回答
-
普通は、My.Application.Info.DirectoryPath なんかで相対パスの基底部分に依存性を持たせますね。
#My.Application.Info.DirectoryPath & "\Settings"
そういう意味では、
窓際族 さんからの引用 VB6だと、デバッグ時もコンパイル後も相対関係は変わらないので、./KIHON/ABC.xls などとして基本になるファイルを
置いてましたが、
この場合、ショートカットの作業ディレクトリの値を書き換えると違うところを指すことになります。
で、VB6も同じで、Appオブジェクトに先に書いたような同様のプロパティがありそれを利用します。
-
窓際族 さんからの引用 実行ファイルの下に、設定ファイルや関連ファイルを納めたフォルダを置きたいのですが、どうするのが普通ですか?
テンプレートファイルのようなものであれば、実行ファイルと同じフォルダで構わないと思います。
その場合はまどかさんがアドバイスされている内容でよさそうです。
My.Application.Info.DirectoryPath http://msdn.microsoft.com/ja-jp/library/6whasz3x(VS.80).aspx
但し、アプリケーション(実行ファイル)を終了した後、次に起動したときに覚えておくような設定情報はアプリケーション(実行ファイル)と同じフォルダに置くべきではありません。
Vista以降でProgram Files以下にインストールすると、ファイルに書き込めないということが起きますので。
もちろん、趣味のソフトウェアであれば、Program Files以下に配置しないとすれば良いかもしれません。
-
窓際族 さんからの引用 VB6だと、デバッグ時もコンパイル後も相対関係は変わらないので、./KIHON/ABC.xls などとして基本になるファイルを
置いてましたが、VB.Netだと、コンパイル時は/bin/debug/がカレントディレクトリになるので、相対関係が異なっています。
プロジェクト内にフォルダを作って、その絶対パスを指定しても、
実際のパスとは異なるので意味がありませんよね。
仕様が変わったので困っているという表現をされていますが、何も変わっていません。
VB6ではプロジェクトファイルがあるフォルダ、VSではプロパティで設定した出力先というだけです。
そしてそれは「コンパイル(ビルド)出力の結果を保存する場所」であり、実行時フォルダではありません。
実行時フォルダはまさに実行された時のフォルダですから、開発ツールがわかるはずがありません。
VB6ではたまたまカレントフォルダが期待と一致していたためそれを利用していたということになります。
「カレントフォルダ」は実行時という言葉とは関連が無く、単に今どこにいるかという概念です。
したがって、自分で故意に設定した場合を除き、基本的に今ここにいるはずだという前提を持ってはいけません。
VSには出力先フォルダの内側の階層の概念がありませんが、出力先フォルダへビルド時にコピーする機能があります。
プロジェクトエクスプローラでファイルを選択し、「出力ディレクトリへコピー」プロパティを設定します。
というように、実行時フォルダ(出力先フォルダ)内の任意のフォルダおよびファイルをVSで管理することはできません。
実行時フォルダ(出力先フォルダ)へxxxというフォルダを作成しyyyというファイルを仕込んでおけ
という独自の開発ルールを作るしかないでしょう。
一応、インストーラプロジェクトではインストール先へ任意のフォルダを作成して任意のファイルを配布することは可能ですので
配布時に省略することは可能です。
ただ、あらかじめ置いておきたいとなると前記の問題があるので、app.configを使うのが一般的かと思います。
ソースの一部になりますしビルドに連動して出力してくれます。
任意のファイルへということになれば先に書いたDirectoryPathを使って組み立てることになるでしょう。
既定値という概念があるなら、ファイルが無ければ既定値で動くという仕組みを作れます。
Code Snippetかなり省略
Public Class MyConfiguration
Private Shared _Parm1 As Integer = 111
Public Shared Property Parm1 As Integer
Get
Return _Parm1
End Get
Public Shared Sub Load()
Public Shared Sub Save()
Shared Sub New()
Load()
End Sub
End Class
という設定ファイルの内容を管理するクラスを作りすべてこのクラスのプロパティを介してアクセスさせます。
ファイルがどこにあるか、というよりファイルであるかさえもコードでは意識する必要がありません。
そしてLoadではファイルが無ければ何もしません。
ファイルが無い場合は、このクラスに定義された既定値が返ります。
こうすれば既定値と違う場合だけファイルを作ればよいことになります。
#app.config方式であれば書いてある内容が既定値ということになりますね。
-
ClickOnceはインストールした情報が仕組みにより管理されています。
なので、何かしらの変更をおこなうと自動修復されます。
したがって、インストール先フォルダに対して期待されていることは実現できませんね。
書き込みができない以上、次の方法になるかと思います。
・ClickOnceでのインストール先ではない場所固定のフォルダ
・フォルダを任意に指定できるが、そのパスを保存しておく場所を固定のレジストリキーなどにする。
窓際族 さんからの引用 absolutePathがデバック時と異なっているので困惑しております。
異なってはいません。
デバッグ時もEXE実行時も、「実行ファイルが存在するフォルダ」ということで意味は等価です。
窓際族 さんからの引用 Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
Application.ExecutablePath 自体がフルパスで入っているはずです。
そして、GetDirectoryNameも引数にフルパスを与えているので結果はフルパスです。
ExecutablePathはファイル名も含みますので、最初に書いたようにMy.Application.Info.DirectoryPathなら欲しい値そのまんまです。
すべての返信
-
普通は、My.Application.Info.DirectoryPath なんかで相対パスの基底部分に依存性を持たせますね。
#My.Application.Info.DirectoryPath & "\Settings"
そういう意味では、
窓際族 さんからの引用 VB6だと、デバッグ時もコンパイル後も相対関係は変わらないので、./KIHON/ABC.xls などとして基本になるファイルを
置いてましたが、
この場合、ショートカットの作業ディレクトリの値を書き換えると違うところを指すことになります。
で、VB6も同じで、Appオブジェクトに先に書いたような同様のプロパティがありそれを利用します。
-
窓際族 さんからの引用 実行ファイルの下に、設定ファイルや関連ファイルを納めたフォルダを置きたいのですが、どうするのが普通ですか?
テンプレートファイルのようなものであれば、実行ファイルと同じフォルダで構わないと思います。
その場合はまどかさんがアドバイスされている内容でよさそうです。
My.Application.Info.DirectoryPath http://msdn.microsoft.com/ja-jp/library/6whasz3x(VS.80).aspx
但し、アプリケーション(実行ファイル)を終了した後、次に起動したときに覚えておくような設定情報はアプリケーション(実行ファイル)と同じフォルダに置くべきではありません。
Vista以降でProgram Files以下にインストールすると、ファイルに書き込めないということが起きますので。
もちろん、趣味のソフトウェアであれば、Program Files以下に配置しないとすれば良いかもしれません。
-
窓際族 さんからの引用 VB6だと、デバッグ時もコンパイル後も相対関係は変わらないので、./KIHON/ABC.xls などとして基本になるファイルを
置いてましたが、VB.Netだと、コンパイル時は/bin/debug/がカレントディレクトリになるので、相対関係が異なっています。
プロジェクト内にフォルダを作って、その絶対パスを指定しても、
実際のパスとは異なるので意味がありませんよね。
仕様が変わったので困っているという表現をされていますが、何も変わっていません。
VB6ではプロジェクトファイルがあるフォルダ、VSではプロパティで設定した出力先というだけです。
そしてそれは「コンパイル(ビルド)出力の結果を保存する場所」であり、実行時フォルダではありません。
実行時フォルダはまさに実行された時のフォルダですから、開発ツールがわかるはずがありません。
VB6ではたまたまカレントフォルダが期待と一致していたためそれを利用していたということになります。
「カレントフォルダ」は実行時という言葉とは関連が無く、単に今どこにいるかという概念です。
したがって、自分で故意に設定した場合を除き、基本的に今ここにいるはずだという前提を持ってはいけません。
VSには出力先フォルダの内側の階層の概念がありませんが、出力先フォルダへビルド時にコピーする機能があります。
プロジェクトエクスプローラでファイルを選択し、「出力ディレクトリへコピー」プロパティを設定します。
というように、実行時フォルダ(出力先フォルダ)内の任意のフォルダおよびファイルをVSで管理することはできません。
実行時フォルダ(出力先フォルダ)へxxxというフォルダを作成しyyyというファイルを仕込んでおけ
という独自の開発ルールを作るしかないでしょう。
一応、インストーラプロジェクトではインストール先へ任意のフォルダを作成して任意のファイルを配布することは可能ですので
配布時に省略することは可能です。
ただ、あらかじめ置いておきたいとなると前記の問題があるので、app.configを使うのが一般的かと思います。
ソースの一部になりますしビルドに連動して出力してくれます。
任意のファイルへということになれば先に書いたDirectoryPathを使って組み立てることになるでしょう。
既定値という概念があるなら、ファイルが無ければ既定値で動くという仕組みを作れます。
Code Snippetかなり省略
Public Class MyConfiguration
Private Shared _Parm1 As Integer = 111
Public Shared Property Parm1 As Integer
Get
Return _Parm1
End Get
Public Shared Sub Load()
Public Shared Sub Save()
Shared Sub New()
Load()
End Sub
End Class
という設定ファイルの内容を管理するクラスを作りすべてこのクラスのプロパティを介してアクセスさせます。
ファイルがどこにあるか、というよりファイルであるかさえもコードでは意識する必要がありません。
そしてLoadではファイルが無ければ何もしません。
ファイルが無い場合は、このクラスに定義された既定値が返ります。
こうすれば既定値と違う場合だけファイルを作ればよいことになります。
#app.config方式であれば書いてある内容が既定値ということになりますね。
-
皆様からの有意義なご説明ありがとうございます。
未熟者ですのでよろしくお願いします。
アプリケーションの初期起動時に作成するファイルは、MenuFormで、起動時に点検または作成するように
したので、●●.exe.infoのようにbin/debug下に作られており、ファイラーなどで、点検したりできます。
これは登録情報ファイルなのでこれでいいのですが、
たとえば、印刷の定型ファイルとかエクセルのテンプレートとか沢山のファイルを置いて、デバック時にも
自由に実験したいのですが、VB6のように行かないので苦労してます。
発行先はprogramfiles/×××/●●●と予定しているので、それらのファイルをそこに置いて絶対パスで
操作するということでしょうか。
よく研究します。
-
窓際族 さんからの引用 VB6のように行かないので苦労してます。
先にも書きましたが、VB6ではたまたま期待と一致した動きであったという認識はできていますか?
VB6でもVSでも、ツリーで表示されているものはファイルであれフォルダであれ「ソース」です。
実行時のイメージではありません。
VB6の場合。
D:\Project1 にvbp ファイルがあるとします。
D:\Project1\Setting にファイルがあるとします。
exe ファイルをD:\Project1 に作成したとします。
VB6ではデバッグ時にvbp ファイルのあるフォルダがWindowsOSのカレントフォルダとして設定されます。
上記の場合は、D:\Project1 になります。
このときコードでファイル名を".\Setting\xxx.txt"としている場合、カレントフォルダの相対パスとみなされますので
"D:\Project1\Setting\xxx.txt"となりつじつまが合い正しく認識できます。
ですが、これはVB6のデバッグ時動作の副作用による偶然の結果です。
上記で作成したexeのショートカットを作成してプロパティの作業ディレクトリをD:\Project1\Setting としたらどうなるでしょうか?
".\Setting\xxx.txt" は "D:\Project1\Setting\Setting\xxx,txt" となり正しく認識できません。
このように実行時のフォルダ構成はどこに配置されるかわからない未来のことですので
開発ツールに実行時フォルダという概念はありません。
したがって、コードで相対パスで表現することは不可能です。(直前に自身でカレントフォルダを操作しない限り)
そして最初に書いたように、通常DirectoryPath等と組み合わせて使用して絶対パスとして表現します。
ただし、DirectoryPath内のフォルダ構成はVSは知ることができませんし、ソースファイルの構成としても表現できません。
したがって、実行時フォルダ内の任意のフォルダは用意しておく必要があります。
ただし、VSには出力先フォルダ=アセンブリの置き場所ということから、アセンブリのある場所と同じ場所という概念があります。
それがapp.configであったり「出力先ディレクトリにコピー」プロパティです。
-
窓際族 さんからの引用 アプリケーションの初期起動時に作成するファイルは、MenuFormで、起動時に点検または作成するように
したので、●●.exe.infoのようにbin/debug下に作られており、ファイラーなどで、点検したりできます。
先にも書きましたが、Vistaでは通常、Program Files以下には書き込めません。
アプリケーションと同じフォルダにファイルを書き込むという設計は辞めるべきです。
窓際族 さんからの引用 発行先はprogramfiles/×××/●●●と予定しているので、それらのファイルをそこに置いて絶対パスで
操作するということでしょうか。
発行というと、ClickOnceですよね?
であれば、Program Files以下にはできないと思うのですが…。
-
相対パスにこだわっていたのでうまくいきませんでした。
出力ディレクトリにコピーすると、
Dim absolutePath As String = Path.GetFullPath(Path.GetDirectoryName(Application.ExecutablePath))
で、なんとかできるようになりました。
ところが、
>先にも書きましたが、Vistaでは通常、Program Files以下には書き込めません。
>アプリケーションと同じフォルダにファイルを書き込むという設計は辞めるべきです。
なんですか。当然、インストーラを使っても無駄ですね。
Vistaの研究をします。
-
窓際族 さんからの引用 >先にも書きましたが、Vistaでは通常、Program Files以下には書き込めません。
>アプリケーションと同じフォルダにファイルを書き込むという設計は辞めるべきです。
なんですか。当然、インストーラを使っても無駄ですね。
すみません、言葉が足りていませんでした。
昇格ダイアログを経て、管理者特権があればProgram Filesに書き込めます。
インストール時は昇格ダイアログを経て、管理者特権でインストールするとしても、アプリケーションを実行する度に毎回昇格ダイアログが表示されるのはよくありません。
その実行しようとしているユーザが昇格させることができるとも限りません。
インストール時点で決まり切ったファイルをProgram Files以下に置くことはありですが、それ以降(アプリケーション初回起動時を含む)はProgram Files以下に書き込むことは避けるべきです。
-
> すみません、言葉が足りていませんでした。
> 昇格ダイアログを経て、管理者特権があればProgram Filesに書き込めます。
ちょっと間違った部分があるのでフォローです。
(インストール後)Program Files以下に作成されたフォルダに対しては書き込むことはできます。
ただし、実際のファイルはProgram Files以下のフォルダには書かれず、"%APPDATA%\Local\VirtualStore\Program Files"に書かれます。(%APPDATA%は環境変数です)
Vistaでは過去に作成されたプログラムとの互換性のために、Program FilesやWindowsフォルダ以下にファイルを作成したとき、VirtualStoreフォルダの下にフォルダが作成され、そこにローミングされます。(補足すれば、%APPDATA%は通常、"C:\Users\ユーザー名\AppData\Roaming"以下に作成されます。そのため、全ユーザー共通の設定ファイルを作成したつもりでも、実際には各ユーザーで別の設定ファイルになります)
※あくまでも、過去に作成されたプログラムとの互換性のための機能です。
新規にシステムを設計する場合はProgram Files以下に保存する事についてはAzuleanさんが言われるように避けるべきです。 -
Vistaでのファイルの書き込みに関しては皆様の書かれているとおりです。
>なんですか。当然、インストーラを使っても無駄ですね。
Program Files配下ではなくてたとえば、
All Users\Application Data\アプリケーション名
配下でよいならば、
MSDNフォーラム過去スレッド「All Users\Documentsにファイルをインストールする方法」http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2849589&SiteID=7
を参照してください。
追記:ここVisual Basic 「Express Edition」 フォーラム ですよね?
「Express Edition」にはセットアッププロジェクトはありませんが、インストーラ作成は別のツールを使ってってことでしょうか?
-
CatTail さんからの引用 Vistaでは過去に作成されたプログラムとの互換性のために、Program FilesやWindowsフォルダ以下にファイルを作成したとき、VirtualStoreフォルダの下にフォルダが作成され、そこにローミングされます。
リダイレクト機能は、新しく作られたプログラムには適用しないように考慮されています。
そのため、VC#2008やVB2008で作られたアプリでは、オプションを変更しない限り、機能しないはずです。
根拠としてはrequestedExecutionLevel = asInvokerのマニフェストが設定されることです。
(動作確認はしていません)
Virtualizationの発動条件などは下記のドキュメントをご参照ください。
http://msdn.microsoft.com/en-us/library/bb756960.aspx
Virtualization is disabled for:
-
64 bit processes
-
Non-interactive processes
-
Processes that impersonate
-
Kernel mode callers
-
Executables that have a requestedExecutionLevel
-
-
> リダイレクト機能は、新しく作られたプログラムには適用しないように考慮されています。
> そのため、VC#2008やVB2008で作られたアプリでは、オプションを変更しない限り、機能しないはずです。
> 根拠としてはrequestedExecutionLevel = asInvokerのマニフェストが設定されることです。
> (動作確認はしていません)
以前、MSのセミナーで「過去のプログラムとの互換性のため、リダイレクト機能がある」と聞いていたもので、
てっきり新しく作られたプログラムには適用されると思っていました。
念のため動作確認してみますが、有効な情報ありがとうございました。ちなみに弊社がVB6→VB.NETに移行した際には、VB6ではINIファイルで管理していましたが、
app.configとデータベースに保存するように変更しました。
(app.configにはデータベースへの接続情報等を保持) -
ただいまインストールのテストをしてまして結果は散々でした。
Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
で得られた場所にフォルダとファイルを作る方法はだめでした。固定的なヘルプファイルのようなものはうまくいってますが、
書き込みを随時する設定ファイルはlocalsettingにコピーされないのです。
ファイルを隠しファイルにしたせいでしょうか。
いろいろ実験してもうまくいかないので、結局
my.settingsを利用することにしました。
これだと安定しています。それに、関連するコードも10分の1になりましたし。
デザイナーを見ると単なるプロパティなのですが、場所が安定しているところが利点です。
みなさん、どうもありがとうございました。
-
インストールのテストということでインストール時にフォルダを作成したいという前提では\書きます。
窓際族 さんからの引用 ただいまインストールのテストをしてまして結果は散々でした。
先にも書きましたが、VSのインストールプロジェクトではインストール先を含め任意のフォルダを作成できますよ。
窓際族 さんからの引用 Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
で得られた場所にフォルダとファイルを作る方法はだめでした。これが何をしていてどういう結果になるか理解してますか?
MSDNで各メソッドの解説を読んでください。
というか、インストーラの中でのコードであれば
Application.ExecutablePathはインストーラ自体のフルパスファイル名なんですが。
アプリケーションのインストール先として指定されたパスを使わないと。。。
-
まどか さんからの引用 窓際族 さんからの引用 Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
で得られた場所にフォルダとファイルを作る方法はだめでした。これが何をしていてどういう結果になるか理解してますか?
MSDNで各メソッドの解説を読んでください。
というか、インストーラの中でのコードであれば
Application.ExecutablePathはインストーラ自体のフルパスファイル名なんですが。
アプリケーションのインストール先として指定されたパスを使わないと。。。
毎度、ご教示ありがとうございます。
いいえ、インストーラの中のコードではありません。
アプリケーションの中で作成するファイルの場所です。
Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
で得られる、場所は、localsettings/apps/のずっと下の方ですね。...tions/のさらに下。そこに、読み込み専用のフォルダはコピーされてるのですが、なぜか、書き込みしようとしているフォルダとファイルが
コピーされてません。そこに、アプリケーションのある場所にインストールされたフォルダをコピーすると、動作します。
ちなみに、インストールテストしたのは、XpProでした。
「ClickOnce を使用して配置されるかどうかによってこのパスは異なります。」とありますね。
absolutePathがデバック時と異なっているので困惑しております。
-
ClickOnceはインストールした情報が仕組みにより管理されています。
なので、何かしらの変更をおこなうと自動修復されます。
したがって、インストール先フォルダに対して期待されていることは実現できませんね。
書き込みができない以上、次の方法になるかと思います。
・ClickOnceでのインストール先ではない場所固定のフォルダ
・フォルダを任意に指定できるが、そのパスを保存しておく場所を固定のレジストリキーなどにする。
窓際族 さんからの引用 absolutePathがデバック時と異なっているので困惑しております。
異なってはいません。
デバッグ時もEXE実行時も、「実行ファイルが存在するフォルダ」ということで意味は等価です。
窓際族 さんからの引用 Dim absolutePath As String = path.GetFullPath(path.GetDirectoryName(Application.ExecutablePath))
Application.ExecutablePath 自体がフルパスで入っているはずです。
そして、GetDirectoryNameも引数にフルパスを与えているので結果はフルパスです。
ExecutablePathはファイル名も含みますので、最初に書いたようにMy.Application.Info.DirectoryPathなら欲しい値そのまんまです。