web-dev-qa-db-ja.com

SQL Server Compact Edition 4.0を展開する方法は?

Microsoft SQL Server Compact 4.0 を展開するにはどうすればよいですか?


SQL Server Compact Edition(現在のバージョン4.0)は次のとおりです。

ソフトウェア開発者がWindowsデスクトップアプリケーションの構築に使用できる無料の組み込みデータベース。フットプリントが小さく、アプリケーションフォルダ内のバイナリのプライベート展開をサポートします。

しかし、実際にどのように展開しますか?

問題は、登録されていない限り、ADO OLEdbプロバイダーを使用できないことです。OLEdbプロバイダーの登録は、管理者として行う必要があります。つまり、SQL Server Compactエディションは、管理者ではありません。

SQL Server Compact 4.0には、redist_enu.txtファイルが付属しています。

リストされた.exeファイルはそれぞれ、同封のコンポーネントをインストール先コンピューターの特定の場所にインストールします。これにより、保守性と技術サポートが保証されます。これらの.exeファイルに含まれている.dllファイルも、このredist.txtで個別に入手できます。ただし、これらの個別の.dllを配布すると、保守性の問題が発生する場合があります。詳細については、 http://go.Microsoft.com/fwlink/?LinkId = 94589 をご覧ください。

BreadCrumbによるプライベート展開の検出:ネイティブスタックのみのプライベート展開、Assembly.LoadFrom()、. localファイル、またはDLL/COMリダイレクト戦略の使用によるSQL Server Compactアセンブリの明示的な読み込みはサポートされておらず、保守性の問題が発生する可能性があります。詳細については、 http://support.Microsoft.com/kb/835322 および http://msdn2.Microsoft.comを参照してください。 /en-us/library/aa375142.aspx

Microsoft SQL Server Compact 4.0

SSCERuntime_x86-ENU.exe
SSCERuntime_x86-DEU.exe
SSCERuntime_x86-FRA.exe
SSCERuntime_x86-JPN.exe
SSCERuntime_x86-RUS.exe
SSCERuntime_x86-ESN.exe
SSCERuntime_x86-ITA.exe
SSCERuntime_x86-KOR.exe
SSCERuntime_x86-CHT.exe
SSCERuntime_x86-CHS.exe
SSCERuntime_x64-ENU.exe
SSCERuntime_x64-DEU.exe
SSCERuntime_x64-FRA.exe
SSCERuntime_x64-JPN.exe
SSCERuntime_x64-RUS.exe
SSCERuntime_x64-ESN.exe
SSCERuntime_x64-ITA.exe
SSCERuntime_x64-KOR.exe
SSCERuntime_x64-CHT.exe
SSCERuntime_x64-CHS.exe
sqlcese40.dll
sqlceqp40.dll
sqlceoledb40.dll
sqlceca40.dll
sqlceme40.dll
sqlcecompact40.dll
sqlceer40en.dll
sqlceer40cn.dll/sqlceer40zh-CHS.dll
sqlceer40de.dll
sqlceer40es.dll
sqlceer40fr.dll
sqlceer40it.dll
sqlceer40ja.dll
sqlceer40ko.dll
sqlceer40tw.dll/sqlceer40zh-CHT.dll
sqlceer40ru.dll
System.Data.SqlServerCe.dll
System.Data.SqlServerCe.Entity.dll

ただし、SQL Server Compact 4.0の再配布方法に関する情報は提供されません。

文書化されていないProgram Filesフォルダーをランダムにスペルチェックして、7つのdllを見つけました。

C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\
      sqlceoledb40.dll
      sqlceqp40.dll
      sqlcese40.dll
      sqlceca40.dll
      sqlcecompact40.dll
      sqlceer40EN.dll
      sqlceme40.dll

注:いくつかの子フォルダーとより多くのdllもあります

これらの7つのdllをフォルダーにコピーして、 ADO Connectionthe connection string を使用して開こうとしました。

Provider=Microsoft.SQLSERVER.CE.OLEDB.4.0;Data Source="store.sdf"

しかし、0x80004005 Unspecified errorで失敗します

iはウィジェットをすりつぶそうとしましたが、ふざけたものを取りました。

45
Ian Boyd

ソリューションを作成しました。

