none
All Users\Documentsにファイルをインストールする方法 RRS feed

  • 質問

  • いつもお世話になっております。

     

    Visual Sudio 2005のセットアッププロジェクトにてインストーラーを作成しています。

    ユーザー共通で使用する設定ファイル(使用するたびに更新する)があるため制限ユーザーでも書き込みが可能な

    Documents and Settings\All Users\Documents

    に設定ファイルをインストールしようと考えています。

    しかし、その設定方法がわかりません。

     

    ご存知の方がいらっしゃいましたら教えてください。

    よろしくお願いします。

    2008年2月15日 8:15

回答

  •  あいこ さんからの引用

    初めに教えていただいた方法ですが、私まだまだ初心者のため具体的にどのようなコードをかけばそれが実現できるのかがまだ理解できておりません・・・

    教えていただいたMSDNライブラリを参考にしてもう少し調べてみます!

    私が言おうとしていたやり方は…

    対象マシンに.NETが入っている前提とします。(入っていなければ事前に入れるか、「必須コンポーネント」としてセットアップに含められます。)

     

    以下はすでに試されてるかとは思いますが…

    セットアッププロジェクトのファイルシステムエディタで「対象コンピュータ上のファイルシステム」を右クリックしてコンテクストメニューで「特殊フォルダの追加」で「カスタムフォルダ」を追加しそれを選択して

    プロパティウィンドウのDefaultLocationで[CommonAppDataFolder]と入力してください。

    そこにさらにサブフォルダを追加します。名前をAAAAAとします。これがアプリケーションデータファイルを入れるフォルダです。

    必要ならばファイルや更なるサブディレクトリを追加してください。

     

    同じソリューションにクラスライブラリプロジェクトを作成します。Class1.csは消してください。

    そのプロジェクトを右クリックしてコンテクストメニューで「追加」「コンポーネント」を選択します。

    「新しい項目の追加」ダイアログで「インストーラクラス」を選択して「追加」して下さい。たとえば名前をMyInstallerとします。

    コードビューでそれを表示します。

    public partial class MyInstaller : Installerの{}なかで

    public overrideと入力しスペースを押すとIntelliSenseによっていくつかメソッドが表示されます。

    このうち、InstallとCommitを選択してください。

    Code Snippet

    public override void Install(System.Collections.IDictionary stateSaver)

    {

        base.Install(stateSaver);

    }

    public override void Commit(System.Collections.IDictionary savedState)

    {

        base.Commit(savedState);

    }

     

     

    ファイルの冒頭に以下を追加しておいてください。

    Code Snippet

    using System.IO;

    using System.Security.Principal;

    using System.Security.AccessControl;

    以下の文字定数FOLDER_NAMEは先ほどのフォルダの名前です。

    Commitを以下のように実装してください

    Code Snippet

    const string FOLDER_NAME = "AAAAA";

     

    public override void Commit(System.Collections.IDictionary savedState)

    {

        WindowsIdentity wi = WindowsIdentity.GetCurrent();

        WindowsPrincipal wp = new WindowsPrincipal(wi);

        if (wp.IsInRole(WindowsBuiltInRole.Administrator))

        {

            string dataFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), FOLDER_NAME); 

            DirectoryInfo di = new DirectoryInfo(dataFolderPath);

            SecurityIdentifier users_sid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);

            DirectorySecurity dsec = di.GetAccessControl();

            dsec.AddAccessRule(

                new FileSystemAccessRule(users_sid,

                FileSystemRights.Modify,

                InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,

                PropagationFlags.InheritOnly,

                AccessControlType.Allow));

            di.SetAccessControl(dsec);

        }

        base.Commit(savedState);

    }

     

    セットアッププロジェクトに戻り、「ファイルシステムエディタ」で先ほど作成したクラスライブラリプロジェクトの「プライマリ出力」を「アプリケーションフォルダ」追加しておきます。

    「カスタム動作エディタ」にて、「インストール」と「確定」のノードを右クリックして「カスタム動作の追加」で「アプリケーションフォルダ」から先ほどのクラスライブラリプロジェクトを選択してください。「インストール」と「確定」のそれぞれのノードの下にそれが現れます。

    これをビルドしてインストールすれば、AAAAA配下のファイルが、Usresのユーザでも「変更」できるようになると思います。

     

    あとは上記コードにあるキーワードをMSDNライブラリ等で参照して適切にカスタマイズしてみてください。

     

    TO:皆様、ツッコミお待ちしています…

    2008年2月19日 4:00

