none
Attaching any type of file in VB.NET

    Question

  •  

    How to attach any type of file in VB.NET.

      I want information or if possible code to attach any type of file in VB.NET.

    Wednesday, April 16, 2008 4:28 AM

Answers

  • You'll have to read through my notes below. Mosft of it is C#, but thereare also some vb.net samples.

     

     

    The following is how to add an image to a project (or ANY kind of file) as an embedded resource. The image actually shows up in Intellisense under the global keyword. To do this, do the following: In Solution Explorer click Resources.resx file (click the ShowAllFiles button if you don't see it).This opens up a pane (just like the Form1 pane) and at the top will be AddResource dropdown menu. From the dropdown choose Add ExistingItem and then browse to the file. You can now see it in Intellisense (although you might still need to change the BuildType to "Embedded Resource" for deployment. In C# use the global keyword - here the Folder file is BMP type.

    Image imgForFolders = global::MyApp.Properties.Resources.Folder;

    In Vb.Net don't use the global keyword - instead use the My namespace

    My.Resources.MyFile

    You can add icons - EVEN TO TREEVIEWS - using this above method, but you must convert it to BMP like this:

    Icon icon1 = global:Tongue TiedtackTraceTree.Properties.Resources.Folder;

    Image img = icon1.ToBitmap();

    The above method created a problem when I tried to port my app to an identical project of different name (I was changing the "Indexer" app to the name "FullTextSearch). The designer wouldn't open for two reasons, regarding this line (in the designer-gneretaeed- code)

    this.pictureBox2.Image = global::Indexer.Resources.Downward

    The first problem is that the copy and paste retained the old app name in the path (see the word Indexer after the global keyword). With the new App, the word Indexer was no longer available in Intellisense, so I had to change it to the new name FullTexTsearch. This change gave this:

    this.pictureBox2.Image = global::FullTextSearch.Resources.Downward

    Next I had the problem that I had, this time, added the image as an ICO file so this required me to edit the designer code with the following cast from icon to bitmap:

    this.pictureBox2.Image = (System.Drawing.Image)global::FullTextSearch.Properties.Resources.Downward.ToBitmap();

    Again, you can only use the global keyword if you used the special pane for adding the resource to the project (the pane opens up when you click Resources.resx file in SE). If you add a document or image just using Project > AddReference, you can access it at the following path (for a document called MyDoc.Doc)

    string DestOnHardDrive = "C:\tempfile.doc"; //unpack MyDoc to a tempfile on the hard drive.

    Assembly executingAssembly = Assembly.GetExecutingAssembly();

    StreamReader sr = new StreamReader(executingAssembly.GetFile("MyNamespace.Resources.MyDoc.doc"));

    StreamWriter sw = new StreamWriter(File.Open(DestOnHardDrive, FileMode.Create));

    sw.Write(sr.ReadToEnd());

    Above, the command executingAssembly.GetFile returns a filestream, so I suppose you could load an imaeg this way. But note the path to the file was:

    MyNamespace.Resources.MyDoc.Doc

    But as VB.Net doesn't add namespaces to the project, I'm not sure what the path would be - I guess it would just be:

    Resources.MyDoc.Doc

    Anyway, back to the above method. Suppose you added, using the abvoe method, a Word document called WordDoc.Doc instead of an image. Access it like this:

    byte[] bytesIn = global::MyApp.Properties.Resources.WordDoc;

    System.IO.FileStream fs = System.IO.File.OpenWrite(@"C:\z.doc");

    fs.Write(bytesIn, 0, bytesIn.Length);

    fs.Close();

    By the way, the notation

    string filename = @"..\..\Resources\z.xls";

    searches two directories up, that is, searches 2 directories UP (not down) from the current directory which I believe is System.Environment.CurrentDirectory.

    Another way sometimes available for addding an iamge is when, say, you are adding an image for a button. When you click the Designer's browser button to select an image for a buton, the brower window let's you specify an embedded resource (assuming is is a bitmap (BMP file). Do NOT pre-add the image using SE but rather choose Image from the button Properties window and THEN browse (as I recall). The problems with doing it this way is that (1) You cannot use ICO files, so convert it to a BMP file first and (20 the Designer doesn't resize the image, so if the image is large, only a small part of it will show up on the button. The good news is that you get a much better looking image (assuming it was the proper size instad of being a large one). The code below not only made the image to smal, but it also gave it an ugly black background. I thought maybe saving it to disk is what was causing the image-quality problem, but even when I used a sheer stream (no disk save) I got the same result. I even tried loding the image into a pictureBox, still poor quality. I noticed that .Net cut the filesize down from 32x32 to 16x16, i think it does for any ICO file. So I tried changing the file extension to jpg, no luck.

     

    Anyway, if you want a REALLY simple way to do this using code, I found this line of code in the editor (the embedded image was called "Backward.ico" for the btnBackward button. Again, this won't resize the image, but it may be cleaner. (The global keyword means "Path"

    this.btnBackward.Image = global::FolderBrowserDialog.Properties.Resources.Backward;

    Or we could load a resource like this:

    MemoryStream ms = new MemoryStream(global::YourNamespace.Resources.MyImage);

    Another way to load the image cleanly (again, without resizing it) is to have the function below (funcGetIMageFromEmbeddedResources) extract the resource to a file and return that path, and then use the path in the following code (placed in the Form1 block):

    string pathToImage = funcGetImageFromEmbeddedResources("Backward.jpg");

    Icon icon1 = Icon.ExtractAssociatedIcon(pathToImage);

    btnBack.Image = icon1.ToBitmap();

    And then resize the image accordingly.

     

     

    Anyway to do all this using code, first add the image or file to SE - right-click proj in SE and choose Add Existing Item. Browse to the file.

    WARNING: IN SOLUTION EXPLORER YOOU MUST RIGHT-CLICK THE NEWLY ADDED FILE AND CHOOSE PROPERTIES IN ORDER TO CHANGE THE FILE'S DEFAULT BUILD TYPE FROM "CONTENT" TO "EMBEDDED RESOURCE." The good news is that any changes that you make to the file will automatically update the .resx file on the next build, even if you just hit f5 to do a test-run. To call this sub, all you need is the name of the file such MyDoc.doc (it loops through all embedded resource names looking for the specified filename).

    subOpenResourceFile("MyDoc.doc")

    and here's the code I finally decided upon - used two functions:

    private Image funcGetImageFromEmbeddedResource(string nameOfFile, int desiredWidth, int desiredHeight)

    {//Pass in zero as desired height if there is no need to resize.

    string pathToImage = funcExtractThisEmbeddedResourceToAFile(nameOfFile);

    Icon icon1 = Icon.ExtractAssociatedIcon(pathToImage);

    Image OriginalImage = icon1.ToBitmap();

    if (desiredHeight == 0 || desiredWidth == 0) return OriginalImage; //don't resize. .

    Bitmap ResizedImage = new Bitmap(desiredWidth, desiredHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    Graphics G = Graphics.FromImage(ResizedImage);

    G.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    G.DrawImage(OriginalImage, 0, 0, ResizedImage.Width, ResizedImage.Height);

    G.Dispose(); //

    return ResizedImage;

    }

     

    private string funcExtractThisEmbeddedResourceToAFile(string nameOfFile)

    { //we'll copy the file to the current directory while extracting it as an embedded resource.

    string pathToDestFile = System.Environment.CurrentDirectory + "\\" + nameOfFile;

    System.IO.FileInfo fi = new System.IO.FileInfo(pathToDestFile);

    if (fi.Exists) fi.Delete();

    System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

    foreach (string str in asm.GetManifestResourceNames())

    if (str.ToLower().IndexOf(nameOfFile.ToLower()) > -1) nameOfFile = str;

    System.IO.Stream fsIn = asm.GetManifestResourceStream(nameOfFile);

    byte[] bytesRead = new byte[fsIn.Length];

    fsIn.Read(bytesRead, 0, bytesRead.Length);

    System.IO.FileStream fsOut = new System.IO.FileStream(pathToDestFile, System.IO.FileMode.Create);

    fsOut.Write(bytesRead, 0, bytesRead.Length);

    fsOut.Close();

    return pathToDestFile;

    }

    In vb.net use something like this:

    Private Sub subExtractThisEmbeddedResourceToAFile(ByVal nameOfFile As String, ByVal pathToDestFile As String)

    Dim fi As New System.IO.FileInfo(pathToDestFile)

    If (fi.Exists) Then fi.Delete()

    Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()

    Dim fullNameOfFile As String = String.Empty

    For Each str As String In asm.GetManifestResourceNames()

    If str.ToLower().IndexOf(nameOfFile.ToLower()) > -1 Then fullNameOfFile = str

    Next

    Dim fsIN As System.IO.Stream = asm.GetManifestResourceStream(fullNameOfFile)

    Dim bytesRead(fsIN.Length = 1) As Byte

    fsIN.Read(bytesRead, 0, bytesRead.Length)

    Dim fsout As New System.IO.FileStream(pathToDestFile, System.IO.FileMode.Create)

    fsout.Write(bytesRead, 0, bytesRead.Length)

    fsout.Close()

    End Sub

     

    And then you just call the first function like this:

    button1.Image = funcGetImageFromEmbeddedResource("MyImage.jpg" ,32, 32)

    I also noticed that when I tried replacing the ICON code with the Image.FromFile code, I got a fuzzier image..

     

    Wednesday, April 16, 2008 6:28 AM

All replies

  • You'll have to read through my notes below. Mosft of it is C#, but thereare also some vb.net samples.

     

     

    The following is how to add an image to a project (or ANY kind of file) as an embedded resource. The image actually shows up in Intellisense under the global keyword. To do this, do the following: In Solution Explorer click Resources.resx file (click the ShowAllFiles button if you don't see it).This opens up a pane (just like the Form1 pane) and at the top will be AddResource dropdown menu. From the dropdown choose Add ExistingItem and then browse to the file. You can now see it in Intellisense (although you might still need to change the BuildType to "Embedded Resource" for deployment. In C# use the global keyword - here the Folder file is BMP type.

    Image imgForFolders = global::MyApp.Properties.Resources.Folder;

    In Vb.Net don't use the global keyword - instead use the My namespace

    My.Resources.MyFile

    You can add icons - EVEN TO TREEVIEWS - using this above method, but you must convert it to BMP like this:

    Icon icon1 = global:Tongue TiedtackTraceTree.Properties.Resources.Folder;

    Image img = icon1.ToBitmap();

    The above method created a problem when I tried to port my app to an identical project of different name (I was changing the "Indexer" app to the name "FullTextSearch). The designer wouldn't open for two reasons, regarding this line (in the designer-gneretaeed- code)

    this.pictureBox2.Image = global::Indexer.Resources.Downward

    The first problem is that the copy and paste retained the old app name in the path (see the word Indexer after the global keyword). With the new App, the word Indexer was no longer available in Intellisense, so I had to change it to the new name FullTexTsearch. This change gave this:

    this.pictureBox2.Image = global::FullTextSearch.Resources.Downward

    Next I had the problem that I had, this time, added the image as an ICO file so this required me to edit the designer code with the following cast from icon to bitmap:

    this.pictureBox2.Image = (System.Drawing.Image)global::FullTextSearch.Properties.Resources.Downward.ToBitmap();

    Again, you can only use the global keyword if you used the special pane for adding the resource to the project (the pane opens up when you click Resources.resx file in SE). If you add a document or image just using Project > AddReference, you can access it at the following path (for a document called MyDoc.Doc)

    string DestOnHardDrive = "C:\tempfile.doc"; //unpack MyDoc to a tempfile on the hard drive.

    Assembly executingAssembly = Assembly.GetExecutingAssembly();

    StreamReader sr = new StreamReader(executingAssembly.GetFile("MyNamespace.Resources.MyDoc.doc"));

    StreamWriter sw = new StreamWriter(File.Open(DestOnHardDrive, FileMode.Create));

    sw.Write(sr.ReadToEnd());

    Above, the command executingAssembly.GetFile returns a filestream, so I suppose you could load an imaeg this way. But note the path to the file was:

    MyNamespace.Resources.MyDoc.Doc

    But as VB.Net doesn't add namespaces to the project, I'm not sure what the path would be - I guess it would just be:

    Resources.MyDoc.Doc

    Anyway, back to the above method. Suppose you added, using the abvoe method, a Word document called WordDoc.Doc instead of an image. Access it like this:

    byte[] bytesIn = global::MyApp.Properties.Resources.WordDoc;

    System.IO.FileStream fs = System.IO.File.OpenWrite(@"C:\z.doc");

    fs.Write(bytesIn, 0, bytesIn.Length);

    fs.Close();

    By the way, the notation

    string filename = @"..\..\Resources\z.xls";

    searches two directories up, that is, searches 2 directories UP (not down) from the current directory which I believe is System.Environment.CurrentDirectory.

    Another way sometimes available for addding an iamge is when, say, you are adding an image for a button. When you click the Designer's browser button to select an image for a buton, the brower window let's you specify an embedded resource (assuming is is a bitmap (BMP file). Do NOT pre-add the image using SE but rather choose Image from the button Properties window and THEN browse (as I recall). The problems with doing it this way is that (1) You cannot use ICO files, so convert it to a BMP file first and (20 the Designer doesn't resize the image, so if the image is large, only a small part of it will show up on the button. The good news is that you get a much better looking image (assuming it was the proper size instad of being a large one). The code below not only made the image to smal, but it also gave it an ugly black background. I thought maybe saving it to disk is what was causing the image-quality problem, but even when I used a sheer stream (no disk save) I got the same result. I even tried loding the image into a pictureBox, still poor quality. I noticed that .Net cut the filesize down from 32x32 to 16x16, i think it does for any ICO file. So I tried changing the file extension to jpg, no luck.

     

    Anyway, if you want a REALLY simple way to do this using code, I found this line of code in the editor (the embedded image was called "Backward.ico" for the btnBackward button. Again, this won't resize the image, but it may be cleaner. (The global keyword means "Path"

    this.btnBackward.Image = global::FolderBrowserDialog.Properties.Resources.Backward;

    Or we could load a resource like this:

    MemoryStream ms = new MemoryStream(global::YourNamespace.Resources.MyImage);

    Another way to load the image cleanly (again, without resizing it) is to have the function below (funcGetIMageFromEmbeddedResources) extract the resource to a file and return that path, and then use the path in the following code (placed in the Form1 block):

    string pathToImage = funcGetImageFromEmbeddedResources("Backward.jpg");

    Icon icon1 = Icon.ExtractAssociatedIcon(pathToImage);

    btnBack.Image = icon1.ToBitmap();

    And then resize the image accordingly.

     

     

    Anyway to do all this using code, first add the image or file to SE - right-click proj in SE and choose Add Existing Item. Browse to the file.

    WARNING: IN SOLUTION EXPLORER YOOU MUST RIGHT-CLICK THE NEWLY ADDED FILE AND CHOOSE PROPERTIES IN ORDER TO CHANGE THE FILE'S DEFAULT BUILD TYPE FROM "CONTENT" TO "EMBEDDED RESOURCE." The good news is that any changes that you make to the file will automatically update the .resx file on the next build, even if you just hit f5 to do a test-run. To call this sub, all you need is the name of the file such MyDoc.doc (it loops through all embedded resource names looking for the specified filename).

    subOpenResourceFile("MyDoc.doc")

    and here's the code I finally decided upon - used two functions:

    private Image funcGetImageFromEmbeddedResource(string nameOfFile, int desiredWidth, int desiredHeight)

    {//Pass in zero as desired height if there is no need to resize.

    string pathToImage = funcExtractThisEmbeddedResourceToAFile(nameOfFile);

    Icon icon1 = Icon.ExtractAssociatedIcon(pathToImage);

    Image OriginalImage = icon1.ToBitmap();

    if (desiredHeight == 0 || desiredWidth == 0) return OriginalImage; //don't resize. .

    Bitmap ResizedImage = new Bitmap(desiredWidth, desiredHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    Graphics G = Graphics.FromImage(ResizedImage);

    G.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    G.DrawImage(OriginalImage, 0, 0, ResizedImage.Width, ResizedImage.Height);

    G.Dispose(); //

    return ResizedImage;

    }

     

    private string funcExtractThisEmbeddedResourceToAFile(string nameOfFile)

    { //we'll copy the file to the current directory while extracting it as an embedded resource.

    string pathToDestFile = System.Environment.CurrentDirectory + "\\" + nameOfFile;

    System.IO.FileInfo fi = new System.IO.FileInfo(pathToDestFile);

    if (fi.Exists) fi.Delete();

    System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

    foreach (string str in asm.GetManifestResourceNames())

    if (str.ToLower().IndexOf(nameOfFile.ToLower()) > -1) nameOfFile = str;

    System.IO.Stream fsIn = asm.GetManifestResourceStream(nameOfFile);

    byte[] bytesRead = new byte[fsIn.Length];

    fsIn.Read(bytesRead, 0, bytesRead.Length);

    System.IO.FileStream fsOut = new System.IO.FileStream(pathToDestFile, System.IO.FileMode.Create);

    fsOut.Write(bytesRead, 0, bytesRead.Length);

    fsOut.Close();

    return pathToDestFile;

    }

    In vb.net use something like this:

    Private Sub subExtractThisEmbeddedResourceToAFile(ByVal nameOfFile As String, ByVal pathToDestFile As String)

    Dim fi As New System.IO.FileInfo(pathToDestFile)

    If (fi.Exists) Then fi.Delete()

    Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()

    Dim fullNameOfFile As String = String.Empty

    For Each str As String In asm.GetManifestResourceNames()

    If str.ToLower().IndexOf(nameOfFile.ToLower()) > -1 Then fullNameOfFile = str

    Next

    Dim fsIN As System.IO.Stream = asm.GetManifestResourceStream(fullNameOfFile)

    Dim bytesRead(fsIN.Length = 1) As Byte

    fsIN.Read(bytesRead, 0, bytesRead.Length)

    Dim fsout As New System.IO.FileStream(pathToDestFile, System.IO.FileMode.Create)

    fsout.Write(bytesRead, 0, bytesRead.Length)

    fsout.Close()

    End Sub

     

    And then you just call the first function like this:

    button1.Image = funcGetImageFromEmbeddedResource("MyImage.jpg" ,32, 32)

    I also noticed that when I tried replacing the ICON code with the Image.FromFile code, I got a fuzzier image..

     

    Wednesday, April 16, 2008 6:28 AM
  • jal2, thanks for the lengthy post :)

    Thing is, I can get a resource to file in four lines of code without having to open a stream reader and stream writer and read in bytes.

    Lets say I got a sample.ico file embedded. To copy it to disk in the application's folder with a name test.ico I could use...

    VB.Net:

    Dim obj As Object = My.Resources.sample
    Dim fout As System.IO.Stream = System.IO.Create("test.ico")
    obj.Save(fout)
    fout.Close()

    C#.Net:

    Object obj = Global::MyApp.Properties.Resources.sample;
    System.IO.Stream fout = System.IO.Create("test.ico");
    obj.Save(fout);
    fout.Close();

    First line gets the resource we want to use
    Second line creates the stream specifying the name and path to the file to create on disk
    Third line uses .Save() to have .net take care of saving the data of the resource to the file stream for us
    Fourth line closes the stream and saves the file to disk

    Friday, September 11, 2009 11:58 PM
  • Something I came across - enjoy.
    System . IO . File . WriteAllBytes ( "FILE.DLL" , My . Resources . FILE )
    Wednesday, November 11, 2009 5:36 PM
  • Mike's solution works a treat if you want to put other exes in your main exe and extract them to disk later. My .save post only works on images.
    Thursday, February 25, 2010 5:30 AM