2
votes

I am using .net 4.0, with POS.net 1.12 and I create a hardware class in a new child AppDomain so that any unhandled exceptions do not kill my parent AppDomain.

I can create the child AppDomain and make calls to it no problem. However, if I try to unload the AppDomain I get the exception "CannotUnloadAppDomainException".

I have googled the issue and the exception normally occurs when threads cannot be killed. I do not actually create any new threads in the child class.

I managed to pinpoint the piece of code that causes this error. If I create the POS hardware class and it only creates POS objects then it works fine. If, however, I call method "Open()" on any piece of hardware, then this exception occurs when unloading. Now before I attempt the unload, I close down all hardware and I have made sure the clean up code gets hit, so I am unsure what the issue is.

Here is the code to create and unload the AppDomain:

AppDomain hardwareDomain = AppDomain.CreateDomain("Hardware domain");

IHardwareManager hardwareManager =
        (IHardwareManager)hardwareDomain.CreateInstanceFromAndUnwrap(typeof(OposHardwareManager).Assembly.Location,
                                                                     typeof(OposHardwareManager).FullName);

hardwareManager.StartupHardware();

hardwareManager.CloseDownHardware();
hardwareManager = null;

// **** causes exception
AppDomain.Unload(hardwareDomain);

And here is the hardware class:

public class OposHardwareManager : MarshalByRefObject, IHardwareManager
{
    private PosExplorer _posExplorer;
    private PosPrinter _printer;

    public void StartupHardware()
    {
        // create the hardware explorer
        this._posExplorer = new PosExplorer();

        // create and enable the printer
        DeviceInfo printerInfo = this._posExplorer.GetDevice(DeviceType.PosPrinter);
        PosDevice printerDevice = this._posExplorer.CreateInstance(printerInfo);
        this._printer = (PosPrinter)printerDevice;

        // ***** this line here, if run, causes the exception on unload 
        this._printer.Open();
        this._printer.Claim(2000);
        this._printer.DeviceEnabled = true;
    }

    public void CloseDownHardware()
    {
        this._printer.Release();
        this._printer.Close();

        this._printer = null;
        this._posExplorer = null;
    }
}

Any ideas?

3

3 Answers

1
votes

If you are referencing a type in your creating domain (like you do with typeof(OposHardwareManager)), the assembly will be loaded in that domain too. When that happens, iow types crossing the domain boundary 'upwards', the created domain cannot be unloaded.

I suggest you do not reference the assembly containing OposHardwareManager and simply create it with the full qualified name instead. This may involve some refactoring.

1
votes

In the documentation of AppDomain.Unload it is remarked that:

If a thread does not abort, for example because it is executing unmanaged code, or because it is executing a finally block, then after a period of time a CannotUnloadAppDomainException is thrown in the thread that originally called Unload.

This is probably your case. Look at the documentation of PosDevice on how to properly release the resource.

Also note that an unhandled exception thrown by a thread created in the new AppDomain will crash your whole application. In the documentation of AppDomain.UnhandledException Event it is remarked that:

In the .NET Framework versions 1.0 and 1.1, an unhandled exception that occurs in a thread other than the main application thread is caught by the runtime and therefore does not cause the application to terminate. Thus, it is possible for the UnhandledException event to be raised without the application terminating. Starting with the .NET Framework version 2.0, this backstop for unhandled exceptions in child threads was removed, because the cumulative effect of such silent failures included performance degradation, corrupted data, and lockups, all of which were difficult to debug.

0
votes

Not sure would this help but I founded the same error on Win 7 and XP. During app exit then the app crashed and error thrown. But the fault came from Report Viewer so when unload the form please make sure call

reportviewer.Reset();