SQL Server Compact Editionは7つのdllで構成されています。

  • sqlceme40.dll文書化されていないネイティブのフラットAPIライブラリ(.net System.Data.SqlServerCe.dllアセンブリはこのdllのラッパーです)
  • sqlceca40.dllEngineReplicationErrorおよび他のいくつかのCOMオブジェクトを実装するCOM DLL
  • sqlceoledb40.dll SSCEのOLEdbプロバイダーを実装するCOM dll(ADOの使用を許可)
  • sqlcese40.dllunknown
  • sqlceqp40.dllunknown
  • sqlcecompact40.dllunknown
  • sqlceer40en.dllunknown

これらのdllを単純に出荷しようとすると、2つが[〜#〜] com [〜#〜]オブジェクトであるという問題があります。 COMオブジェクトdllはregisteredである必要があります。例:

>regsvr32 sqlceca40.dll
>regsvr32 sqlceoledb40.dll

問題は、COMオブジェクトを登録するにはadministrative特権が必要なことです( グローバルソリューションを使用してローカルの問題を解決する )。これは、ユーザーが

  • アプリケーションをinstallする必要がある(実行したくない)
  • ユーザーに管理者権限が必要です(管理者権限は必要ありません)

幸いなことに、Windows XPで2001年に始まったMicrosoftは、このCOMmonの問題を解決しました: Registration-Free COM

まず、SQL Server Compact Edition 4.0でアプリケーションに "dependancy"があることを宣言します。これを行うには、アセンブリマニフェストを作成します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Assembly xmlns="urn:schemas-Microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
        version="1.0.0.0"
        processorArchitecture="X86"
        name="client"
        type="win32"
    /> 

    <description>Hyperion Pro</description> 

    <!-- We have a dependancy on SQL Server CE 4.0 -->
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.SQLSERVER.CE.4.0"
                version="4.0.0.0" processorArchitecture="x86"
            />
        </dependentAssembly>
    </dependency>
    <!-- We are high-dpi aware on Windows Vista -->
    <asmv3:application xmlns:asmv3="urn:schemas-Microsoft-com:asm.v3">
        <asmv3:windowsSettings
            xmlns="http://schemas.Microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>

    <!-- We were designed and tested on Windows 7 -->
    <compatibility xmlns="urn:schemas-Microsoft-com:compatibility.v1">
        <application>
            <!--The ID below indicates application support for Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <!--The ID below indicates application support for Windows Vista -->
            <!--supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/-->
        </application>
    </compatibility>

    <!-- Disable file and registry virtualization -->
    <trustInfo xmlns="urn:schemas-Microsoft-com:asm.v2">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</Assembly>

このファイルを実行可能ファイル(Hyperion.exe.manifest)の横に配置するか、RT_MANIFESTリソースとしてアプリケーションにビルドできます。

Microsoft.SQLSERVER.CE.4.0というアセンブリとして依存していることに注意してください。最初にディレクトリを作成して、このアセンブリを作成します。

Microsoft.SQLSERVER.CE.4.0

アプリケーションをデプロイするとき、この "Assembly"を構成する7つのdllをすべて、特別なMicrosoft.SQLSERVER.CE.4.0ファイルとともにこの.manifestサブフォルダーに配置します。

C:\
|---Users
   |---Ian
       |---AppData
           |---Local
               |---Hyperion Pro
                   |    Hyperion.exe
                   |    Hyperion.exe.manifest
                   |----Microsoft.SQLSERVER.CE.4.0
                            sqlceme40.dll
                            sqlceca40.dll
                            sqlceoledb40.dll
                            sqlcese40.dll
                            sqlceqp40.dll
                            sqlcecompact40.dll
                            sqlceer40en.dll
                            Microsoft.SQLSERVER.CE.4.0.manifest

つまり、アプリケーションフォルダーにはアプリケーションとMicrosoft.SQLSERVER.CE.4.0フォルダーが含まれます。

 Directory of C:\Users\Ian\AppData\Local\Hyperion Pro

05/29/2012  09:23 AM         1,899,008 Hyperion.exe
05/28/2012  01:46 PM             1,587 Hyperion.exe.manifest
05/29/2012  09:27 AM    <DIR>          Microsoft.SQLSERVER.CE.4.0
           2 File(s)      1,900,675 bytes
           1 Dir(s)  20,851,503,104 bytes free

タスクの次の部分は、Microsoft.SQLSERVER.CE.4.0.manifestファイルを定義することです。登録不要のCOMでは、マニフェストファイルですべてのCOMオブジェクトとそのclsidを宣言できます。これには多くのリバースエンジニアリングが必要でした。ただし、SQL Server Compact Edition 4.0のアセンブリマニフェストは次のとおりです。

Microsoft.SQLSERVER.CE.4.0.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Assembly xmlns="urn:schemas-Microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity 
       type="win32"
       name="Microsoft.SQLSERVER.CE.4.0"
       processorArchitecture="x86"
       version="4.0.0.0" />

<!-- OLEDB Provider -->
<file name = "sqlceoledb40.dll">
    <comClass
            description = "Microsoft SQL Server Compact OLE DB Provider for Windows"
            clsid="{2006C53A-C915-41EA-BAA9-9EAB3A1FBF97}"
            threadingModel = "Both"
            progid = "Microsoft.SQLSERVER.CE.OLEDB.4.0" />
</file>

<!-- Native flat engine library -->
<file name="sqlceme40.dll" />

<!-- Engine and Replication COM object -->
<file name="sqlceca40.dll">
    <comClass description="Active SSCE Engine Object"
            clsid="{68D45319-3702-4837-9F8E-DA6845D82482}"
            threadingModel="Both"
            progid="SSCE.Engine.4.0" />
    <comClass description="SSCE Error Object"
            clsid="{36228F21-B5C7-4054-8DC2-47D3E236E8B5}"
            threadingModel="Both"
            progid="SSCE.Error.4.0" />
    <comClass description="SSCE Param Object"
            clsid="{0B3A7B75-A9B0-4580-9AA5-1A7DA47AD1CB}"
            threadingModel="Both"
            progid="SSCE.Param.4.0" />
    <comClass description="Active SSCE Replication Object"
            clsid="{11D5B2D4-26A4-44F5-A48B-0FAC3A919ED8}"
            threadingModel="Both"
            progid="SSCE.Replication.4.0" />
    <comClass description="Active SSCE remote data access Object"
            clsid="{58BC9AD6-BF11-40B3-9AB1-E3F2ED784C08}"
            threadingModel="Both"
            progid="SSCE.RemoteDataAccess.4.0" />

    <typelib tlbid="{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}"
            version="4.0" 
            helpdir=""/>
</file>

<comInterfaceExternalProxyStub 
    name="ISSCEEngine"
    iid="{10EC3E45-0870-4D7B-9A2D-F4F81B6B7FA2}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCEError"
    iid="{31155A3B-871D-407F-9F73-DEBFAC7EFBE3}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCERDA"
    iid="{4F04F79D-1FF1-4DCD-802B-3D51B9356C14}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCEParams"
    iid="{A78AFF90-049C-41EC-B1D8-665968AAC4A6}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCEParam"
    iid="{A9876C60-2667-44E5-89DB-E9A46ED392C0}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCEErrors"
    iid="{C40143CA-E9F9-4FF4-B8B4-CC02C064FC1B}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<comInterfaceExternalProxyStub 
    name="ISSCEMerge"
    iid="{C6EB397F-D585-428D-A4F4-454A1842CB47}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{CE4AACFA-3CFD-4028-B2D9-F272314F07C8}" />

<file name="sqlceqp40.dll" />
<file name="sqlcese40.dll" />
<file name="sqlcecompact40.dll" />
<file name="sqlceer40EN.dll" />

</Assembly>

最後の落とし穴は、Microsoft.SQLSERVER.CE.4.0というアセンブリに依存するのと同じように、SQL Server Compact Edition 4.0はMicrosoft.VC90.CRTというアセンブリに依存することです。幸いなことに、SQLCEのインストールには、このアセンブリのコピーが付属しています。

|----Microsoft.VC90.CRT
    |    Microsoft.VC90.CRT.manifest 
    |    msvcr90.dll

つまり、最終的なディレクトリ構造は次のとおりです。

C:\
|---Users
   |---Ian
      |---AppData
         |---Local
            |---Hyperion Pro
               |    Hyperion.exe
               |    Hyperion.exe.manifest
               |----Microsoft.SQLSERVER.CE.4.0
                   |   Microsoft.SQLSERVER.CE.4.0.manifest
                   |   sqlceme40.dll
                   |   sqlceca40.dll
                   |   sqlceoledb40.dll
                   |   sqlcese40.dll
                   |   sqlceqp40.dll
                   |   sqlcecompact40.dll
                   |   sqlceer40en.dll
                   |---Microsoft.VC90.CRT
                      |   Microsoft.VC90.CRT.manifest
                      |   msvcr90.dll
52
Ian Boyd

SQL Server Ce 4.0 SP1の場合:

展開のざらざらしたものすべてに取り組むのではなく、セットアップファイル自体をEmbeddedResourceとしてexeに含めることを選択し、この小さなヘルパーを実行しました。

 public static class RedistHelper
    {
        private static readonly ILog Log = LogManager.GetLogger(
                                              MethodBase.GetCurrentMethod().DeclaringType);

        private static readonly string SqlCeRedistName64 = "SSCERuntime_x64-ENU.exe";
        private static readonly string SqlCeRedistName32 = "SSCERuntime_x86-ENU.exe";
        private static readonly Dictionary<string, Assembly> Assemblies = 
                        new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);

        private static string SqlCeRedistName
        {
            get 
            {
                return Environment.Is64BitOperatingSystem 
                                       ? SqlCeRedistName64 
                                       : SqlCeRedistName32;
            }
        }

        public static bool IsSqlCeInstalled()
        {
            RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
                                                           RegistryView.Registry64);
            RegistryKey ret = localKey.OpenSubKey(
                    @"SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v4.0\ENU");
            return ret != null;
        }

        private static byte[] ReadFully(Stream input)
        {
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                    ms.Write(buffer, 0, read);
                return ms.ToArray();
            }
        }

        public static Assembly OnCurrentDomainOnAssemblyResolve(object sender,
                                                                ResolveEventArgs args)
        {
            Assembly dll;
            var name = new AssemblyName(args.Name).Name + ".dll";
            if (!Assemblies.TryGetValue(name, out dll))
            {
                Assembly res = typeof(RedistHelper).Assembly;
                using (Stream input =
                           res.GetManifestResourceStream(typeof(RedistHelper), name))
                {
                    if (input == null)
                    {
                        Log.WarnFormat("Assembly {0} does not contain {1}", res, name);
                        return null;
                    }
                    dll = Assembly.Load(ReadFully(input));
                    if (dll == null)
                    {
                        Log.WarnFormat("Assembly {0} failed to load.", name);
                        return null;
                    }
                    Log.InfoFormat("Loaded Assembly {0}.", name);
                    Assemblies[name] = dll;
                    return dll;
                }
            }
            return dll;
        }

        public static void InstallSqlCe()
        {
            using (Stream stream =
                       typeof(RedistHelper).Assembly.GetManifestResourceStream(
                           typeof(RedistHelper), SqlCeRedistName))
            {
                Debug.Assert(stream != null);
                byte[] bytes = new byte[(int)stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                string path = Path.Combine(Path.GetTempPath(), SqlCeRedistName);

                if (File.Exists(path))
                    File.Delete(path);

                File.WriteAllBytes(path, bytes);

                Process process = new Process
                                  {
                                      StartInfo = new ProcessStartInfo
                                                  {
                                                      FileName = path,
                                                      UseShellExecute = true
                                                  }
                                  };
                process.Start();
                process.WaitForExit();
            }
        }
    }

本当に頭痛の種になったのは、System.Data.SqlServerCe.dllを参照することだけでした。IlMergeを単純に使用しなかったので、メインでオンデマンドでロードしました。

AppDomain.CurrentDomain.AssemblyResolve += RedistHelper.OnCurrentDomainOnAssemblyResolve;
8

何かが変わったかどうかわからない。しかし、最新のSQL Server CE nugetパッケージでは、アプリケーションマニフェストは不要になりました。 x86とAMD64の2セットのバイナリを取得します。それらをx86またはAMD64サブディレクトリの下のターゲットフォルダにコピーするだけです。

|--Your App Dir
   |--x86 (x86 sql ce binaries)
   |--AMD64 (AMD64 sql ce binaries)

そして、あなたは行ってもいいです。 System.Data.SqlCe.dllがネイティブバイナリを自動的に検索してロードできるようです。アプリが1つのプラットフォームのみを対象としている場合は、それらをアプリディレクトリに展開することもできます。

0
Shao Skywalker