C# Silverlight中动态加载的程序集调用DllImprot,用于锁定文件

C# Silverlight中动态加载的程序集调用DllImprot,用于锁定文件,c#,c++,silverlight,C#,C++,Silverlight,我的Silvelight 5应用程序有一个非常具体的问题: 我有一个动态加载Silverlight库(可能很多)的应用程序,这些库是通过dllimport调用方法的 原因:适用于不同的扫描设备。Silverlight库是用于逻辑的,C++库来自生产者并与设备连接。可能有许多silverlight库,它们必须在运行时加载 问题:加载Silverlight库和扫描后,我不能用C++库访问文件。为什么我必须这么做?若用户试图选择扫描仪,我将计算库的哈希代码,以检查服务器上是否有更新的版本 我的实施:

我的Silvelight 5应用程序有一个非常具体的问题: 我有一个动态加载Silverlight库(可能很多)的应用程序,这些库是通过dllimport调用方法的

原因:适用于不同的扫描设备。Silverlight库是用于逻辑的,C++库来自生产者并与设备连接。可能有许多silverlight库,它们必须在运行时加载

问题:加载Silverlight库和扫描后,我不能用C++库访问文件。为什么我必须这么做?若用户试图选择扫描仪,我将计算库的哈希代码,以检查服务器上是否有更新的版本

我的实施: ViewModel正在调用方法以获取当前扫描仪类:

 using (var stream = new IsolatedStorageFileStream(scanner.DirectoryName + Path.DirectorySeparatorChar + scanner.ScannerLibraryName, System.IO.FileMode.Open, store))
    {
      AssemblyPart assemblyPart = new AssemblyPart();
      Assembly assembly = assemblyPart.Load(stream);
      return (Scanner)assembly.CreateInstance(scanner.ClassName);
    }
稍后还有扫描:

        this.userScanner.LoadProducerLibrary();
        result = userScanner.ScanDocument();
        this.userScanner.FreeProducerLibrary();
LoadProducerLibrary调用:

[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string lpFileName);
ScanDocument也通过dllimport调用一些第三方方法

FreeProducerLibrary呼叫:

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] /* unnecessary, isn't it? */
public static extern bool FreeLibrary(IntPtr hModule);
之后,我在不同的viewmodel中有一个方法,它试图打开producer库文件来计算哈希代码,结果我得到“无法访问该文件,因为它正被另一个进程使用”

我曾尝试在Scanner类(动态加载程序集)中计算哈希代码,但一切正常,所以我怀疑这就是这个过程。但为什么免费图书馆还不够

你能给我提些建议吗?我是否应该尝试处理userScanner字段

ScanDocument也通过dllimport调用一些第三方方法

您忽略了最重要的代码,但该语句足以诊断您的问题。pinvoke封送拆收器还调用DLL上的LoadLibrary()。因此,DLL的引用计数为2。您的FreeLibrary()调用不会卸载它,并且文件保持锁定

您可以通过再次调用FreeLibrary()来解决这个问题。这将卸载DLL,但也会在程序中设置定时炸弹。您不能安全地再次拨打这些电话。pinvoke marshaller仍然确信DLL已加载,因此它不会重新生成为导入函数生成的存根。它们指向以前加载函数的地址,而不是现在加载函数的地址。这似乎是可行的,尤其是当你在人工测试中这样做的时候。但迟早,DLL无法在同一地址重新加载,因为它的地址空间被用于其他用途,并且您的程序将因硬崩溃而失败

如果您想实现这一点,则不能将[DllImport]用于这些方法。相反,您必须执行pinvoke marshaller所做的工作,为您使用的每个入口点调用GetProcAddress(),并使用您声明的与本机函数签名匹配的委托,使用Marshal.GetDelegateForFunctionPointer()调用它。工作,它不漂亮


更好的选择是使用一个单独的助手进程来进行这些调用并与之交互。现在安全了,让助手进程终止可以确保pinvoke存根消失,DLL解锁。不确定Silverlight的实用性,它的设计并没有将进程互操作放在功能列表的首位。没有过程类,这给方法带来了障碍。

谢谢您的精彩回答。如果我成功了,我会尝试你的解决方案,而不是在这里分享。