web-dev-qa-db-ja.com

32ビットおよび64ビットのC#の世界でSystem.Data.SQLiteを使用するためのオプション

System.Data.SQLite.dllが32ビットおよび64ビットのビルドで提供される理由を理解しています。だから、それにこだわって先に進まないようにしましょう。 :)

このように行われるため、純粋なC#開発は、3つの選択肢があるため少し難しくなるようです。

  1. 32ビットのみをサポートし、管理されたアセンブリにx86をコンパイルして、32ビットまたは64ビットでの実行時にそれを処理するように強制することです。これにより、64ビット環境を使用している場合の利点が失われます。

  2. 64ビットを強制し、64ビットのみをサポートし、32ビットで実行する機能を失いますが、64ビットのすべての利点を得ることになります。

  3. 1つはx86をコンパイルして32ビットSQLiteを使用し、もう1つはx64をコンパイルして64ビットSQLiteを使用するアセンブリの2つのバージョンを作成することです。これにより、コンパイルオプションとして「ANY」を使用できなくなり、単一のビルドをどちらのタイプにも簡単にデプロイできなくなります。 2つのプロジェクトが必要になるため、開発の観点から管理するのはそれほどひどいことではありません。一方にはC#コードのみが公式に含まれ、もう一方にはもう一方のコードへの「リンク」が使用されます。これはコンパイルのみを目的としています。それでも、展開のために2つの出力を管理する必要があります。

とはいえ、私は上記が唯一の正しい選択であるという確認を探しているだけです。

しかし、私が見落としている他の選択肢がある場合は、私に知らせてください。具体的には、任意の場所にコンパイルできる単一のC#DLLを取得する方法がある場合は、実行場所に応じて32ビットまたは64ビットを利用し、System.Data.SQLite.dllを引き続き使用できます。 。

21
Rodney S. Foley

メインアプリケーションをAnyCPUに保持するための2つの一般的なソリューションがあります。

  • X86アセンブリとx64アセンブリの両方をGACにインストールします。これらは同じアセンブリ名を持つことができ(必要です!)、GACはx86バージョンとx64バージョンのどちらを使用するかを自動的に決定します。

  • AppDomain.AssemblyResolve にフックし、 Assembly.LoadFrom を使用してサブディレクトリから適切なアセンブリを提供します

14
springy76

これはSpringy76からの回答の詳細です。これを行う:

public class AssemblyResolver
{
    public static void HandleUnresovledAssemblies()
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.AssemblyResolve += currentDomain_AssemblyResolve;
    }

    private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (args.Name == "System.Data.SQLite")
        {
            var path = Path.Combine(pathToWhereYourNativeFolderLives, "Native");

            if (IntPtr.Size == 8) // or for .NET4 use Environment.Is64BitProcess
            {
                path = Path.Combine(path, "64");
            }
            else
            {
                path = Path.Combine(path, "32");
            }

            path = Path.Combine(path, "System.Data.SQLite.DLL");

            Assembly assembly = Assembly.LoadFrom(path);
            return Assembly;
        }

        return null;
    }
}

生成されたパスが、32ビットまたは64ビットのSQLiteDLLの正しい場所を指していることを確認してください。個人的には、このNuGetパッケージの結果で良い結果が得られました: http://www.nuget.org/packages/SQLitex64

(コンパイルされたSQLite Dllを取得するには、NuGetパッケージを使用するだけで済みます。取得したら、NuGetによって作成されたプロジェクト内のSQLiteへの参照とNuGetパッケージ自体を削除します。実際、参照をそのままにしておくと、 SQLiteが未解決のアセンブリとして認識されることはないため、このソリューションに干渉します。)

できるだけ早く、できればブートストラップ中に「HandleUnresolvedAssemblies()」を呼び出します。

21
Holf

同様の問題は、ネイティブの32/64ビットOCIDLLに対してOracleのODP.NETにも存在します。

プロジェクトの「x86」プラットフォームと「x64」プラットフォームの両方を作成し、条件付き参照を使用するようにプロジェクトファイルを手動で編集することで、これを解決しました。

<Choose>
<When Condition="'$(Platform)' == 'x64'">
  <ItemGroup>
    <Reference Include="Oracle.DataAccess, processorArchitecture=x64">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\ThirdParty\ODP.NET\x64\Oracle.DataAccess.dll</HintPath>
    </Reference>
    <Content Include="..\ThirdParty\ODP.NET\x64\oci.dll">
      <Link>oci.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x64\orannzsbb11.dll">
      <Link>orannzsbb11.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x64\oraociei11.dll">
      <Link>oraociei11.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x64\OraOps11w.dll">
      <Link>OraOps11w.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</When>
