4

Summary

Goal

I have two C# projects. The output of the first project is a DLL (output type in Visual Studio is set to Class Library) that lets me control my application from other languages. It basically starts an instance of my application without showing any of its UI windows. I can use this DLL in other programming languages (like Python, Matlab) without any problems.

But now I want to use that DLL in another C# project. To do this, I have added the DLL as a reference in my project. To initiate an instance of my application, I create an object of the type that is defined in the DLL:

namespace MyDLL
{
    class Program
    {
        static void Main(string[] args)
        {
            MyApp app = new MyApp();
        }
    }
}

This results in an exception:

System.InvalidOperationException: 'The 'ResourceAssembly' property of the 'Application' type cannot be changed after it has been set.'

The cause of this exception is the fact that MyApp sets the ResourceAssembly in order to load the application's resources (things like UI images):

System.Windows.Application.ResourceAssembly = typeof(AppBase.MainWindow).Assembly; 

What I've tried

Since Application.ResourceAssembly can only be set once, I tried a way around it as described in the second solution of this StackOverflow post. This prevents the ResourceAssembly exception from being thrown.

The DLL object the attempts to start but then throws the following exception:

System.InvalidOperationException: 'The Application object is being shut down.'

The InnerException value of this exception is null, but its source value is PresentationFramework. This is the StackTrace of the exception:

at System.Windows.Application.GetResourcePackage(Uri packageUri)
at System.Windows.Application.GetResourceOrContentPart(Uri uri)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at App.MainWindow..ctor(Boolean showWindow)
at MyDLL.MyApp.startApp()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

2 Answers2

2

Well, the exception states The Application object is being shut down.. This might mean that your wpf application is prematurely ending, so I'd try debugging what's happening inside the app.

One thing that I did notice, is that your app startup code doesn't seem quite right.

static void Main(string[] args)
{
    MyApp app = new MyApp();
}

Assuming that MyApp is a Wpf Application class, you're lacking the required call to the Run method, which requires a Window as an argument.

So I'd expect your code to look something like:

static int Main(string[] args)
{
    MyWindow window = new MyWindow();
    MyApp app = new MyApp();
    return app.Run(window);
}

Also, note how I've changed the return type of Main, so we can return the appropriate return code.

Edit: (I clearly missed the part about the ResourceAssembly)

You can absolutely set the Resource Assembly for the application, but as you've correctly stated, you're not allowed to do it twice.

Where do you set it the first time? And why are you setting it, if you know that you need to set it to something else later?

Unfortunately, I don't think we'll be able to help, without further information.

Doctor Jones
  • 21,196
  • 13
  • 77
  • 99
  • The Resource Assembly is only set explicitly in the DLL to point the application to the required resources (things like images that are used in the UI). I don't set the Resource Assembly explicitly in the C# app that tries to use the DLL. So I actually set it just once. Is there some kind of default setting that could be applied, which results in it being set twice? – jasper-bosch Nov 21 '19 at 12:54
  • @jasper-bosch, you can only set the resource assembly manually under special circumstances. The WPF app must be hosted from an unmanaged assembly, or it must be loaded into a new app domain, using a method other than execute assembly. How are you referring to your app? If it is merely a DLL reference, or you have loaded the assembly, then it will be in the same app domain as your parent app, which will not work. – Doctor Jones Nov 21 '19 at 14:08
1

As an option, you can publish your class library as NuGet Package in local package source and use it it in other solutions as regular NuGet Package.