none
AccessDBファイルの格納場所について RRS feed

  • 質問

  • WinXP用に作成された32ビットのアプリです。C\myDataと言うフォルダーを作成し、この中に、myAccessDB.accdbファイルを置いてあります。ADODBでVB.NETプログラムから使用します。参照パスは固定で”C\myData\myAccessDB.accdb”という簡単な方法です。この条件で、WinXP、Win7(32)、Win7(64)、WinServer2008R2(64)のOSに対応できるデータフォルダーを探しております。
    ユーザーの方がファイルエクスプロラーでファイルコピーしたいと言う条件がありますので、パスは短く固定位置が喜ばれます。LIは、高、中、低を問わず書込めないと困ります。「C:\Users\myData」が良いのではと思いましたが、WinServer2008R2、WinXPで通用してもWin7(32)では無理でした。このようなケース、皆様は、どのようにお考えでしょうか?

    2011年1月13日 14:57

回答

  • ClickOnceで配置後、アプリケーションが起動する度に、ある特定のフォルダ、例えばC:\Users\myDataにmdbがあるかどうかをチェックし、無い場合はそこにコピーするようにしてはダメでしょうか? すなわち、ClickOnceでmdbを配置するのではなく、アプリケーションでmdbを配置してみてはいかがでしょうか?

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年1月26日 0:19
    モデレータ

