web-dev-qa-db-fra.com

Comment déployer SQL Server Compact Edition 4.0?

Comment déployer Microsoft SQL Server Compact 4. ?


SQL Server Compact Edition (actuellement à la version 4.0) est:

une base de données intégrée gratuite que les développeurs de logiciels peuvent utiliser pour créer des applications de bureau Windows. Il a une petite empreinte et prend en charge le déploiement privé de ses fichiers binaires dans le dossier d'application.

Mais comment le déployez-vous réellement?

Le problème est que vous ne pouvez pas utiliser le fournisseur OLEdb ADO sauf s'il est enregistré. L'enregistrement d'un fournisseur OLEdb doit être effectué en tant qu'administrateur. Cela signifie que l'édition SQL Server Compact échouera avec les utilisateurs qui sont pas un administrateur.

SQL Server Compact 4.0 est fourni avec un redist_enu.txt fichier:

Les fichiers .exe répertoriés installent chacun leurs composants inclus à un emplacement spécifique sur l'ordinateur de destination. Cela permet de garantir la maintenance et le support technique. Les fichiers .dll inclus dans ces fichiers .exe sont également disponibles séparément dans ce redist.txt. Toutefois, les distributions de ces fichiers .dll distincts peuvent entraîner des problèmes de facilité de maintenance. Pour plus de détails, veuillez consulter http://go.Microsoft.com/fwlink/?LinkId=94589

Détection de déploiement privé via BreadCrumb: le déploiement privé de la pile native uniquement et le chargement explicite de SQL Server Compact Assembly via Assembly.LoadFrom (), le fichier .local ou l'utilisation de stratégies de redirection DLL/COM ne sont pas pris en charge et peuvent entraîner des problèmes de facilité de maintenance . Pour plus d'informations, voir http://support.Microsoft.com/kb/835322 et 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

mais il ne donne aucune information sur la redistribution de SQL Server Compact 4.0.

Épeler au hasard les sans-papiers Program Files dossier j'ai trouvé 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

Remarque: Il existe également des dossiers enfants avec plus de DLL

j'ai essayé de copier ces 7 DLL dans un dossier et j'ai essayé d'ouvrir une connexion ADO en utilisant la chaîne de connexion :

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

mais il échoue avec 0x80004005 Unspecified error

j'ai essayé de frobber le widget, mais il a grobé le frobber.

45
Ian Boyd

j'ai créé la solution.

SQL Server Compact Edition est composé de 7 DLL:

  • sqlceme40.dll La bibliothèque d'API plate, non documentée et native (L'assembly .net System.Data.SqlServerCe.dll Est un wrapper autour de cette DLL)
  • sqlceca40.dll Une DLL COM qui implémente Engine, Replication, Error et quelques autres objets COM
  • sqlceoledb40.dll Une DLL COM qui implémente un fournisseur OLEdb pour SSCE (autorisant l'utilisation d'ADO)
  • sqlcese40.dll inconnu
  • sqlceqp40.dll inconnu
  • sqlcecompact40.dll inconnu
  • sqlceer40en.dll inconnu

Le problème avec la tentative de simplement envoyer ces DLL est que deux d'entre eux sont des objets [~ # ~] com [~ # ~] . La DLL de l'objet COM doit être enregistrée, par exemple:

>regsvr32 sqlceca40.dll
>regsvr32 sqlceoledb40.dll

Le problème est que l'enregistrement d'un objet COM nécessite des privilèges administratif ( en utilisant une solution globale pour résoudre un problème local ). Cela signifie que vos utilisateurs

  • devez installer votre application (ce que vous ne voulez pas faire)
  • nécessite que vos utilisateurs disposent d'autorisations administratives (ce que vous ne voulez pas faire)

Heureusement, à partir de 2001 avec Windows XP, Microsoft a résolu ce problème COMmon: Registration-Free COM .

Tout d'abord, vous déclarerez que votre application a un "dépendance" sur SQL Server Compact Edition 4.0. Pour ce faire, créez un manifeste d'assembly:

<?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>

Vous pouvez placer ce fichier à côté de votre exécutable (comme Hyperion.exe.manifest), Ou vous pouvez l'intégrer dans votre application en tant que ressource RT_MANIFEST.

Notez que nous avons une dépendance par rapport à l'assembly appelé Microsoft.SQLSERVER.CE.4.0. Nous créons d'abord cet assemblage en créant un répertoire appelé:

Microsoft.SQLSERVER.CE.4.0

Lorsque vous déployez votre application, vous placerez les 7 dll qui composent ce "Assembly" dans ce sous-dossier Microsoft.SQLSERVER.CE.4.0, Avec un fichier spécial .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

En d'autres termes, le dossier d'application contient votre application et le dossier 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

La prochaine étape de votre tâche consiste à définir le fichier Microsoft.SQLSERVER.CE.4.0.manifest. COM sans inscription permet à un fichier manifeste de déclarer tous les objets COM et leurs identifiants. Cela a pris beaucoup d'ingénierie inverse. Mais le manifeste d'assembly pour SQL Server Compact Edition 4.0 est:

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>

Le dernier problème est que, de la même manière que nous avons une dépendance sur un assembly appelé Microsoft.SQLSERVER.CE.4.0, SQL Server Compact Edition 4.0 a à son tour une dépendance sur un assembly appelé Microsoft.VC90.CRT. Heureusement, votre installation de SQLCE est livrée avec une copie de cet assembly:

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

Cela signifie que la structure finale du répertoire est:

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

Pour Sql Server Ce 4.0 SP1:

Au lieu de s'attaquer à toutes les choses sérieuses du déploiement, j'ai simplement choisi d'inclure les fichiers d'installation eux-mêmes dans mon exe en tant que EmbeddedResource et j'ai fait cette petite aide:

 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();
            }
        }
    }

La seule chose qui m'a vraiment donné mal à la tête était de référencer le System.Data.SqlServerCe.dll - il ne voulait tout simplement pas IlMerge, alors je l'ai plutôt chargé à la demande, dans mon principal:

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

Je ne sais pas si quelque chose a changé ou non. Mais avec le dernier package de nuget SQL Server CE, les manifestes d'application ne sont plus nécessaires. Vous obtiendrez deux ensembles de binaires: x86 et AMD64. Copiez-les simplement dans votre dossier cible sous le sous-répertoire x86 et/ou AMD64.

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

Et vous êtes prêt à partir. Il semble que System.Data.SqlCe.dll puisse rechercher et charger automatiquement les fichiers binaires natifs. Vous pouvez également les déployer dans le répertoire de l'application si votre application n'est ciblée que pour une seule plate-forme.

0
Shao Skywalker