Has anyone solved this problem?
Yes, Microsoft has. They needed to solve this exact same problem for their SQL Server Compact package. It has a single managed assembly, System.Data.SqlServerCe.dll, acting like the adapter to a managed program, and a bunch of native DLLs that implement the actual database engine. The way they bind to the native DLL entrypoints is not something I ever recommend, I'll work from the assumption that you use pinvoke. I recommend you use this technique to ensure that the client program can run AnyCPU.
Repeating the essence of that post, you want to execute this code somewhere in an initialization method or a static constructor:
public static void SetupDatabaseBinaries() {
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, IntPtr.Size == 8 ? "amd64" : "x86");
bool ok = SetDllDirectory(path);
if (!ok) throw new System.ComponentModel.Win32Exception();
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
The only non-trivial step is to get the user's project to copy the native DLL(s) into the project's amd64/x86 directories. This requires a post-build step, just the way the Compact package does it. You'll want to download the Nuget package to see how they did this, it isn't very trivial. Run VS elevated, create a dummy Console mode project and retrieve the Nuget package for Sql Server Compact. After it is installed, use Project + Properties, Build events tab and note how it added this post build event:
if not exist "$(TargetDir)x86" md "$(TargetDir)x86"
xcopy /s /y "$(SolutionDir)packagesMicrosoft.SqlServer.Compact.4.0.8876.1NativeBinariesx86*.*" "$(TargetDir)x86"
if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64"
xcopy /s /y "$(SolutionDir)packagesMicrosoft.SqlServer.Compact.4.0.8876.1NativeBinariesamd64*.*" "$(TargetDir)amd64"
Nothing much to it, it doesn't do anything more than creating the x86 and amd64 subdirectories and copies the DLLs into them. The tricky part is having your Nuget package add this build event. Have a look-see at the package folder for the magic that accomplished this. You probably want to follow the example as closely as possible to avoid mistakes. Look at the packagesMicrosoft.SqlServer.Compact.4.0.8876.1ools directory, it contains two PowerShell script files that do this. Install.ps1 runs at the end of the install. The function that creates the post-build step is in VS.psm1, Add-PostBuildEvent. Good luck with it.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…