1

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 :-/

M4N
  • 94,805
  • 45
  • 217
  • 260
Jon Cage
  • 36,366
  • 38
  • 137
  • 215
  • Don't try my exact suggestion - I'm not sure you require the ImageResources part and might still need to include the extension. Use the code in the question about getting the names to get the real names and subsitute those in the code. Also, I'd comment on people's answers as I don't get any notifications about your question. – Adam Houldsworth Jul 19 '10 at 16:07
  • See the comment on your answer.. – Jon Cage Jul 19 '10 at 16:15
  • Ah right, not sure then - the problem is likely the qualified name, but I'm not sure how this applies to C++.NET – Adam Houldsworth Jul 19 '10 at 17:53

3 Answers3

5

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. Go 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
  • 36,366
  • 38
  • 137
  • 215
1

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:

How can I discover the "path" of an embedded resource?

Community
  • 1
  • 1
Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • I _did_ use the code in the question you linked and it gave me `MyControlsLib.ImageResources.resources` as per my edit.. – Jon Cage Jul 19 '10 at 16:13
  • +1: Thanks for the suggestions. None of them quite worked, but it at least put me on the right path. – Jon Cage Jul 20 '10 at 12:40
0
System::Reflection::Assembly^ assembly = System::Reflection::Assembly::GetExecutingAssembly();

Resources::ResourceManager^ rm = gcnew Resources::ResourceManager("namespaceName" + ".ResourceFileName", assembly);

this->button->Image = cli::safe_cast<Image^>(rm->GetObject("image1"));
Nico
  • 51
  • 4