Search code examples
c#loadingembedded-resource

Resource Loading works in SharpDevelop but not when Compiled Manually


I'm making a game engine and wondering about how to load resources.

I'm currently using this code for it.

public static Stream GetResourceStream(string name) {
    string asmname = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location).Replace('\\', '.').Replace('/', '.');
    return Assembly.GetEntryAssembly().GetManifestResourceStream(asmname + "." + name.Replace('\\', '.').Replace('/', '.'));
}

And using it as

Image img = Image.FromStream(GetResourceStream("Resources/image.png"));

It is working in the current form in SharpDevelop but If I compile the source from command-line like

csc.exe /t:winexe /res:Resources/image.png Game.cs

It is returning null stream. Having listed the resources with

foreach (var name in typeof(this).Assembly.GetManifestResourceNames())
{
    MessageBox.Show(name);
}

It's listing image with simple name, no package name or folder name.

What is the best way to load resources in the entry assembly? (I'll have a separate GameEngine.dll)

Thanks.


Solution

  • Whilst I cannot tell you the best way to load resources in your assembly I can tell you what the problem is.

    If you run MSBuild from the command line you will see that when SharpDevelop is building your project it is using a slightly different command line option. Assuming MSBuild is on your path then running something like the following will show you what command line options are being passed to csc:

    msbuild /t:Rebuild YourSolution.sln
    

    The /res or /resource parameter will look a bit different. It will be something like:

    /resource:Resources\image.png,YourAssemblyRootNamespace.Resources.image.png 
    

    If you read the documentation on the /resource compiler option you will see that it allows you to specify an identifier which is the name used as the embedded resource name. In the example above this identifier is

    YourAssemblyRootNamespace.Resources.image.png
    

    You can also override this identifier either on the command line, as shown above, or inside SharpDevelop by setting the LogicalName property for the image.png file. To set that right click the file in the Projects window and select Properties.

    In your situation I would be tempted to set my own logical names for the images. So if you use image.png for your logical name then your GetResource method becomes simpler:

    public static Stream GetResourceStream(string name) {
        return Assembly.GetEntryAssembly().GetManifestResourceStream(name);
    }
    
    Stream stream = GetResourceStream("image.png");
    

    This should work both when compiling using SharpDevelop or on the command line if you use the /res command line option:

    /res:Resources\image.png,image.png
    

    It should also work using the command line option you were trying to use:

    /res:Resources\image.png