Background:
> System. Data. SQLite. DLL assembly does not support AngCPU format well
System.Data.SQLite.dll has three schemes to adapt to x86 and x64:
Use 32 or 64 hybrid compiled assemblies (programs run in 64 bits, but references to 32-bit assemblies cause errors, and vice versa) -- so this scheme is very disgusting.
Assemblies using AnyCPU -- but you have to refer indirectly to the C++ core assembly: SQLite.Interop.dll -- that is, you have to refer to two assemblies at the same time: System.Data.SQLite.dll and SQLLite. Interop. dll.
The third one is based on the second one: run the official installation file of SQLite and install the SQLite.Interop.dll assembly into the system directory automatically - when you call the AnyCPU version of System.Data.SQLite.dll, the program will automatically go to the system directory to find the corresponding C++ assembly.
(But this solution does not support install-free running - your local compilation works properly and copies to other computers crash (the target computer also has to run the official SQLite installation file)
The entanglement arises:
I just want to refer to an assembly.
> This assembly is AnyCPU (automatic adaptation x64 x86).
> I compiled the program and sent it to the other party, the other party can directly double-click to run.
The above three solutions: basically, they can't solve this problem perfectly.
Existing solutions can be found online:
http://download.csdn.net/download/yhbcpg/8441051
After downloading:
But there are problems:
This buddy downloaded code modification from the official website of SQLite - and finally used code obfuscation (of course, adding hundreds of lines of code to protect his own code - is beyond reproach).
I really don't like 10940_x64 and 10940_86 folders - it seems a bit difficult to modify the source code based on this author, let's just implement one by ourselves.
Feasibility assessment attempt:
> I downloaded the latest 1.0.105.2 source code from the official website of SQLite.
After compiling, the x64 x86 directory is created manually.
> The program is working properly -- in other words, the SQLite authorities have provided the identification of x64 x86 folders
Then, adjust the target:
Increase self-release function.
Release to the current program directory: No x86 and x64 directories are used
Release to the corresponding platform directory: using x86 and x64 directories
Each run-time checks whether the C++ assembly adapts to the current program platform and whether it needs to be re-released.
Thus, System.Data.SQLite.dll adaptive AnyCPU begins with self-releasing assembly rewriting:
> GZip compression of C++ assemblies x86 and x64 to save the byte size of the assemblies and to be embedded in the project:
> In reading the official source code of SQLite 1.0.105.2, I found a function in the source code Unsafe NativeMethods. cs: PreLoad SQLiteDll (*).
> An auxiliary class u RecoverHelper.cs, which releases C++ assemblies, is added and called directly by the PreLoadSQLiteDll(*) function.
> The modified code is as follows:
1 private static bool PreLoadSQLiteDll( 2 string baseDirectory, /* in */ 3 string processorArchitecture, /* in */ 4 ref string nativeModuleFileName, /* out */ 5 ref IntPtr nativeModuleHandle /* out */ 6 ) 7 { 8 //Added code 9 __RecoverHelper.InitResourceSQLiteInteropAssembly(); 10 11 // 12 // NOTE: If the specified base directory is null, use the default 13 // (i.e. attempt to automatically detect it). 14 // 15 if (baseDirectory == null) 16 baseDirectory = GetBaseDirectory(); 17 18 //..... 19 }
> u RecoverHelper.cs source code is as follows:
1 using System.Configuration; 2 using System.IO; 3 using System.IO.Compression; 4 using System.Reflection; 5 using System.Security.Cryptography; 6 using System.Text; 7 8 namespace System.Data.SQLite 9 { 10 /// <summary> 11 /// <para>repair System.Data.SQLite Required operating environment.</para> 12 /// <para>release System.Data.SQLite Needed C++Assembly SQLite.Interop.dll</para> 13 /// </summary> 14 internal static class __RecoverHelper 15 { 16 #region Attempt to load embedded assemblies 17 18 internal const string SQLite_Interop = @"SQLite.Interop"; 19 internal const string SQLite_Interop_x64MD5 = @"7d40719ca6d7c1622fa54d2f17a97020"; 20 internal const string SQLite_Interop_x86MD5 = @"bfd7e42cd1638debe255771057699574"; 21 22 23 /// <summary> 24 /// Whether will SQLite.Interop.dll Release to x64 x86 Folder, If this parameter is not released to the current directory. 25 /// </summary> 26 internal static bool InteropPlatformFolder 27 { 28 get 29 { 30 string value = (ConfigurationManager.AppSettings["System.Data.SQLite:InteropPlatformFolder"] ?? string.Empty).Trim().ToUpper(); 31 return (string.IsNullOrEmpty(value) || value == "TRUE" || value == "1" || value == "T"); 32 } 33 } 34 35 36 37 /// <summary> 38 /// When the running environment is not found SQLite.Interop.dll Assembly time, Attempt to write inline bytes back to disk and restore them to the original file SQLite.Interop.dll 39 /// </summary> 40 internal static void InitResourceSQLiteInteropAssembly() 41 { 42 try 43 { 44 //When the running environment is not found SQLite.Interop.dll Assembly time, Attempt to write inline bytes back to disk and restore them to the original file SQLite.Interop.dll 45 46 Assembly assembly = Assembly.GetExecutingAssembly(); 47 string domainFolder = AppDomain.CurrentDomain.BaseDirectory; 48 bool is64Proc = (IntPtr.Size == 8); 49 string interopFolder = string.Format(@"{0}\{1}", domainFolder.TrimEnd('/', '\\'), (InteropPlatformFolder ? (is64Proc ? @"x64\" : @"\x86\") : string.Empty)); 50 string SQLiteInteropDllPath = string.Format(@"{0}\{1}.dll", interopFolder.TrimEnd('/', '\\'), SQLite_Interop); 51 if (!Directory.Exists(interopFolder)) Directory.CreateDirectory(interopFolder); 52 53 //If the disk SQLite.Interop.dll existence, Check correlation MD5 54 if (File.Exists(SQLiteInteropDllPath)) 55 { 56 string existFileMD5 = GetFileMD5(SQLiteInteropDllPath); 57 string rightFileMD5 = is64Proc ? SQLite_Interop_x64MD5 : SQLite_Interop_x86MD5; 58 59 //If MD5 Atypism, Remove existing disk SQLite.Interop.dll 60 if (!string.Equals(existFileMD5, rightFileMD5, StringComparison.CurrentCultureIgnoreCase)) 61 File.Delete(SQLiteInteropDllPath); 62 } 63 64 65 //If the disk SQLite.Interop.dll Non-existent, Then release SQLite.Interop.dll 66 if (!File.Exists(SQLiteInteropDllPath)) 67 { 68 string libResourceName = string.Format("{0}.Lib.{1}.x{2}.GZip.dll", Assembly.GetExecutingAssembly().GetName().Name, SQLite_Interop, (is64Proc ? "64" : "86")); 69 Stream stream = assembly.GetManifestResourceStream(libResourceName); 70 if (stream == null) return; 71 72 try 73 { 74 using (stream) 75 { 76 using (Stream zipStream = (Stream)new GZipStream(stream, CompressionMode.Decompress)) 77 { 78 using (FileStream myFs = new FileStream(SQLiteInteropDllPath, FileMode.Create, FileAccess.ReadWrite)) 79 { 80 //Read all data from compressed streams 81 byte[] buffer = new byte[1024]; 82 do 83 { 84 int n = zipStream.Read(buffer, 0, buffer.Length); 85 if (n <= 0) break; 86 myFs.Write(buffer, 0, n); 87 } while (true); 88 89 zipStream.Close(); 90 } 91 } 92 } 93 } 94 catch (Exception) { } 95 } 96 } 97 catch(Exception) { } 98 } 99 100 101 #endregion 102 103 #region auxiliary function 104 105 /// <summary> 106 /// Computational file MD5, Computation error returns an empty string 107 /// </summary> 108 public static string GetFileMD5(string path) 109 { 110 if (!File.Exists(path)) return string.Empty; 111 112 try 113 { 114 using (FileStream myFs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) 115 { 116 using (MD5 md5 = new MD5CryptoServiceProvider()) 117 { 118 byte[] hash = md5.ComputeHash(myFs); 119 myFs.Close(); 120 121 StringBuilder sb = new StringBuilder(); 122 for (int i = 0; i < hash.Length; i++) sb.Append(hash[i].ToString("x2")); 123 return sb.ToString(); 124 } 125 } 126 } 127 catch (Exception) 128 { 129 return string.Empty; 130 } 131 } 132 /// <summary> 133 /// Calculates the specified length of a file from the specified byte MD5 (Insufficient remaining bytes, Only the remaining byte stream is computed), Computation error returns an empty string 134 /// </summary> 135 public static string GetFileMD5(string path, long offset, long length) 136 { 137 if (!File.Exists(path)) return string.Empty; 138 139 try 140 { 141 const int PACKAGE_SIZE = 1024 * 1024; //1 per time M 142 143 using (MD5 md5 = new MD5CryptoServiceProvider()) 144 { 145 md5.Initialize(); 146 147 using (FileStream myFs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) 148 { 149 myFs.Position = offset; 150 long fileByteLength = Math.Min(length, myFs.Length - myFs.Position); 151 byte[] buffer = new byte[PACKAGE_SIZE]; 152 153 long readLength = 0; 154 while (readLength < fileByteLength) 155 { 156 long leaveLength = myFs.Length - myFs.Position; 157 long leaveLength2 = fileByteLength - readLength; 158 int bufferLength = (leaveLength > (long)PACKAGE_SIZE) ? PACKAGE_SIZE : Convert.ToInt32(leaveLength); 159 bufferLength = (leaveLength2 > (long)bufferLength) ? bufferLength : Convert.ToInt32(leaveLength2); 160 161 myFs.Read(buffer, 0, bufferLength); 162 163 if (readLength + bufferLength < fileByteLength) //Not the last piece 164 md5.TransformBlock(buffer, 0, bufferLength, buffer, 0); 165 else //The last piece 166 md5.TransformFinalBlock(buffer, 0, bufferLength); 167 168 readLength = readLength + bufferLength; 169 if (myFs.Position >= myFs.Length) break; 170 } 171 172 byte[] hash = md5.Hash; 173 StringBuilder sb = new StringBuilder(); 174 for (int i = 0; i < hash.Length; i++) sb.Append(hash[i].ToString("x2")); 175 return sb.ToString(); 176 } 177 } 178 } 179 catch (Exception) 180 { 181 return string.Empty; 182 } 183 } 184 185 186 #endregion 187 } 188 }
Finally, use the official test tool of SQLite to test:
> The test passed as follows:
Relevant source code and assembly downloads (using official key signatures):
> Click Download Source Code and Signed Assemblies If this article is helpful to you, please click on the "Recommendation" in the lower right corner. Thank you.
Go directly to the Bin directory and run the official test tools test.exe and test32.exe
> By default, release C++ assemblies to the x86 x64 folder. If you want to set it to: release C++ assemblies to the current directory, you can add the following configuration in App.config:
1 <configuration> 2 <appSettings> 3 <add key="System.Data.SQLite:InteropPlatformFolder" value="0"/> 4 5 </appSettings> 6 </configuration>