Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何基于客户端架构动态加载x86/x64版本的SQLite3.DLL?_.net_Sqlite_Pinvoke_Devart - Fatal编程技术网

.net 如何基于客户端架构动态加载x86/x64版本的SQLite3.DLL?

.net 如何基于客户端架构动态加载x86/x64版本的SQLite3.DLL?,.net,sqlite,pinvoke,devart,.net,Sqlite,Pinvoke,Devart,我正在尝试在运行时动态加载SQLite3.DLL的适当x86/x64版本,以便与Devart.SQLite.DLL一起使用。我无法事先控制将DLL的适当版本安装到应用程序根目录,因此我必须设法从应用程序根目录的/x86或/x64子目录中获取正确的版本 关于如何实现这一点有什么想法吗?无可否认,我在这里完全迷路了。到目前为止,我的代码是: Public Sub New() LoadAssembly(“sqlite3.dll”,True) 端接头 私有函数GetAssemblyPath(ByVal程

我正在尝试在运行时动态加载SQLite3.DLL的适当x86/x64版本,以便与Devart.SQLite.DLL一起使用。我无法事先控制将DLL的适当版本安装到应用程序根目录,因此我必须设法从应用程序根目录的/x86或/x64子目录中获取正确的版本

关于如何实现这一点有什么想法吗?无可否认,我在这里完全迷路了。到目前为止,我的代码是:

Public Sub New()
LoadAssembly(“sqlite3.dll”,True)
端接头
私有函数GetAssemblyPath(ByVal程序集为字符串,ByVal版本为字符串)为字符串
返回Path.GetDirectoryName(Reflection.Assembly.getExecutionGassembly().Location)&“\”版本和“\”程序集
结束函数“GetAssemblyName”
_
公共共享函数LoadLibraryW(lpLibFileName作为字符串)作为IntPtr
端函数
私有子加载程序集(ByVal myAssembly作为字符串,可选ByVal doLoadLibrary作为布尔值=False)
将名称变暗
将文件名设置为字符串
将版本设置为字符串
如果UIntPtr.Size=8,则version=“x64”否则version=“x86”
文件名=GetAssemblyPath(myAssembly,版本)
尝试
如果你是图书馆的话
HostLog.WriteEntry(文件名,EventLogEntryType.Information)
Dim ptr As IntPtr=LoadLibraryW(文件名)
HostLog.WriteEntry(ptr.ToString(),EventLogEntryType.Information)
其他的
an=AssemblyName.GetAssemblyName(文件名)
AppDomain.CurrentDomain.Load(an)
如果结束
特例
HostLog.WriteEntry(例如Message,EventLogEntryType.Error)
结束尝试
“端头”组件
编辑 如注释中所述,我未能指定在尝试加载sqlite3.dll时收到的实际错误。事实证明,我的App.Config中缺少以下内容:

<system.data>
  <DbProviderFactories>
    <remove invariant="Devart.Data.SQLite" />
    <add name="dotConnect for SQLite" 
       invariant="Devart.Data.SQLite" 
       description="Devart dotConnect for SQLite" 
       type="Devart.Data.SQLite.SQLiteProviderFactory, Devart.Data.SQLite, Version=4.2.122.0, Culture=neutral, PublicKeyToken=09af7300eec23701" />
  </DbProviderFactories>
</system.data>


一旦我将其添加到App.Config中,我以前的代码示例就如预期的那样工作了。感谢大家的帮助。

您可以创建一个包含两个实现的接口。x86实现和x64实现。你可以说,
[DllImport(“x86version.dll”)]Bob(strings)[DllImport(“x64version.dll”)]Bob(字符串s)

例如:

public interface ISQLite
{
    public void Foo();
}

public class SQLite32 : ISQLite
{
   [DllImport("x86/SQLite3.dll")]
    private void foo();
   public void Foo()
   {
       foo();
   }
}

public class SQLite64 : ISQLite
{
   [DllImport("x64/SQLite3.dll")]
    private void foo();
   public void Foo()
   {
      foo();
   }
}

public static class SQLiteLoader
{
   public static ISQLite GetSQLite()
   {
       if(System.Environment.Is64BitOperatingSystem)
          return new SQLite64();
       else
          return new SQLite32();
   }
}

事实证明,我的原始代码示例确实有效,但我未能在程序的App.Config中正确注册SQLite的DBProviderFactory。现在,我可以从应用程序根目录将x86和x64 sqlite3.dll捆绑到各自的/x86和/x64目录中,并在运行时加载正确的版本。对于那些寻求完整解决方案的人,请参见下面的内容(感谢大家对代码的改进;他们已经被合并):

App.Config

<system.data>
  <DbProviderFactories>
    <remove invariant="Devart.Data.SQLite" />
    <add name="dotConnect for SQLite" 
       invariant="Devart.Data.SQLite" 
       description="Devart dotConnect for SQLite" 
       type="Devart.Data.SQLite.SQLiteProviderFactory, Devart.Data.SQLite, Version=4.2.122.0, Culture=neutral, PublicKeyToken=09af7300eec23701" />
  </DbProviderFactories>
</system.data>

AssemblyLoader.vb

Imports System.IO
Imports System.Reflection
Imports System.Security

''' <summary>
''' Handles dynamically loading managed and unmanaged assemblies.
''' </summary>
Public Class AssemblyLoader

  ''' <summary>
  ''' Loads the appropriate x86/x64 version of an assembly based on its filename.
  ''' </summary>
  ''' <param name="myAssembly">The filename of the assembly.</param>
  ''' <param name="isManaged">True if the assembly is managed, otherwise False.</param>
  ''' <exception cref="ArgumentException">If myAssembly is invalid, such as an assembly with an invalid culture.</exception>
  ''' <exception cref="SecurityException">The caller does not have path discovery permission.</exception>
  ''' <exception cref="BadImageFormatException">Thrown if myAssembly is not a valid assembly. -or-Version 2.0 or later of the common language runtime is currently loaded and assemblyRef was compiled with a later version.</exception>
  ''' <exception cref="FileLoadException">An assembly or module was loaded twice with two different evidences.</exception>
  ''' <exception cref="AppDomainUnloadedException">The operation is attempted on an unloaded application domain.</exception>
  Public Shared Sub LoadByVersion(ByVal myAssembly As String, Optional ByVal isManaged As Boolean = True)
    Dim an As AssemblyName
    Dim filename As String
    Dim version As String
    If UIntPtr.Size = 8 Then version = "x64" Else version = "x86"
    filename = GetAssemblyPath(myAssembly, version)

    Try
        If Not File.Exists(filename) Then Exit Sub
        If isManaged Then
            an = AssemblyName.GetAssemblyName(filename)
            If Not IsNothing(an) Then AppDomain.CurrentDomain.Load(an)
        Else
            LoadLibraryW(filename)
        End If
    Catch ex As ArgumentException
        Throw
    Catch ex As SecurityException
        Throw
    Catch ex As BadImageFormatException
        Throw
    Catch ex As FileLoadException
        Throw
    Catch ex As AppDomainUnloadedException
        Throw
    End Try
  End Sub ' LoadAssembly

  ''' <summary>
  ''' Gets the absolute path of the dependant assembly.
  ''' </summary>
  ''' <param name="assembly">The filename (without path) of the dependent assembly.</param>
  ''' <param name="version">The subfolder containing the version of the assembly needed (e.g. "x86", "x64").</param>
  ''' <returns>The absolute path of the specific version of the assembly.</returns>
  Private Shared Function GetAssemblyPath(ByVal assembly As String, ByVal version As String) As String
    Return Path.Combine(Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location), version, assembly)
  End Function ' GetAssemblyName

  ''' Return Type: HMODULE->HINSTANCE->HINSTANCE__*
  '''lpLibFileName: LPCWSTR->WCHAR*
  <Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint:="LoadLibraryW")> _
  Private Shared Function LoadLibraryW(<Runtime.InteropServices.InAttribute()> <Runtime.InteropServices.MarshalAsAttribute(Runtime.InteropServices.UnmanagedType.LPWStr)> lpLibFileName As String) As IntPtr
  End Function ' LoadLibraryW

End Class ' AssemblyLoader
Imports System.IO
输入系统。反射
导入系统。安全
''' 
''处理动态加载托管和非托管程序集。
''' 
公共类汇编加载器
''' 
''根据程序集的文件名加载相应的x86/x64版本。
''' 
''程序集的文件名。
''如果程序集是托管的,则为True,否则为False。
''如果myAssembly无效,例如具有无效区域性的程序集。
''调用方没有路径发现权限。
如果myAssembly不是有效程序集,则引发“”-或公共语言运行库的2.0或更高版本当前已加载,并且assemblyRef是使用更高版本编译的。
''一个程序集或模块加载了两次两个不同的证据。
''在卸载的应用程序域上尝试该操作。
公共共享子LoadByVersion(ByVal myAssembly作为字符串,可选ByVal isManaged作为Boolean=True)
将名称变暗
将文件名设置为字符串
将版本设置为字符串
如果UIntPtr.Size=8,则version=“x64”否则version=“x86”
文件名=GetAssemblyPath(myAssembly,版本)
尝试
如果文件不存在(文件名),则退出子文件
如果我被管理的话
an=AssemblyName.GetAssemblyName(文件名)
如果不是Nothing(an),则AppDomain.CurrentDomain.Load(an)
其他的
LoadLibraryW(文件名)
如果结束
捕获ex作为例外
扔
Catch ex作为SecurityException
扔
捕获ex作为BadImageFormatException
扔
捕获ex作为FileLoadException
扔
Catch ex作为AppDomainUnloadexception
扔
结束尝试
“端头”组件
''' 
''获取从属程序集的绝对路径。
''' 
''依赖程序集的文件名(不带路径)。
''包含所需程序集版本的子文件夹(例如,“x86”、“x64”)。
''程序集特定版本的绝对路径。
私有共享函数GetAssemblyPath(ByVal程序集为字符串,ByVal版本为字符串)为字符串
返回Path.Combine(Path.GetDirectoryName(Reflection.Assembly.getExecutionGassembly().Location)、版本、程序集)
结束函数“GetAssemblyName”
''返回类型:HMODULE->HINSTANCE->HINSTANCE__*
''lpLibFileName:LPCWSTR->WCHAR*
_
私有共享函数LoadLibraryW(lpLibFileName作为字符串)作为IntPtr
结束函数“LoadLibraryW”
“结束类”AssemblyLoader
**MyApp**

<snip>
Public Sub New()
    Try
        AssemblyLoader.LoadByVersion("sqlite3.dll", False)
    Catch ex As Exception
        ' Error logging done here
    End Try
End Sub
</snip>

公共分新()
尝试
AssemblyLoader.LoadByVersion(“sqlite3.dll”,False)
特例
'在此处完成日志记录时出错
结束尝试
端接头

另一种解决方案是,在您的解决方案中包括适当命名的每种操作系统类型的SQLite3 dll(例如SQLite3-x86.dll和SQLite3-x64.dll),并设置为使用可执行文件复制到应用程序的输出目录(即,将“复制到输出目录”设置为“始终”)。然后,当程序启动时,有一个函数检查.dll是否存在,并且
public static bool checkForSQLite()
{
      string sqliteFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "sqlite3.dll");

            if (!File.Exists(sqliteFileName))
            {
                string version = "x86";

                if (IntPtr.Size == 8)
                {
                    version = "x64";
                }

                string resourceFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "sqlite3-" + version + ".dll");

                File.Move(resourceFileName, sqliteFileName);

                return true;
            }
            else
            {
                return false;
            }
        }