views:

29

answers:

2

I have a controls library which I've added a .resx file to (ImageResources.resx). It contains two .png images which I subsequently added.

In that same library I have a control which loads a couple of images to do some custom drawing, but I don't seem to be able to load the resources:

void GTableLayoutPanel::SetBorderImagesFromManifest(String^ topLeftCornerImageName, String^ topImageName)
{
    // Grab the assembly this is being called from
    Assembly^ assembly = Assembly::GetExecutingAssembly();

    // Grab the images from the assembly
    Stream^ stream = assembly->GetManifestResourceStream(topLeftCornerImageName);
    Image^ topLeftImage = System::Drawing::Image::FromStream(stream);
    stream = assembly->GetManifestResourceStream(topImageName);
    Image^ topImage = System::Drawing::Image::FromStream(stream);

    // Update the internal store from the supplied images
    SetBorderImages(topLeftImage, topImage);
}

...gives me errors complaining that stream is null which suggests my call to GetManifestResourceStream is failing.

The images are called group_box_top.png and group_box_top_left.png and I'm calling the image loader as follows:

SetBorderImagesFromManifest("group_box_top_left.png", "group_box_top.png");

I've also tried:

SetBorderImagesFromManifest("group_box_top_left", "group_box_top");

...because the files appear in the .resx file without the .png extensions, but this gives the same error.

Have I missed a step here?

[Edit] I tried the suggestion in that final link and I get:

MyControlsLib.ImageResources.resources

So now I've tried referencing:

Stream^ strm1 = assembly->GetManifestResourceStream("MyControlsLib.ImageResources.resources.group_box_top_left");
Stream^ strm2 = assembly->GetManifestResourceStream("MyControlsLib.ImageResources.resources.group_box_top_left.png");
Stream^ strm3 = assembly->GetManifestResourceStream("MyControlsLib.ImageResources.group_box_top_left");
Stream^ strm4 = assembly->GetManifestResourceStream("MyControlsLib.ImageResources.group_box_top_left.png");

...all of which return nullptr :-/

+1  A: 

I think the path to the resource item might need to be fully qualified:

GetManifestResourceStream("MyNamespace.ImageResources.group_box_top_left")

This link shows a C# example (sorry), notice when creating the stream it has the namespace in the arguments:

http://support.microsoft.com/kb/319292

This also goes onto how to find the fully qualified path to a resource:

http://stackoverflow.com/questions/27757/how-can-i-discover-the-path-of-an-embedded-resource

Adam
I _did_ use the code in the question you linked and it gave me `MyControlsLib.ImageResources.resources` as per my edit..
Jon Cage
+1: Thanks for the suggestions. None of them quite worked, but it at least put me on the right path.
Jon Cage
+1  A: 

I finally got the magic combination for a C++/CLI solution. So just in case anyone else has this issue:

Method 1 (via .resx file)

  1. Add the image files (I used .pngs, but bitmaps etc. work too).
  2. Add a resource file:
    1. Got to Solution Explorer.
    2. Right-click on Resource Files in the project you're adding to
    3. Select Add > New Item..
    4. Choose Visual C++ > Resource > Assembly Resource File (.resx). I nameed mine "ImageResources.resx"
  3. Add the images:
    1. Double click on "ImageResources.resx" in Solution Explorer
    2. Click on the Add Resource button and select Add Existing File...
    3. Select the images you want to embed. I added group_box_top.png and group_box_top_left.png which appear in the .resx file as group_box_top and group_box_top_left.

You can then grab the images from the manifest with:

// Grab the assembly this is being called from
Assembly^ assembly = Assembly::GetExecutingAssembly();
AssemblyName^ assemblyName = assembly->GetName();

// Grab the images from the assembly
ResourceManager^ rm = gcnew ResourceManager(assemblyName->Name+".ImageResources", assembly);
Bitmap^ topLeftImage = (Bitmap^)rm->GetObject("group_box_top_left");
Bitmap^ topImage = (Bitmap^)rm->GetObject("group_box_top");

Note that the ImageResources string passed into the ResourceManager constructor must match the name of your .resx file.

Method 2 (via linker)

  1. Add the files:
    1. Right-click on your project
    2. Go to Linker -> Input
    3. Add the files you want to embed to the Embed Managed Resource File property. I added PingSend.wav here.

To get access to the files simply do:

System::Reflection::Assembly^ assembly = Assembly::GetExecutingAssembly();
System::Media::Sonudplayer^ pingPlayer = gcnew System::Media::SoundPlayer(assembly->GetManifestResourceStream("PingSend.wav"));

..which in this case, loads the audio file ready to play back.

Jon Cage