Click here to Skip to main content
Click here to Skip to main content

How To Use a Single Resource Component for your Images and Mixing C# and VB in the Same NETCF Solution

, 4 Jun 2009 GPL3
Rate this:
Please Sign up or sign in to vote.
Snippets show the steps and workarounds of issues while implementing it

Introduction

Having the images and/or text used through an application packed into a single resource component which is included into your main assembly is very attractive for an application as it makes the deployment set compact. Moreover, loading these images from code is much less prone to errors since otherwise there will be a bunch of images spread out in some folder. 

Furthermore when working on full applications, sometimes it is a necessary to mix C# and VB due to either end-user requests or the need to interface with APIs and/or legacy library calls and some of the arguments for those are specific for either language and finding the equivalent is cumbersome or the conversion just does not work.

This article covers both topics as I ran into this and had to dig a bit deep to get an actual working solution. The basics are straightforward but the details are what needed some research and some extra tools/steps as the Microsoft documentation is a bit vague, nothing new there. 

1. The Single Resource Component as Part of the Main Assembly

1.1 Creating the Resource Component 

First we create a resource component: Right click on the solution and select Add Component on the pop up menu. This will display different templates, select a resource file:

An extra Resource item will be listed on your solution, now click on the newly added resource item. You will get the option to add resources, do add your images, in our case we picked a couple of pre-cooked images. Upon completion you'll see there will also be a resources folder created under your solution, and your images will be listed there. For the method shown here, make sure that each of the images is set as an embedded resource.

1.2 Retrieving the Images from the Resource Component

OK, now the code for calling is listed below. The highlighted section shows the syntax to extract the specific image from the resource. The namespaces needed here are System.Reflection for Assembly interface and System.IO for Streaming.

