System.TypeLoadException referencing .NET 1.0 assemblies after .NET 4.0 migration

3

There's a project which was migrated from .NET 3.5 to .NET 4.0. The project has some references to .NET 1.0 assemblies, which are wrappers around COM objects. These .NET 1.0 assemblies and COM objects are product of an external company. The project compiles, but during runtime the first point when the software references an object defined in those 1.0 assemblies throws an exception:

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'.

The structure is marked as eligible for type equivalence, but it has a static or non-public field. The actual "structure" is an enum, in Reflector it looks like this:

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

The inner Exception is null. I can see a HRESULT of 0x80131522 (-2146233054), it means COR_E_TYPELOAD. I don't think I have any missing native dlls or assemblies, because our .NET works fine (and it uses the same code, same references).

How to fix this exception? Is there an easy way like specifying requiredRuntime in dll's config files or requiredTargetFramework in csproj's Reference section?

.net
com
migration
arcgis
asked on Stack Overflow Apr 1, 2013 by Csaba Toth • edited Apr 2, 2013 by Csaba Toth

2 Answers

0

If the circumstances are rough, then I can play rough too.

If we take a look at the actual error message, it's complaining about a "static or non-public" field in the "structure". The so called structure is actually an enum. Seemingly a wrapper enum on the COM layer. There are more dozens of various wrapper enums, each value is specified explicitly. Each of the enums also contain one private int variable named "value__". More specifically it looks like this: .field private specialname rtspecialname int32 value__

So why don't we just simply make them public:

  1. Disassemble the source with ildasm.
  2. Replace the private scope qualifier with public (if I recall it correctly: 49 places were replaced).
  3. Finally I compile a dll using ilasm from the modified IL.

And voila! The resulting dll (ESRI.MapObjects2.Core.dll) is 311.296 bytes, while the original is 323.584 bytes long, which makes me a little suspicious still. But if I overwrite the original dll in the GAC with my modified one, things work, our software doesn't blow up any more. I cannot confirm that everything 100% works, because I don't really know the GIS part of our software. But what I managed to get so far is OK. What can make someone worry: if the presence of the public variable would change any structure layout, it might cause the shift of the enum values, or other mixup. But hopefully it won't mix up anything. This is a quick hack, and in production it'd require the overwrite of the ESRI.MapObjects2.Core.dll in GAC after the MapObjects42 installation. Sigh. So I don't necessarily advise it to anyone, but it seems to work, and it gave me some satisfaction, some kind of revenge feeling. Hacking gave me a little happiness at the end of the day.

answered on Stack Overflow Apr 2, 2013 by Csaba Toth
0

Maybe possible solution for someone else: leaving out the .NET wrapper dll supplied by the vendor, and reference the underlying COM components directly form our project. This is described by Joe Parker in this thread: http://social.msdn.microsoft.com/Forums/zh-CN/vblanguage/thread/81c44b22-7bdc-4379-b0f6-953e1f96adfe. "We were able to solve this with with MapObjects 2.3 by referencing the controls as COM components instead of using the .NET dlls that come with MapObjects. Remove the ESRI.??? references from your project, then add references to the COM component "ESRI MapObjects 2.3". This wraps the COM component with .NET code that will actually run in VS 2010.

Then for the visual component, right-click in your toolbox and "Choose Items". Select "MapObjects 2.3 Map Control" from the "COM components" tab and then you will be able to add the control to a form. In my case I had to add it to a form then remove it just so Visual Studio would automatically add a reference to "AxMapObjects2" to the project. This reference has the visual control and some of it's supporting types. Then I just replaced our old AxMap references with AxMapObjects2.AxMap and other types with MapObjects2.Typename and everything worked (at least so far)."

His method can be generalized I think to other similar situations too: "app<->vendor .NET wrapper<->vendor COM objects". Unfortunately the method may not be as easy in our case, because we not only have a COM control hosted in the app, but in other modules of our software we have export and import capabilities and other scattered stuff. So I cannot just reference the GUI COM component there, I only need some core functionality in those other places. But I thought I'll share this finding, it may help to others. I'm 100% sure that not MapObjects2 and our app will be the only victim. As more project will migrate to .NET 4.0 and still have some old legacy burden can face this.

answered on Stack Overflow Apr 2, 2013 by Csaba Toth

User contributions licensed under CC BY-SA 3.0