すべての返信

  • 外池と申します。

     

    直接の回答じゃなくて、申し訳ありませんが・・・、お使いになっている言語はなんでしょうか? もし、VBのように、My.Settingsが使えるのであれば、簡単に解決できる問題ですが・・・。

     

    2008年2月15日 9:06
  • 使用している言語はC#です

     

    よろしくお願いします

     

    2008年2月15日 9:13
  • 外池です。C#ですか。よかった。私がお答えする方法は、C#でも、VBでも共通です。

     

    で、まず、前提条件ですが、

     

    1) ご希望のフォルダーは使いません。

    2) アプリケーションそのものが直接管理する方式ですので、インストーラーで設定の保存の方式を確認することはできるかもしれませんが、変更は難しいと思います。

    3) Visual Studio 2005以降のC#です。

    4) 制限ユーザーも使えるかどうかは、未確認です。

     

    で、C#のアプリのプロジェクトで、ソリューションエクスプローラを見ると、Propertiesのフォルダーのようなものがありますよね?

     

    これをダブルクリックすれば、アプリケーション、ビルド、ビルドイベントなどのタブがある画面が現れるのはご存知だと思いますが、その中の設定のタブを使えば、アプリケーション全体の設定も、ユーザーごとの設定も、できます。プリミティブが型も保管できますし、オブジェクト(おそらく、シリアライズ可能なクラスのオブジェクトなのだと思う)であれば、状態を丸ごと保管することも可能です。

     

    前提条件が受け入れられるものであれば・・・、お役に立てると思います。

     

     

     

     

     

     

     

    2008年2月15日 9:27
  • なるほど、ここで記憶しておくことができるということですね!

    スコープ:ユーザー、アプリケーションの違いは何でしょうか?

    スコープをユーザーにすると、プログラムから書き換えられますが、アプリケーションにすると読み取り専用になってしまいます

    2008年2月15日 9:36
  • 外池です。

     

    初期値(ビルドしたときに最初に用意される値)は、特に、プリミティブ型の設定値であれば、ご覧頂いている設定画面でそのまま書き込めばOKです。

     

    で、アプリの中で読み出すときには、My.Settings.xxxxと、xxxxのところに設定画面で用いた「名前」をつけて、あと、適当に代入文にすれば、設定の読み出しも、設定の書き込みもできます。あとは、My.Settings.Saveとすれば保存できます。

     

    詳しくは、

    http://msdn2.microsoft.com/ja-jp/library/c9db58th.aspx

     

    ただ・・・、ドキュメントは、すべて、Visual Basicのドキュメント扱いになってますね。C#でも問題ないハズですが。

    2008年2月15日 9:47
  • 外池です。すいません、問題アリでした。

     

    訂正します。

     

    C#の場合は、Myは使えなくて、Properties.Settingsをつかって、しかも、インスタンスを用意するか、あるいは、Defaultを使うか。

    http://www.microsoft.com/japan/msdn/vs05/vcsharp/SettingsCS_RL.aspx

     

     

     

    2008年2月15日 9:57
  • 権限付与を行うインストーラクラスdllかexeを作成して、カスタム動作で呼び出すとかどうでしょうか。

    DirectoryInfoなどからDirectorySecurityオブジェクトを得てFileSystemAccessRuleオブジェクトを追加してDirectoryInfoに戻せばよいと思います。

    詳しくはMSDNライブラリをご参照ください。

     

    DirectorySecurity クラス
    http://msdn2.microsoft.com/ja-jp/library/system.security.accesscontrol.directorysecurity.aspx

    FileSecurity クラス

    http://msdn2.microsoft.com/ja-jp/library/system.security.accesscontrol.filesecurity.aspx

     

     

    2008年2月15日 9:57
  • >外池さま

    全ユーザーで共通の値を保持したいのですが、

    ユーザーごとの管理となってしまうようです。

    具体的に、値というのはそのアプリケーションで保存したファイル数です。

    ですので、それぞれのユーザーが保存したファイル数を検索して足すことによって

    その値を求めようと思うのですが、現在アプリケーションを実行しているユーザー以外の

    設定を取得することはできるのでしょうか?

    よろしくお願いします

    2008年2月15日 10:08
  • インストーラですよね?

    だと、残念ですが、設定方法はありません(自分でプログラム的に設定する以外の選択肢はない)。

     

    OS 的には、CSIDL_COMMON_DOCUMENTS(SHGetSpecialFolderPath API などで取得) が該当する場所ですので、Custom Actions(VSのカスタム動作ではない)を用いてセットアップすることは可能ですが、この場合、C/C++ でDLLを作る必要があり、その追加をVSセットアップ上から行うことができません(できないのは、VSセットアップの問題であって、WindowsInstallerの問題ではありません)。

     

    ORCAで変更するなど、ビルド後に面倒な処理を施せばできますが、あまりお勧めできません(ビルドコマンドにスクリプトで埋め込みするという方法もありますが...)。

     

    さて、インストーラ側はともかくとして、アプリケーション側ですが、該当フォルダを取り出すメソッドは .NET Framework には用意されていませんが、問題ありませんか?

     

    .NET Framework が用意している既定のフォルダで用意しているのは、System.Environment.SpecialFolder 列挙体 です。

    3.5 でも変わり映えしませんが、どちらにしても、該当フォルダはなく、すべてのユーザーで共有できるフォルダは、CommonApplicationData となります。

     

    もし、こちらのフォルダでも問題ないのであれば、WindowsInstaller としても同じフォルダを指定できます。

    ですが、VSセットアップはなぜか対応していません。

    そのため、VSセットアップで上記フォルダを指定したい場合は

    1. セットアッププロジェクトでファイルシステムビューを開く
    2. ツリーの対象コンピュータ上のファイルシステムで右メニューから特別なフォルダ->カスタム フォルダを作成
    3. 名前を適当なものにする(表示されるわけではないので、恥ずかしくない程度であれば何でもよい)
    4. DefaultLoation に[CommonAppDataFolder]をセット
    5. Property も同じ値(全部大文字になります)をセット(別の名称でもかまいません)

    という形で、間接的に設定します。

    実際にインストールしてみたわけではないので、本当にうまくいくかどうかは確認が必要ですが、ビルドしたmsiを見る限りではこれでセットアップできると思います。

    2008年2月15日 10:16
  • 外池です。

     

    スコープをApplicationにしても、ダメですか? すいません、ちょっと、自分でやってみます・・・

     

     

     

    2008年2月15日 10:18
  • 外池です。

     

    大変、お恥ずかしい。まったく勘違いしていました。Settingsだと、設定の保存は、ユーザーごとになってしまうようですね。申し訳ない。私の申し上げたアプローチはダメっぽいです。

     

    制限ユーザー、というのが、具体的にどのような権限しかないのか・・・。要するに、一般のUserグループのアカウントのひと?

     

    すいません、他の回答者の方のご提案の線も、検討してみてください・・・。私ももう少し考えて見ます。

    2008年2月15日 10:31
  • 外池です。申し訳ありません。わたしも、とっちゃん様と同じ意見になりました。

     

    私なら・・・、インストーラーで設定してやるよりも、アプリで、初回起動時に、独自のフォルダーを探しにいって、なければ、設定保存用のフォルダーを作って、かつ、設定用のファイルを書き出してやります。

     

    では、「独自のフォルダーをどこに置くか?」となれば、

      アプリ自身が存在する場所(Program Filesの下のどこか)か、あるいは、

      Documents and Settings\All Users\Application Dataのどこかか、

    という感じになるでしょう。どちらも、管理者でなくても、Userは、ファイルの作成・書き込みと、フォルダーの作成・データの追加が許可されています。

     

    ・・・・、うーん、ファイルの上書き保存は、OKなのでしょうか。(今、断言できません・・・。どなたか、ヘルプ)

     

     

    2008年2月15日 10:52
  • >とっちゃん様,外池様

     

    教えていただいた方法で、Documents and Settings\All Users\Application Dataに設定ファイルをインストールすることができました!

    しかし、試してみたところ、制限ユーザーではこのファイルを更新(上書き保存)することができないようです・・・

     

    制限ユーザーでもファイルを更新可能な共有のフォルダはないのでしょうか?

     

    よろしくお願いします。

    2008年2月15日 10:58
  •  外池 さんからの引用

      Documents and Settings\All Users\Application Dataのどこかか、

    という感じになるでしょう。どちらも、管理者でなくても、Userは、ファイルの作成・書き込みと、フォルダーの作成・データの追加が許可されています。

     

    ・・・・、うーん、ファイルの上書き保存は、OKなのでしょうか。(今、断言できません・・・。どなたか、ヘルプ)

     

    >All Users\Application Data

     

    既定では既存ファイルの変更ができないんですよ…

     

    過去スレッド「アプリケーション設定情報の保存場所」

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2548032&SiteID=7

    2008年2月15日 11:01
  • IIJIMASさま

     

    情報ありがとうございます。

    All Users/Documentsならばファイルの更新ができるのでしょうか?

    しかしここへはファイルのインストール方法がわからないので、初回起動時に作成ということになりますかね。

    ということは、アンインストール時にファイルが削除されない。。。

     

    どこか妥協しなければ、やはり全ユーザー共通というのは無理なのでしょうか・・・?

     

    2008年2月15日 11:15
  • あら、だめなんだ。となると、アプリレベルで場所を決めてということになりますねぇ...

     

    ところで、All Users\Application Data に「サブフォルダ」を用意すれば大丈夫とかありませんか?

    #Application Data のフォルダとそのサブフォルダではアクセス権が異なるかもしれません

    2008年2月15日 11:19
  • 「All Users\Application Data\アプリケーション名」とフォルダを作成して実行してみましたが、

    ファイルの更新はできませんでした・・・

    2008年2月15日 11:23
  •  あいこ さんからの引用

    「All Users\Application Data\アプリケーション名」とフォルダを作成して実行してみましたが、

    ファイルの更新はできませんでした・・・

    たしかDocumentsも同じだったと思います。

     

    >「All Users\Application Data\アプリケーション名」

     

    場所はそこでよいと思います。

    インストールの時にUsersグループか特定のユーザにそのフォルダやファイル変更権限を与えるのはどうでしょうか。

    たとえば、ベストかどうかわかりませんが私がこのスレッドで最初に書き込んだ方法があると思います。
    2008年2月15日 11:32
  • "All Users\Application Data"や"All Users\Documents"は、「ファイルを作った人が、そのファイルを他の人に見せるためのフォルダ」というような位置付けなので、この中に、上位からのアクセス権を継承したフォルダやファイルを作ると、おおざっぱに言って、「ファイルの所有者(≒作成者)とAdministratorsがフルコントロール、それ以外の人が読み取り専用」というアクセス権が設定されます(所有者であれば、制限ユーザーであっても書き込み可です)。で、参考になるであろう"All Users\Application Data\Microsoft"のアクセス権を見てみると、上位フォルダからは継承せず、直接設定してあります(All Users\Application Data\Microsoft\Dr Watsonなんかだと、Everyoneフルコントロールだったりします)。

    ということで、設定ファイルを置くために、"All Users\Application Data"の中にアプリケーション名でフォルダを作り、このフォルダのアクセス権を、アプリケーションのポリシーにあわせて設定するというのが順当なのではないかと思います。

    2008年2月15日 20:29
  • >IIJIMASさま

    メッセージありがとうございます。

    初めに教えていただいた方法ですが、私まだまだ初心者のため具体的にどのようなコードをかけばそれが実現できるのかがまだ理解できておりません・・・

    教えていただいたMSDNライブラリを参考にしてもう少し調べてみます!

     

    >佐伯浩介さま

    メッセージありがとうございます。

    フォルダのアクセス権をアプリケーションから設定する方法はわかるのですが、

    インストール時のフォルダ作成時に設定する方法がわかりません・・・

    インストールは管理者権限で行われるので、インストール後に、作成したフォルダのアクセス権を変更するような処理をはしらせればよいのでしょうか?

     

    よろしくお願いします。

    2008年2月16日 6:20
  •  あいこ さんからの引用

    フォルダのアクセス権をアプリケーションから設定する方法はわかるのですが、

    インストール時のフォルダ作成時に設定する方法がわかりません・・・

    インストールは管理者権限で行われるので、インストール後に、作成したフォルダのアクセス権を変更するような処理をはしらせればよいのでしょうか?

    VSセットアップでしたよね?

    残念ながら、VSセットアップでは、アクセス権の設定項目が用意されていません。
    #おそらく大半のインストール作業で必要とされないからだとは思いますが...

     

    WindowsInstallerとしては、LockPermissions Table でアクセス権の設定ができるようにはなっています。

    ただ、その知識レベルが、Native API でのOS設定が可能な知識レベルという非常にハードルの高いものとなっているので、実際に利用するとなるとかなり厳しいかもしれません。

     

    その上、ORCAなりで後付けしないとだめですし...

     

    2008年2月18日 5:36
  •  あいこ さんからの引用

    初めに教えていただいた方法ですが、私まだまだ初心者のため具体的にどのようなコードをかけばそれが実現できるのかがまだ理解できておりません・・・

    教えていただいたMSDNライブラリを参考にしてもう少し調べてみます!

    私が言おうとしていたやり方は…

    対象マシンに.NETが入っている前提とします。(入っていなければ事前に入れるか、「必須コンポーネント」としてセットアップに含められます。)

     

    以下はすでに試されてるかとは思いますが…

    セットアッププロジェクトのファイルシステムエディタで「対象コンピュータ上のファイルシステム」を右クリックしてコンテクストメニューで「特殊フォルダの追加」で「カスタムフォルダ」を追加しそれを選択して

    プロパティウィンドウのDefaultLocationで[CommonAppDataFolder]と入力してください。

    そこにさらにサブフォルダを追加します。名前をAAAAAとします。これがアプリケーションデータファイルを入れるフォルダです。

    必要ならばファイルや更なるサブディレクトリを追加してください。

     

    同じソリューションにクラスライブラリプロジェクトを作成します。Class1.csは消してください。

    そのプロジェクトを右クリックしてコンテクストメニューで「追加」「コンポーネント」を選択します。

    「新しい項目の追加」ダイアログで「インストーラクラス」を選択して「追加」して下さい。たとえば名前をMyInstallerとします。

    コードビューでそれを表示します。

    public partial class MyInstaller : Installerの{}なかで

    public overrideと入力しスペースを押すとIntelliSenseによっていくつかメソッドが表示されます。

    このうち、InstallとCommitを選択してください。

    Code Snippet

    public override void Install(System.Collections.IDictionary stateSaver)

    {

        base.Install(stateSaver);

    }

    public override void Commit(System.Collections.IDictionary savedState)

    {

        base.Commit(savedState);

    }

     

     

    ファイルの冒頭に以下を追加しておいてください。

    Code Snippet

    using System.IO;

    using System.Security.Principal;

    using System.Security.AccessControl;

    以下の文字定数FOLDER_NAMEは先ほどのフォルダの名前です。

    Commitを以下のように実装してください

    Code Snippet

    const string FOLDER_NAME = "AAAAA";

     

    public override void Commit(System.Collections.IDictionary savedState)

    {

        WindowsIdentity wi = WindowsIdentity.GetCurrent();

        WindowsPrincipal wp = new WindowsPrincipal(wi);

        if (wp.IsInRole(WindowsBuiltInRole.Administrator))

        {

            string dataFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), FOLDER_NAME); 

            DirectoryInfo di = new DirectoryInfo(dataFolderPath);

            SecurityIdentifier users_sid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);

            DirectorySecurity dsec = di.GetAccessControl();

            dsec.AddAccessRule(

                new FileSystemAccessRule(users_sid,

                FileSystemRights.Modify,

                InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,

                PropagationFlags.InheritOnly,

                AccessControlType.Allow));

            di.SetAccessControl(dsec);

        }

        base.Commit(savedState);

    }

     

    セットアッププロジェクトに戻り、「ファイルシステムエディタ」で先ほど作成したクラスライブラリプロジェクトの「プライマリ出力」を「アプリケーションフォルダ」追加しておきます。

    「カスタム動作エディタ」にて、「インストール」と「確定」のノードを右クリックして「カスタム動作の追加」で「アプリケーションフォルダ」から先ほどのクラスライブラリプロジェクトを選択してください。「インストール」と「確定」のそれぞれのノードの下にそれが現れます。

    これをビルドしてインストールすれば、AAAAA配下のファイルが、Usresのユーザでも「変更」できるようになると思います。

     

    あとは上記コードにあるキーワードをMSDNライブラリ等で参照して適切にカスタマイズしてみてください。

     

    TO:皆様、ツッコミお待ちしています…

    2008年2月19日 4:00
  • >IIJIMASさま

     

    ありがとうございます!!

    丁寧に教えていただいたおかげで、希望していた動作が実現できました

     

    これですべて解決しました。

    本当にありがとうございました

    2008年2月19日 5:24