<When Condition="'$(Platform)' == 'x86'">
  <ItemGroup>
    <Reference Include="Oracle.DataAccess, processorArchitecture=x86">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\ThirdParty\ODP.NET\x86\Oracle.DataAccess.dll</HintPath>
    </Reference>
    <Content Include="..\ThirdParty\ODP.NET\x86\oci.dll">
      <Link>oci.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x86\orannzsbb11.dll">
      <Link>orannzsbb11.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x86\oraociei11.dll">
      <Link>oraociei11.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="..\ThirdParty\ODP.NET\x86\OraOps11w.dll">
      <Link>OraOps11w.dll</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</When>
</Choose>

これにより、2つの異なるプロジェクトの使用を回避できました。 SQLiteでも同様のことができると確信しています。

6

2つのプロジェクトが必要になるため、開発の観点から管理するのはそれほどひどいことではありません。

それは真実ではありません-同じプロジェクト内で2つのビルド構成を使用できます。展開時には、x86とx64の両方をビルドする必要がありますが、コードベースおよびプロジェクトは同じにすることができます。

私は現在、SQLiteだけでなく、x64およびx86バリアントを含む他のネイティブ/相互運用ライブラリも原因で、より大規模な本番プロジェクトでこれを行っています。

3
Reed Copsey

Branko Dimitrijevic氏は、「SQLiteでも同様のことができると確信しています」と述べています。そしてそれは正しいです。 :)

まったく同じ問題を抱えていたので、ロドニーの質問とブランコの答えを見つけて、自分で試してみました。私の動作するSQLiteの実装を見たい人は、次のようにします。

<Choose>
  <When Condition="'$(Platform)' == 'x64'">
    <ItemGroup>
      <Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64">
        <SpecificVersion>False</SpecificVersion>
        <HintPath>System.Data.SQLite\x64\System.Data.SQLite.dll</HintPath>
      </Reference>
    </ItemGroup>
  </When>
  <When Condition="'$(Platform)' == 'x86'">
    <ItemGroup>
      <Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64">
        <SpecificVersion>False</SpecificVersion>
        <HintPath>System.Data.SQLite\x86\System.Data.SQLite.dll</HintPath>
      </Reference>
    </ItemGroup>
  </When>
</Choose>

<ItemGroup>
  <Reference Include="Microsoft.CSharp" />
  <Reference Include="System" />
  <Reference Include="System.configuration" />
  <Reference Include="System.Core" />
  <Reference Include="System.Windows.Forms" />
  <Reference Include="System.Xml.Linq" />
  <Reference Include="System.Data.DataSetExtensions" />
  <Reference Include="System.Data" />
  <Reference Include="System.Xml" />
</ItemGroup>

もちろん、HintPathには好きな名前を付けることができます。

これが完璧なソリューションであることがわかりました。単一のプロジェクトを維持し、必要に応じてターゲットプラットフォームをすばやく切り替えることができます。唯一の潜在的な欠点は、ソリューションエクスプローラーにリファレンスが表示されないことです。しかし、それは全体的な機能に対して支払うための小さな代償です。

2
Charlie Hills

通常、アプリが4 GBを超えるメモリを必要としない限り、オプション1が最適です。 64ビットOS上の32ビットアプリには、多くの欠点がなくても、64ビットのほとんどの利点があることを忘れないでください。これが、VS2010の.exeアプリのデフォルトのターゲットがx86である理由です。

2
Ben Robinson

Visual Studioのコンパイルオプションを変更することで、これを解決することもできます。

Visual Studioでコンパイル設定を変更するには:

  1. プログラムのスタートアッププロジェクトに移動します。
  2. プロパティウィンドウを開きます。
  3. [コンパイル]タブをクリックします。
  4. 高度なコンパイルオプションをクリックします。
  5. ターゲットCPUオプションをx86に変更します。

これで、64ビットマシンで実行している場合でも、プログラムは常に32ビットモードで実行されます。

上記のように、環境ごとに1つずつ、合計2つのディストリビューションを提供することもできます。これは将来的に標準になるでしょうが、私の現在のプロジェクトでは、これが最良で最も簡単なオプションでした。

0
synctwok