Silverlight中动态加载的程序集调用DllImprot来锁定文件



我的silverlight 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调用一些第三方方法。

FreeProducerLibray调用:

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] /* unnecessary, isn't it? */
public static extern bool FreeLibrary(IntPtr hModule);

之后,我在不同的视图模型中有一个方法,它试图打开生产者库文件来计算哈希码,我得到"无法访问文件,因为它正在被另一个进程使用"。

我试着在扫描器类(动态加载程序集)中计算哈希码,它是好的,所以我怀疑这是这个过程。但是为什么免费图书馆还不够呢?

你能给我一些建议吗?我应该尝试以某种方式处置userScanner字段吗?

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

你漏掉了最重要的代码,但这句话足以诊断你的问题。pinvoke编组程序还调用DLL上的LoadLibrary()。所以DLL的引用计数是两个。你的FreeLibrary()调用卸载它,文件保持锁定。

你可以通过再次调用FreeLibrary()来解决这个问题。这个卸载DLL,但这也在您的程序中放置了一个定时炸弹。你不能再安全地打这些电话了。pinvoke编组程序仍然确信DLL已加载,因此它不会重新生成为导入函数生成的存根。它们指向以前加载函数的地址,而不是现在加载函数的地址。它将看起来工作,特别是当您在人工测试中这样做时。但是迟早,DLL不能在相同的地址再次被重新加载,因为它的地址空间被用于其他东西,你的程序将失败与硬崩溃。

如果你想让这个工作,那么你不能对这些方法使用[DllImport]。相反,您必须做pinvoke编组器所做的工作,并为您使用的每个入口点调用GetProcAddress(),并使用Marshal.GetDelegateForFunctionPointer()使其可调用,使用您声明的与本机函数签名匹配的委托。工作,它不漂亮。

更好的选择是使用单独的辅助进程来进行这些调用并与之互操作。现在它是安全的,让帮助进程终止确保了pinvoke存根的消失和DLL的解锁。不确定Silverlight中什么是实用的,它在设计时并没有把进程互操作放在功能列表的前列。没有Process类,这会给方法带来漏洞。

最新更新