sql server 2008 - ¿Cómo implementar SQL Server Compact Edition 4.0?
sql-server-2008 deployment (2)
He creado la solución.
SQL Server Compact Edition se compone de 7 dlls:
-
sqlceme40.dll
La biblioteca de API plana nativa no documentada (el ensamblado .NETSystem.Data.SqlServerCe.dll
es un contenedor de este dll) -
sqlceca40.dll
Un dll COM que implementaEngine
,Replication
,Error
y algunos otros objetos COM -
sqlceoledb40.dll
Un dll COM que implementa un proveedor OLEdb para SSCE (que permite el uso de ADO) -
sqlcese40.dll
desconocido -
sqlceqp40.dll
desconocido -
sqlcecompact40.dll
desconocido -
sqlceer40en.dll
desconocido
El problema con tratar de enviar estos dlls es que dos de ellos son objetos COM . Los objetos DLL del objeto COM deben registrarse , por ejemplo:
>regsvr32 sqlceca40.dll
>regsvr32 sqlceoledb40.dll
El problema es que registrar un objeto COM requiere privilegios administrativos ( utilizando una solución global para resolver un problema local ). Esto significa que tus usuarios
- tiene que instalar su aplicación (que no quiere hacer)
- requiere que sus usuarios tengan permisos administrativos (que no desea hacer)
Afortunadamente, a partir de 2001 con Windows XP, Microsoft resolvió este problema de COMmon: COM sin registro .
Primero, declarará que su aplicación tiene una "dependencia" en SQL Server Compact Edition 4.0. Para ello, crea un manifiesto de ensamblaje:
<?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>
Puede colocar este archivo junto al ejecutable (como Hyperion.exe.manifest
), o puede compilarlo en su aplicación como un recurso RT_MANIFEST
.
Tenga en cuenta que tenemos una dependencia contra asamblea llamada Microsoft.SQLSERVER.CE.4.0
. Creamos este ensamblaje primero al crear un directorio llamado:
Microsoft.SQLSERVER.CE.4.0
Cuando implemente su aplicación, colocará los 7 dll que componen este "ensamblado" en esta subcarpeta Microsoft.SQLSERVER.CE.4.0
, junto con un archivo .manifest
especial:
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 otras palabras, la carpeta de la aplicación contiene su aplicación y la carpeta 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 siguiente parte de su tarea es definir el archivo Microsoft.SQLSERVER.CE.4.0.manifest
. El COM sin registro permite que un archivo de manifiesto declare todos los objetos COM y sus clsid. Esto requirió mucha ingeniería inversa. Pero el manifiesto de conjunto para SQL Server Compact Edition 4.0 es:
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>
El resultado final es que, de la misma manera que tenemos una dependencia en un ensamble llamado Microsoft.SQLSERVER.CE.4.0
, SQL Server Compact Edition 4.0 a su vez tiene una dependencia en un ensamble llamado Microsoft.VC90.CRT
. Afortunadamente, su instalación de SQLCE se envía con una copia de este conjunto:
|----Microsoft.VC90.CRT
| Microsoft.VC90.CRT.manifest
| msvcr90.dll
Esto significa que la estructura de directorio final es:
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
¿Cómo implemento Microsoft SQL Server Compact 4.0 ?
SQL Server Compact Edition (actualmente en la versión 4.0) es:
una base de datos libre e integrada que los desarrolladores de software pueden usar para construir aplicaciones de escritorio de Windows. Tiene una huella pequeña y admite el despliegue privado de sus binarios dentro de la carpeta de la aplicación.
Pero, ¿cómo se implementa realmente?
- Microsoft dice que se puede implementar dentro de la carpeta de la aplicación ( bueno ) y admite la implementación de xcopy .
- Microsoft también dice que no se puede implementar dentro de la carpeta de la aplicación ( mal ) y no es compatible con la implementación de xcopy .
- algunas personas tienen ejemplos de esto usando la implementación simple de xcopy , pero no entran en los detalles requeridos para completar la implementación
El problema es que no puede usar el proveedor ADO OLEdb a menos que esté registrado. El registro de un proveedor OLEdb debe hacerse como administrador. Eso significa que la edición SQL Server Compact fallará con usuarios que no sean administradores.
SQL Server Compact 4.0 viene con un archivo redist_enu.txt
:
Los archivos .exe enumerados cada uno instala sus componentes adjuntos a una ubicación específica en la computadora de destino. Esto ayuda a garantizar la capacidad de servicio y el soporte técnico. Los archivos .dll incluidos en estos archivos .exe también están disponibles por separado en este archivo redist.txt. Sin embargo, la distribución de estos .dlls separados puede generar problemas de servicio. Para obtener más detalles, consulte http://go.microsoft.com/fwlink/?LinkId=94589
Detección de despliegue privado a través de BreadCrumb: la implementación privada de la pila nativa y la carga explícita de SQL Server Compact Assembly a través de Assembly.LoadFrom (), archivo local o el uso de estrategias de redireccionamiento DLL / COM no son compatibles y pueden generar problemas de mantenimiento. . Para obtener más información, consulte http://support.microsoft.com/kb/835322 y 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
pero no proporciona ninguna información sobre cómo redistribuir SQL Server Compact 4.0.
Aleatoriamente lanzando hechizos alrededor de la carpeta de Program Files
indocumentados encontré 7 dlls:
C:/Program Files/Microsoft SQL Server Compact Edition/v4.0/
sqlceoledb40.dll
sqlceqp40.dll
sqlcese40.dll
sqlceca40.dll
sqlcecompact40.dll
sqlceer40EN.dll
sqlceme40.dll
Nota: También hay algunas carpetas secundarias con más dlls
intenté copiar estos 7 dll a una carpeta e intenté abrir una conexión ADO utilizando la cadena de conexión :
Provider=Microsoft.SQLSERVER.CE.OLEDB.4.0;Data Source="store.sdf"
pero falla con 0x80004005 Unspecified error
Para Sql Server Ce 4.0 SP1:
En lugar de abordar todos los detalles de la implementación, simplemente opté por incluir los archivos de configuración en mi archivo ejecutable como EmbeddedResource e hice este pequeño ayudante:
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();
}
}
}
Lo único que realmente me dio un dolor de cabeza fue hacer referencia a System.Data.SqlServerCe.dll, simplemente no IlMerge, así que en su lugar lo cargué a pedido, en mi principal:
AppDomain.CurrentDomain.AssemblyResolve += RedistHelper.OnCurrentDomainOnAssemblyResolve;