0

Title says it all, How do I save a file from the application resources to the desktop for example?

In the future it will create a directory and store it in there, essentially I'm making a game installer, but none of this matters right now.

I have tried about 6 different code methods and all of them failed, kept throwing errors about not being able to convert an icon/image to a 1-dimensional array. Or that "Icon" or "Image" is not a member of System.Drawing.Icon

Any help would be appreciated Thank you!

EDIT: Posting some code I've tried.

#1 ('Length' is not a member of System.Drawing.Icon)

Dim File01 As System.IO.FileStream = New System.IO.FileStream("C:\Users\" + Environment.UserName + "\Desktop\" + "EXAMPLE_Icon.ico", IO.FileMode.Create) File01.Write(My.Resources.EXAMPLE_Icon, 0, My.Resources.EXAMPLE_Icon.length) File01.Close()

#2 ('System.Drawing.Icon' cannot be converted to '1-dimensional array of Byte)

Dim filePath = Path.Combine("C:\Users\" + Environment.UserName + "\Desktop\", "EXAMPLE_Icon.ico") File.WriteAllBytes(filePath, My.Resources.EXAMPLE_Icon)

#3 ('RawFormat' is not a member of 'System.Drawing.Icon')

Dim filePath = Path.Combine("C:\Users\" + Environment.UserName + "\Desktop\", "EXAMPLE_Icon.ico") Using icon = My.Resources.EXAMPLE_Icon icon.Save("C:\Users\" + Environment.UserName + "\Desktop\", icon.RawFormat) End Using

  • You should post all 6 things youve tried and failed with. Even your failures are important clues to us to know how your mind is approaching (even if it isnlt uscceeding) at the problem, which in turn tells us how to teach you better. If we can correct the underlying misunderstandings then the knowledge has a better chance of sticking/we can better imagine ways to teach you effectively – Caius Jard Aug 03 '20 at 19:53
  • Yeah, I can understand that. I am a very tactile/kinesthetic learner. So I need hands on with working code to then pull it apart and understand how it works to then modify/manipulate it. I will look back through all my code and post what I have, I may have been exaggerating on the "6", but I'll post what I have. – SilverSlash Aug 03 '20 at 20:34
  • You just need `Dim ico = DirectCast(My.Resources.ResourceManager.GetObject("[Icon Name]"), Icon)`, then call `ico.Save()`, passing an open FileStream as argument. See whether this method is among those that don't work for you, then post the code you tried to make it work. – Jimi Aug 03 '20 at 20:36
  • Thank you, Caius & Jimi! I will try Jimi's provided examples and come back to check on the post. – SilverSlash Aug 03 '20 at 20:46
  • I have just tried the code examples that Jimi provided. I think I am misunderstanding how to implement the given code. – SilverSlash Aug 03 '20 at 21:31
  • Well done on ignoring pretty much everything I said [here](https://stackoverflow.com/questions/63225331/vb-net-2010-extracting-an-application-resource-to-the-desktop). One thing I said specifically was that you should try to find out how to save an `Icon` to a file and you've obviously made no effort at all. I just did a web search for *"vb.net save icon to file"* and the second match was the documentation for the `Icon.Save` method but you have made no attempt to use that, suggesting that you don't even know it exists. If you don't even do a web search then you haven't tried. – jmcilhinney Aug 04 '20 at 00:48
  • Pardon my effort to avoid blowing up your notifications. I'm not active on here enough to notice what you post the second you post it, and when I do have time, I'm looking for a quick fix that I can study/modify later. I did know that `Icon.Save` exists, and I have tried it. However, the instances that I have tried it were clearly wrong based on the amount of errors. I clearly misunderstood how to implement `Icon.Save` and failed to mention it. Happy? Good. – SilverSlash Aug 05 '20 at 03:03

1 Answers1

2
  • Build the destination path using Path.Combine() when the path is composited.

  • Many known System locations have a predefined value in Environment.SpecialFolder: in your case, Environment.SpecialFolder.Desktop. Environment.GetFolderPath() accepts one of these values and returns the correct file system path.
    This returns the Path of the Desktop folder for the current User:

    Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    
  • The Icon object has a Save() method that accepts a Stream as argument.
    You can pass a FileStream to save the Icon to a File, preserving its format, or a MemoryStream, then use File.WriteAllBytes() to save the MemoryStream's buffer calling its ToArray() method.

Using a Resource name, as a string, using ResourceManager.GetObject():

Dim iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "myIcon.ico")

Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None),
    ico = TryCast(My.Resources.ResourceManager.GetObject("myIcon"), Icon)
    ico?.Save(stream)
End Using

Or, depending on what fits better in the context of your operations:

Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None)
    My.Resources.myIcon.Save(stream)
End Using
GC.Collect()

Note: here, I'm calling GC.Collect() after calling Save() directly on the Icon object generated by My.Resources. The Docs don't exactly explain it: My.Resources is a factory, it doesn't return the object stored in the Project's Resources, it generates a new object (a different one each time) from the data stored as a Resource. With My.Resources.myIcon.Save(stream), we create a new object, save its data to disc, but never actually dispose of it. Calling GC.Collect() right after, the memory used is reclaimed immediately. If we don't, that memory is never reclaimed (we're leaking).

It's probably better to assign the generated object a to temporary variable declared with a Using statement. The two methods that follow can make use of GC.Collect(), calling it right after, to reclaim the allocated memory immediately, but it's not strictly required, we're not really leaking resources.
Open up Visual Studio's Diagnostic Tools to test the behavior with and without GC.Collect(), calling these methods multiple times.

Using stream As New FileStream(iconPath, FileMode.Create, FileAccess.Write, FileShare.None),
    ico = My.Resources.myIcon
    ico.Save(stream)
End Using
' GC.Collect()  <= Not strictly required, but test the difference

Or using a MemoryStream:

Using ms As New MemoryStream(),
    ico As Icon = My.Resources.myIcon
    ico.Save(ms)
    ms.Position = 0
    File.WriteAllBytes(iconPath, ms.ToArray())
End Using
' GC.Collect()  <= Not strictly required, but test the difference
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • I'm not sure that I'd advocate calling GC.Collect after saving a single icon, as it could lead the reader to believe it needs to be done every time (or worse, after every Using). In practical terms it should be seldom called, if ever, and not without the developer being fully aware of why they're doing it. "Someone on the Internet wrote it so I just pasted it in and I don't know why" wouldn't be a good enough reason for me – Caius Jard Aug 04 '20 at 06:12
  • @Caius Jard Not *after every `Using`*, the first method doesn't have it. But you're right, I'll add a couple of notes: it's interesting to test the difference with or without `GC.Collect()` in different conditions (I assume a Dev would put code under test to see what's what, but I may be wrong here :). – Jimi Aug 04 '20 at 11:03
  • Hah, yeah I live in hope that SO users think deeply about the answers they receive, retain a sense of ownership of their problem, work through minor typos, carefully test and *don't* just blindly paste the first thing that seems to work.. But the universe is ever willing to [remind me how wrong I am](https://www.theverge.com/tldr/2016/5/4/11593084/dont-get-busted-copying-code-from-stack-overflow) – Caius Jard Aug 04 '20 at 13:47