3

有一个项目从 .NET 3.5 迁移到 .NET 4.0。该项目有一些对 .NET 1.0 程序集的引用,这些程序集是 COM 对象的包装器。这些 .NET 1.0 程序集和 COM 对象是外部公司的产品。该项目可以编译,但在运行时,当软件引用那些 1.0 程序集中定义的对象时,第一个点会引发异常:

System.TypeLoadException: Could not load the structure 'ESRI.MapObjects2.Core.ShapeTypeConstants' from assembly 'ESRI.MapObjects2.Core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8fc3cc631e44ad86'.

该结构被标记为符合类型等效条件,但它具有静态或非公共字段。实际的“结构”是一个枚举,在 Reflector 中它看起来像这样:

[Guid("B027CAB1-6908-11D2-AF98-006097DA3688")] public enum ShapeTypeConstants { moShapeTypeEllipse = 0x1a, moShapeTypeLine = 0x16, moShapeTypeMultipoint = 0x18, moShapeTypePoint = 0x15, moShapeTypePolygon = 0x17, moShapeTypeRectangle = 0x19 }

内部异常为空。我可以看到 0x80131522 (-2146233054) 的 HRESULT,这意味着 COR_E_TYPELOAD。我不认为我缺少任何本机 dll 或程序集,因为我们的 .NET 工作正常(并且它使用相同的代码、相同的引用)。

如何解决此异常?是否有一种简单的方法,例如在 dll 的配置文件中指定 requiredRuntime 或在 csproj 的参考部分中指定 requiredTargetFramework?

4

2 回答 2

0

如果情况很恶劣,那我也可以玩得很粗糙。

如果我们查看实际的错误消息,它会抱怨“结构”中的“静态或非公共”字段。所谓结构其实就是一个枚举。似乎是 COM 层上的包装器枚举。还有几十种不同的包装枚举,每个值都是明确指定的。每个枚举还包含一个名为“value__”的私有 int 变量。更具体地说,它看起来像这样: .field private specialname rtspecialname int32 value__

那么我们为什么不简单地将它们公开:

  1. 用 ildasm 拆解源码。
  2. 用 public 替换 private 范围限定符(如果我没记错的话:替换了 49 个位置)。
  3. 最后,我使用修改后的 IL 中的 ilasm 编译了一个 dll。

瞧!生成的 dll (ESRI.MapObjects2.Core.dll) 是 311.296 字节,而原来的长度是 323.584 字节,这让我还是有点怀疑。但是,如果我用我修改过的 dll 覆盖 GAC 中的原始 dll,一切正常,我们的软件就不会再崩溃了。我无法确认一切都 100% 有效,因为我并不真正了解我们软件的 GIS 部分。但是到目前为止我设法得到的还可以。让人担心的是:如果公共变量的存在会改变任何结构布局,它可能会导致枚举值的偏移或其他混淆。但希望它不会混淆任何东西。这是一个快速破解,在生产中需要在安装 MapObjects42 后覆盖 GAC 中的 ESRI.MapObjects2.Core.dll。叹。所以我不一定建议任何人,但它似乎奏效了,它给了我一些满足感,一种报复的感觉。黑客在一天结束时给了我一点快乐。

于 2013-04-02T00:22:29.863 回答
0

对其他人来说可能的解决方案:省略供应商提供的 .NET 包装器 dll,并直接从我们的项目中引用底层 COM 组件。Joe Parker 在此线程中对此进行了描述:http: //social.msdn.microsoft.com/Forums/zh-CN/vblanguage/thread/81c44b22-7bdc-4379-b0f6-953e1f96adfe。“我们能够使用 MapObjects 2.3 解决这个问题,方法是将控件引用为 COM 组件,而不是使用 MapObjects 附带的 .NET dll。从您的项目中删除 ESRI.??? 引用,然后添加对 COM 组件的引用” ESRI MapObjects 2.3"。这用实际在 VS 2010 中运行的 .NET 代码包装了 COM 组件。

然后对于可视组件,右键单击您的工具箱并“选择项目”。从“COM components”选项卡中选择“MapObjects 2.3 Map Control”,然后您就可以将控件添加到表单中。在我的情况下,我必须将其添加到表单中,然后将其删除,这样 Visual Studio 就会自动向项目添加对“AxMapObjects2”的引用。此参考具有视觉控制和一些支持类型。然后我只是用 AxMapObjects2.AxMap 替换了旧的 AxMap 引用,用 MapObjects2.Typename 替换了其他类型,一切正常(至少到目前为止)。”

我认为他的方法也可以推广到其他类似情况:“app<->vendor .NET wrapper<->vendor COM objects”。不幸的是,在我们的案例中,该方法可能并不容易,因为我们不仅在应用程序中托管了一个 COM 控件,而且在我们软件的其他模块中,我们还具有导出和导入功能以及其他零散的东西。所以我不能只在那里引用 GUI COM 组件,我只需要在其他地方的一些核心功能。但我想我会分享这个发现,它可能对其他人有所帮助。我 100% 确定不是 MapObjects2,我们的应用程序将是唯一的受害者。随着越来越多的项目将迁移到 .NET 4.0 并且仍然有一些旧的遗留负担可以面对这个问题。

于 2013-04-02T00:40:32.743 回答