すべての返信

  • どのフォルダーにどういったファイルを配置すべきかについての指針がありますので、それに乗っかるのが良いかと。

     リソースの管理 - Windows 7 対応アプリケーションの互換性
     http://msdn.microsoft.com/ja-jp/windows/dd882533.aspx
    2011年1月14日 1:31
  • よく理解していないので的外れなことを言っているかもしれませんが、「パスは短く固定位置が喜ばれます。」ということであれば、”C\myData\myAccessDB.accdb”でいいような気がするのですが、なぜダメなのでしょうか? あと、ごめんなさい、LIが何を指しているのかわかりませんでした。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年1月14日 1:31
    モデレータ
  • totojoさん、trapemiyaさん、どうもありがとうございます。

    色々な作法があり、何がベストか躊躇している状況です。(資料リンクありがとうございます)
    一番簡単で、良いと考えたのが『”C\myData\myAccessDB.accdb”』の方法です。ところが罠があるのです。
    WinXPとWin7(32)で、AdministratorとUsersの権限でログイン、正常に読み書きができます。よし、よし
    と、WindowsServer2008R2で、同様に試験、これもAdministrator権限でログイン、正常に読み書きできます。
    困ったのは、Usersの権限でログイン、正常に読めますが、書き込みが出来ない状況です。
    WindowsServer2008R2では、『”C\Users\myData\myAccessDB.accdb”』とするとどの権限でも読み書きできます。
    しかし、Win7(32)では、ファイルエクスプロラーで、『”C\Users\myData』フォルダーすら出来ません。
    VistaとWin7(64)では試験しておりませんが、固有の事情がありそうです。

    >LIとは何?
    これ逆でした。整合性レベル Integrity Level(IL) アクセスを制御するメカニズム (どう変わるWindows7&Vistaのアプリケーション開発.pdf NECラーニング MVP 山崎 明子氏 作成資料より) Liでは意味不明でした。申し訳ございませんでした。

    >リソースの管理 - Windows 7 対応アプリケーションの互換性
    作法に従うと、メソッドでフォルダーのパスを取得し、固定パスは使用してはならないと言う事ですか?プログラム改造が大変そうです。

    2011年1月14日 9:45
  • WindowsServer2008R2だけうまくいかないというのはUsersグループに実行権限が付与されていないからでしょうか?
    であれば、インストーラーに関してはあまり詳しくないのですが、Visual Studioのセットアッププロジェクトを使用されているのであれば、カスタム動作でうまくできるかもしれません。また、WindowsServer2008R2のセキュリティに関しても詳しくありませんので、この方面の話になると私にはわかりません。ごめんなさい。
    LIに関しては了解しました。

    (参考)
    Visual Studioセットアッププロジェクトのカスタム動作
    http://jehupc.exblog.jp/9073239/

    【VB.NET】ファイルのアクセス権限を変更する
    http://blog.livedoor.jp/akf0/archives/51465450.html

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年1月14日 16:15
    モデレータ
  • Windowsはマルチユーザーで使用できます。

    質問内容を読みましたが、Windowsに複数のユーザーがログオンした際、このデータベースはどのようなふるまいをすべきなのでしょうか?

    • 同じPCを使用する他の人のデータが参照できる
    • 各人のデータが分離されて管理される(各人ごとにデータベースファイルが用意される)
    • 各人のデータが分離されている(データベース内でログオンユーザーごとにデータが管理されている)
    • このアプリケーションを使用する場合には、複数の人がWindowsを使用してはいけない
    などのバリエーションがあり、それぞれに適切な配置場所があります。
    2011年1月15日 1:00
  • trapemiyaさん、佐祐理さん、こんにちは
    遅くなりました。私、本物のノロウイルスやられたようで力が入りません。
    ごめんなさい。昔から、セキュリティの問題は頭が痛いです。

    ご参考リンクありがとうございます。
    やはり、何か、工夫しないと往けないのかなぁと考え出しました。

    単独か、複数アクセスでは、一人で使用する条件でと思っております。

    チュートリアル : 異なるローカル フォルダへのドキュメントとアセンブリの配置
    http://msdn.microsoft.com/ja-jp/library/ms404838(v=VS.80).aspx

    このあたりを眺めますと、『コード アクセス セキュリティ ポリシー ツール (Caspol.exe)』
    などでも良いのか?

    チュートリアル : ローカル フォルダへのドキュメントとアセンブリの配置
    チュートリアル : ローカル フォルダへのドキュメントの配置とネットワーク フォルダへのアセンブリの配置
    チュートリアル : ネットワーク フォルダへのドキュメントとアセンブリの配置
    チュートリアル : 配置マニフェストを使用したドキュメント レベルのカスタマイズの配置
    チュートリアル : Windows インストーラ ファイルを使用したドキュメント レベルのカスタマイズの配置
    など、など、「ClickOnce の配置の概要」から始めないと、ブツブツ。

    ■特別なフォルダとカスタム フォルダ
    http://msdn.microsoft.com/ja-jp/library/s2esdf4x(VS.80).aspx

    1)共通ファイル フォルダ  通常は C:\Program Files\Common。
    2)ユーザーの個人データ フォルダ C:\Documents and Settings\username\My Documents。
    3)ユーザーのアプリケーション データ フォルダ C:\Documents and Settings\username\Application Data。
     
    この辺りの利用であれば、何も考えなくても上手くアクセス出来るのであれば、無難と言うことでしょうか?

    2011年1月19日 4:02

  • ●AccessDB.mdbのお手軽な配置場所は何処でしょうか?

    【普通の手順のつもり】
    VisualStudio2008でAccessDB.mdbを配置するには、ソリューションエクスプローラで、プロジェクト名(上から2番目)
    を選びマウス右クリックで追加より、既存の項目でAccessDB.mdbを追加した。発行したクライアント用アプリのインストール
    場所を利用する事にしました。

    <AccessDB.mdbのプロパティ操作>
    ビルド:コンテンツ
    出力:新しい場合はコピーする

    <AccessDBDataSet.xsdのプロパティ操作>
    ビルド:なし
    出力:常にコピーしない

    ※ AccessDB.mdbのプロパティで、出力:常にコピーするに設定すると、プログラムで、AccessDB.mdbにデータを追加しても、データは初期状態になるよです。

    その後、発行し、インストールすると下記状態となります。

    C:\Documents and Settings\ユーザ名\Local Settings\Apps\2.0\R0RLZOVK.5TG\LH0OMEM1.5VP
    \プログラム名.exe_31d2d089f59a6e7e_0003.0000_none_c911156ad50e6424

    <配置ファイル>
    プログラム名.exe.config
    AccessDB.mdb
    プログラム名システム仕様書.pdf

    C:\Documents and Settings\ユーザ名\Local Settings\Apps\2.0\R0RLZOVK.5TG\LH0OMEM1.5VP\
    \プログラム名_31d2d089f59a6e7e_0003.0000_00f1839504c53392

    <配置ファイル>
    プログラム名.cdf-ms
    プログラム名.exe
    プログラム名.exe.cdf-ms
    プログラム名.exe.config
    プログラム名.exe.manifest
    プログラム名.manifest
    プログラム名.txt
    プログラム名システム仕様書.pdf

    おおよそ、上記のような状態で、クライアントアプリがインストールされております。
    こんな理由で、お客様に、『AccessDB.mdbを入れ替えて下さい』と簡単に言えないので
    簡単なツールを作成して、AccessDB.mdbを入れ替えればとも思います。


    ●インストーラで配置されたパスをプログラムで取得する方法はあるのでしょうか?

    アプリケーション設定情報はどこに保存すべきか?
    http://www.atmarkit.co.jp/fdotnet/dotnettips/263apppath/apppath.html

            private void button1_Click(object sender, EventArgs e)
            {
                string myFolderA, myFolderB, myFolderC, myFolderD, myFolderE, myFolderF, myFolderG;
                myFolderA = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                myFolderB = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData );
                myFolderC = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData );
                myFolderD = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                myFolderE = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);
                myFolderF = System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                myFolderG = System.Environment.GetFolderPath(Environment.SpecialFolder.Programs);

                MessageBox.Show(myFolderA + "\n" + myFolderB + "\n" + myFolderC + "\n" + myFolderD + "\n"
                                                 + myFolderE + "\n" + myFolderF + "\n" + myFolderG );
            }

    上記情報で、『C:\Documents and Settings\ユーザ名\Local Settings』この辺までは、取得できます。また
    『AppDomain.CurrentDomain.BaseDirectory + "..\\..\\App.config"』や
    『AppDomain.CurrentDomain.SetupInformation.ConfigurationFile』の方法も使えるかも知れません。

    ●AccessDB.mdbを配置してもタスクスケジューラから起動したい。
    データ用と実行形式で、配置パスが分離されると、タスクスケジューラがプログラム名.exeを直接起動する為
    AccessDB.mdbにアクセスできなくなる。(インストール後、手動で、AccessDB.mdbをEXEのある方に複写)

    まだ、非常に泥臭い状況です.

    • 編集済み 電子の妖精 2011年1月25日 10:02 記述ミスを訂正
    2011年1月25日 7:55
  • ClickOnce (プロジェクトのプロパティの [発行] タブ) でなくて、別にセットアップ プロジェクトを作るべきではないかと。
    複数のログオン ユーザーから同一の Access DB ファイルを使用したいのですよねぇ。
    2011年1月25日 8:06
  • totojoさん、こんばんは!

    ClickOnceの複雑さには、頭が痛いです。totojoさんのおっしゃるとうりで、単純なインストール方法があれば便利な気が致します。

    >複数のログオン ユーザーから同一の Access DB ファイルを使用したいのですよねぇ。
    このあたりの事もあるのですが、取り敢えずは、最もシンプルに一人のログオンユーザーですが、AccessDBファイルをAccess2007を使用して自分で編集したいなどのご要望がございます。

    自作プログラムとAccess2007でAccessDBファイルを共有すると言ったほうが良いのかもしれません。(もちろん同時にアクセスする事はないです)

    何か良いアイディアはないでしょうか?

    2011年1月25日 10:16
  • ClickOnceで配置後、アプリケーションが起動する度に、ある特定のフォルダ、例えばC:\Users\myDataにmdbがあるかどうかをチェックし、無い場合はそこにコピーするようにしてはダメでしょうか? すなわち、ClickOnceでmdbを配置するのではなく、アプリケーションでmdbを配置してみてはいかがでしょうか?

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年1月26日 0:19
    モデレータ
  • 大分遅くなりましたが、trapermiyaさん、どうもありがとうございました。
    お許しください。お陰様で、上手く出来ました。まだ、簡単な試験しかしておりませんが
    Win7(32)、Win2008ServerR2の、AdministratorとUser共に正常に動作しました。

    <作成方法>
    AccessDB.accdbをプロジェクトのソースのフォルダー位置へ複写する。
    既存ファイルの追加で、プロジェクトに入れ、「コンテンツ」、「新規は複写する」
    と設定すれば、データセットも自動作成され、パッケージに含まれる。
    Form1に、DataGredViewを張り付け、データーソースを設定など、手順どうりに
    進めます。更に、Form1_Load()に下記コードを追加し、発行する。
    (64ビット環境では、コンパイルのターゲットCPUはx86に設定する)

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Xml;
    using System.Security.AccessControl;
    
    namespace AccessDBArrange
    {
     public partial class Form1 : Form
     {
      public Form1()
      {
       InitializeComponent();
      }
    
      private void Form1_Load(object sender, EventArgs e)
      {
       //==========================
       //--- AccessDBを格納する ---
       //==========================
    
       //===============================================================================================
       //=== ローカル位置に、格納先データフォルダーパスを組み立てる         ===
       //=== 結果:正常に読み書きが行える。但し、Win7では、エクスプロラーではファイルを見れない ===
       //===============================================================================================
       //string dstFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
       //string myCompanyName ="BigMouth";
       //string mySoftName ="AccessDBArrange";
       //dstFolder += "\\" + myCompanyName + "\\" + mySoftName;
    
    
       //===============================================================================================
       //=== 任意の位置に、格納先データフォルダーパスを組み立てる          ===
       //===============================================================================================
       string dstFolder = "c:\\";
       string myCompanyName = "BigMouth";
       string mySoftName = "AccessDBArrange";
       dstFolder += "\\" + myCompanyName + "\\" + mySoftName;
    
       // インストールしたプログラムのパスを取得する
       string srcFolder = AppDomain.CurrentDomain.BaseDirectory;
     
       // アクセスDBのファイル名を指定する
       string accdbFile = "AccessDB.accdb";
    
       // 格納先にAccessDB.accdbが存在するか?
       if (File.Exists(dstFolder + "\\" + accdbFile) != true)
       {
        //フォルダーを作成する
        Directory.CreateDirectory( dstFolder );
    
        // 属性を設定する(RD&WD 許可)但し、ローカル位置では設定しないこと。
        SetAttrib( dstFolder );
    
        //ファイルを複写する
        File.Copy( srcFolder + "\\" + accdbFile, dstFolder + "\\" + accdbFile );
    
       }
    
       //========================================
       //--- AccessDB DataSetのパスを変更する ---
       //========================================
       string strConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
            dstFolder + "\\" + accdbFile + ";Persist Security Info=True";
    
       SetConnectionStrings(strConnect);
    
       // TODO: このコード行はデータを 'accessDBDataSet.テーブル1' テーブルに読み込みます。
       // 必要に応じて移動、または削除をしてください。
       this.テーブル1TableAdapter.Fill(this.accessDBDataSet.テーブル1);
    
      }
    
      /// <summary>
      /// 接続文字列を更新する
      /// </summary>
      /// <param name="strConnect"></param>
      private void SetConnectionStrings(string strConnect)
      {
       string appConfigPath = null;
    
       appConfigPath = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    
       System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
    
       // xxxx.exe.config.deployを読出す。
       doc.Load(appConfigPath);
    
       foreach (System.Xml.XmlNode n in doc["configuration"]["connectionStrings"])
       {
        // 更新する
        XmlElement newElement = doc.CreateElement("add");
        newElement.SetAttribute("name", "AccessDBArrange.Properties.Settings.AccessDBConnectionString");
        newElement.SetAttribute("connectionString", strConnect);
        newElement.SetAttribute("providerName", "System.Data.OleDb");
        doc["configuration"]["connectionStrings"].ReplaceChild(newElement, n);
       }
    
       // App.config 更新する
       doc.Save(AppDomain.CurrentDomain.BaseDirectory + "..\\..\\App.config");
    
       // xxxxx.exe.config.deploy を更新する。
       doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
      }
    
      /// <summary>
      /// ファイルとパスの属性を設定する(参照『全ては時のなかに』)
      /// </summary>
      /// <param name="path"></param>
      private void SetAttrib(string path)
      {
    
       FileInfo FileInfo = new System.IO.FileInfo(path);
       try
       {
        FileSecurity FileSec = null;
        FileSec = FileInfo.GetAccessControl();
    
        // アクセス権限を指定
        // Everyoneに対し、フルコントロールの許可
        //(サブフォルダ、及び、ファイルにも適用)
        FileSystemAccessRule AccessRule = new FileSystemAccessRule("Everyone",
               FileSystemRights.FullControl, AccessControlType.Allow);
    
        FileSec.AddAccessRule(AccessRule);
        FileInfo.SetAccessControl(FileSec);
       }
       catch (Exception ex)
       {
        MessageBox.Show(ex.Message);
       }
      }
     
      private void テーブル1BindingNavigatorSaveItem_Click(object sender, EventArgs e)
      {
       this.Validate();
       this.テーブル1BindingSource.EndEdit();
       this.tableAdapterManager.UpdateAll(this.accessDBDataSet);
      }
     }
    }
    2011年2月1日 16:39