如何在紧凑框架中从字节数组加载程序集

How to load an assembly from byte array in compact framework

我有使用智能扫描仪的旧客户,他们使用的是旧 windows 手机。因此,我一直在为这些智能设备开发紧凑的框架。我正在编写一个 class 库,它将为扫描仪硬件的接口提供插件类型的机制。我希望能够将来自扫描仪制造商的第三方程序集作为插件 DLL 中的嵌入式资源嵌入。我想这样做是为了避免在我的插件系统试图找到插件接口的实现时必须反映所有这些第三方 DLL。相当困难。问题是使用嵌入式资源,我可以获得程序集的字节,但 System.Reflection.Assembly.LoadAssembly(byte[]) 在紧凑框架中不可用。只有 LoadAssembly(AssemblyName)LoadAssembly(String)。如何在运行时从嵌入式资源加载这些程序集?

这是我现在拥有的:

    protected void LoadEmbeddedAssemblies()
    {
        Assembly asm = Assembly.GetCallingAssembly();
        foreach (string resName in asm.GetManifestResourceNames())
        {
            if (resName.EndsWith(".dll"))
            {
                try
                {
                    //this is an embedded assembly
                    using (Stream s = asm.GetManifestResourceStream(resName))
                    {
                        if (s.Length > Int32.MaxValue) throw new IOException("The assembly is to large");
                        byte[] bytes = new byte[s.Length];                            
                        s.Read(bytes, 0, Convert.ToInt32(s.Length));

                        //Assembly.Load(bytes) <- Compact Framework sucks
                    }
                }
                catch (Exception e)
                {
                    Log(new LogMessageRaisedEventArgs("AScannerBase", "LoadEmbeddedAssemblies", "Exception encountered while loading embedded assembly", e.Message));
                }
            }
        }
    }

Compact Framework 不支持以这种方式加载程序集。由于应用 运行 所使用的平台不太可能在给定设备上发生变化,因此只需确定第一个 运行 的设备类型并将适当的程序集提取到应用文件夹中,从那时起加载程序会为您找到它们。

出于几个原因,我不建议将供应商程序集嵌入您的程序集。首先,并非所有设备供应商 SDK 都是纯 .NET 的,可以或应该放在应用程序文件夹中。许多人要求他们的安装 运行 放置标准 dll、注册表项等。其次,您通过在中间件中嵌入每个供应商程序集来增加组件的大小,并且假设您支持多个供应商,那么大小可能会变得相当大。特别是如果设备在 GAC 中已经有扫描程序集,您将占用根本不需要的额外存储空间。

我使用并建议使用以下机制:

Application(s)......................................
   |                                               .
   V                                               .
Generic scanning abstraction lib                   . (Assembly.LoadFrom based
   A                                               .  upon convention or XML 
   |                                               .  configuration file)
Vendor Specific Implementation of abstraction <.....
   |                                               
   V                                               
Vendor SDK 

通过这种方式,您可以在创建 CAB 时设置 "plugins",包括根据配置文件或其他命名约定动态加载它们的信息。应用程序确实知道或关心加载了哪个抽象实现,只是它符合抽象。

我看到了两种可能的解决方案来支持来自一个应用程序的不同设备:

  1. 您使用您的方法并嵌入所需的设备程序集,并且由于不支持 System.Reflection.Assembly.LoadAssembly(byte[]),请先将程序集保存到文件系统,然后加载它.这样你就有了一个包含各种不同运行时文件的大型应用程序,其中只保存所需的运行时并加载 to/from 文件系统。

  2. 您使用像 PocketMEF 这样的插件系统,并有不同的子目录来加载供应商特定的程序集和本机 DLL。朗姆酒时间可以根据供应商动态加载。

在这两种情况下,您都必须定义一个接口层并实现 类 来为不同供应商的 SDK 实现接口。

有关如何使用 PocketMEF 进行硬件抽象的文章位于 http://www.hjgode.de/wp/2012/02/16/mobile-development-compact-framework-managed-extension-framework-mef/

另一个使用 pocketMEF 的多个接口示例位于 https://github.com/hjgode/intermeccontrols/blob/master/DPAG7

而且,cTacke 是对的,大多数 .NET 供应商程序集需要额外的本机库(即 Intermec Barcode Scanner .NET 程序集需要本机 DLL itcscan.dll)。有时这些是预安装在 windows mobile/CE 设备上,有时需要先安装它们。安装可能意味着仅复制 DLL 或(我不知道供应商使用它),安装额外的 COM 接口等,需要在使用前先注册。