Consultingwerk Blog

UltraControls, .NET Assemblies and deployment, a follow up

by Marko Rüterbories | Jul 18, 2011

This is a follow up post on the „a few words on OpenEdge UltraControls and deployment” post. Traditionally Progress R-code is compatible a few minor versions up and down. So it would be expected that 10.2A R-code should work on 10.2B and 10.2B R-code works on 10.2A as long as you do not use any of the new features of 10.2B in the ABL source code.

The thing that does change this rule with GUI for .NET are references to .NET Assemblies.  As described in the previous post on this topic references to 3rd party assemblies (including version information and vendor public key token) are written to the R-code. For 3rd party assemblies references can be resolved using various strategies (deploying the required assemblies to the application directory or the GAC). Some more details on how this will be resolved further in this post.

The one Assembly reference that cannot be resolved by deploying whatever Assembly version is required is the %DLC%\bin\Progress.NetUI.dll. This assembly contains that Progress built in .NET objects like the Progress.Windows.Form or Progress.Data.BindingSource classes. This will make it impossible to use GUI for .NET R-code compiled on a different Progress version. This is what effectively removes the version compatibility between 10.2A and 10.2B R-code (in both orders). It is only supported to use R-code between service packs as described in the previous post.

Deploying 3rd party assemblies

A .NET Assembly is a .DLL file containing compiled .NET classes. See http://en.wikipedia.org/wiki/.NET_assembly for additional information. The Global Assembly Cache (GAC) is a place on the Windows client that contains Assemblies that can be used by multiple applications. Assemblies can be stored in multiple versions and languages and allow verification of the vendor/publisher using private/public key pairs. More information can be found on MSDN or here http://en.wikipedia.org/wiki/Global_Assembly_Cache

Progress looks for Assemblies (identified by name and version and other possible attributes like vendor public key and language) in:

  • Application working directory OR alternatively the directory identified by the –assemblies parameter
  • %DLC%\bin for Progress.NetUI.dll
  • %DLC%\bin\infragistics\winforms for the Infragicstics Assemblies
  • the Global Assembly Cache (GAC)

Trapping Assembly load errors during application startup

A way to create a smarter error message should be the following CATCH block, given the use of structured error handling (ROUTINE-LEVEL ON ERROR UNDO, THROW in all .NET Forms) and the –errorstack startup parameter:

Catch-Assembly-load-error-source-code

This catch block should be placed in the startup procedure (-p parameter) or whatever procedure or class starts the first GUI for .NET Form. The constructor of the GUI for .NET Form executes the InitializeComponent method. This is the method that is generated by the VisualDesigner and loads the .NET Assemblies by NEW’ing the first GUI for .NET objects. With the code above we CATCH all .NET System.IO.FileNotFoundException errors. In the CATCH Block I check the stack trace of the error object (Exception) from where the error is thrown. If it’s thrown from the InitializeComponent method, it’s very, very likely loading a .NET Assembly that caused the error.  This is why we need the –errorstack startup parameter to make the detection of actual .NET Assembly load errors reliable.

In this case the FileName property of the error message object contains the name of the .NET Assembly that is not found.

Of course any subsequent load of .NET Forms might need the same or a similar CATCH block.