private void btnLoad_Click(object sender, EventArgs e)
{
    //load the images from the resource
     string start_name = "resource_sample"; // the target EXE (or DLL if mixed code mode)
     //set the basic drawing
     displayBuffy = new Bitmap(200,200);
     //set ip the screen canvas
    Graphics displayCanvas = Graphics.FromImage(displayBuffy);
     Bitmap bmp;
     // Now grab the image from the resource as a stream
    Assembly assembly = Assembly.GetExecutingAssembly();
    string strRes = start_name + ".Resources.bandera_checker.gif";
    Stream stream = assembly.GetManifestResourceStream(strRes);
    bmp = null;
    try
    {
        bmp = new Bitmap(stream);
    }
    catch { }
    stream.Close();
     //displayCanvas.DrawImage(bmp, 10, 10);
    displayCanvas.DrawImage(bmp, new Rectangle(5, 5, bmp.Width / 3, bmp.Height / 3),
        new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
     //show on the form
    Invalidate();
}  // --- end of btnLoad_Click --
private void Form1_Paint(object sender, PaintEventArgs e)
{
    if (displayBuffy != null)
    {
        Graphics g = e.Graphics;
        g.DrawImage(displayBuffy, 0, 0);
    }
}  // --- end of  Form1_Paint ---

1.3 Caveats and Workaround  

Up to here nothing exciting. Of course if you only have one or two images, it will all work beautifully, but when building large applications, quite a few images are needed and they usually are modified as the development goes on. But while doing this, the code will eventually not load a specific image no matter how deep your debug goes. To solve this, first we need to double check the name and path of the image in the EXE, due to the many changes made sometimes it either gets moved or is not included. The Visual Studio tool called ILDASM.exe comes pretty handy here, loading your EXE (or DLL for mixed language solutions) will allow you to see the actual path to the included resources, just click on the MANIFEST as shown in the picture below and you will see the actual details for the specific image or if it is actually included in the resource component. The ILDASM.exe is part of the framework SDK. If you don't have it, it can be downloaded from here.

fig3.jpg

With this, it is straightforward to double check if the specific images were actually included in the resource. As we well know, when the code grows in size and there are a large number of images being modified, it does not take long to get them out of place or hit a glitch in the VS where it ends up skipping them.  

2. Mixing C# and VB in the Same Solution

As stated at the beginning, for many reasons it may be necessary to have mixed code, sometimes the end-user has some older code which usually is in VB and wants to still use it and maintain it or some other similar reasons. For this, we can easily add a VB section as a DLL and it is all good. It can go either way, e.g. having the main code in VB and adding the companion as C# or the other way. In the sample here C# will be the main code and the companion code will be in VB.

In essence, all we need to do is add another project to the current solution in the other language (VB in the sample below), add a reference to the companion code and use the proper syntax.

2.1 Creating the VB Section

The first step is to add another project to our current solution. If you have the VS installed by default, you will not see the option to add another project. To enable it, go to Tools->Options->Projects & Solutions and make sure you check always show solution as in the figure below:

fig4.jpg

So now you will get the solution view, highlight the solution and click Add New Project in the pop up, select the VB smart_device type as shown in the figure below:

fig5.jpg

On the next screen, we select the type as class library and we are ready to go. This will make the VB section a DLL where the needed VB routines will live. 

Our project will now list a class vb file under the newly added VB project. Inside this file we can put our library of VB routines. In a real world scenario where we have many routines, it makes  sense if we group routines with some common behaviour and/or handling  into a respective namespace. Such code is listed below: 

' All we need is to define our little home-brewed namespace and
' we are good to go with the mix

Namespace resource_sample_VB
    Public Class VB_Class_1
        Public Sub My_add_date(ByRef this_date As Date, ByVal days_2_add As Integer)
            Dim tmp_date As Date
            tmp_date = this_date
            Try
                tmp_date = tmp_date.AddDays(days_2_add)
            Catch
                tmp_date = this_date
            End Try
            this_date = tmp_date
        End Sub
    End Class
End Namespace

2.2 Calling VB from the C# Code

Finally we need to call this VB code from the main Project (C#). Since we made the VB code as a class library, the code will be compiled into a DLL. We need this DLL to be available to the  main Project. To do so, a reference to the VB DLL needs to be added as in the figure below:  

fig7.jpg

One small issue here is that while browsing to make a reference of the VB DLL at the very  beginning there will be no such DLL as the VB project has not been built yet. A quick workaround is to highlight the vb project and build it from the Build Menu, afterwards you can go to the references and browse for the DLL.   

Finally from C#, this is the syntax to call it

.
.
.
using System.Reflection; // Needed for Assembly
using System.IO;         // Needed for Stream
using resource_sample_VB_pieces.resource_sample_VB; // from our VB section
.
.
.
        private void btn_Add2Date_Click(object sender, EventArgs e)
        {
           // instantiate the VB class
           VB_Class_1 vb_tools = new VB_Class_1();

           DateTime thisDate = DateTime.Parse (textDate.Text);

           //call the VB method
           vb_tools.My_add_date(ref thisDate, Int32.Parse( textDays.Text ));
           //print out the result carried out by VB
           LblResult.Text = thisDate.ToString("d");


        } // --- end of btn_Add2Date_Click ---

2.3 Simple Output of the Code

In our sample code, the btnLoad_Click loads the image from the Resource component and the btn_Add2Date_Click button passes the values on the textboxes to the VB and the simple date calculation is printed out. 

fig6.jpg

Final Thoughts 

Statistically, old VB code is used from legacy code and/or the end-user wants to maintain it. The mixing code shown above allows to cover such a case where the preferred C# runs along with the VB code. Also the resource component or another set of resources could be also placed on the DLL to make it more memory efficient. 

Of course, this is not the only way to accomplish this, but it is tested and it works.

History

  • 4th June, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

becker666
Software Developer (Senior) BSC Inc
United States United States

Becker Cuéllar is an independent developer(C#/C++/J2ME/VB/perl) on the Washington DC corridor and focuses on developing/integrating web interfaces with Databases(MSSQL, MySQL, Oracle, Sybase), with mobile devices, scripting(perl/php/javascript) and with MS and Linux(RHE) based backends. Aditionally a full Mobile architect/developer for custom applications for Windows Mobile NETCF , Blackberry J2ME, Android, PalmOS and iPhone.
 
You'll find him traveling and hiking somewhere on this planet when not working on a project or on a road course race track tweaking his engine and attempting to improve his lap times.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 4 Jun 2009
Article Copyright 2009 by becker666
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid