Exception thrown on bitmap declaration under weird circumstances - vb.net

I encountered this problem and through much frustration isolated it to this.
When I drag a file on my exe from another folder, a bitmap declaration that has nothing to with the command line arguments throws an exception "System.ArgumentException: Parameter is not valid".
This does not happen when:
The file is dragged from the same folder as exe
The file is dragged on a shortcut of the exe
Here is the minimum code that produces this error:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
Dim logo As New Bitmap("logo.png") 'an image in the same dir as exe
Me.BackgroundImage = logo
Catch ex As Exception
MessageBox.Show("Exception: " & ex.Message)
End Try
End Sub
End Class

If you provide just a file name then it is assumed that that file resides in the current directory. The current directory is not always the same at startup and it can change while an application is running too.
I'm guessing that that file is in the same folder as your EXE. In that case, when the code works the current directory must be the application folder and in cases where it fails the current directory must be some other folder.
We often see similar issues when Process.Start is used run a game. Many games do as you have and assume that the current directory is the application folder. If you run the game from the commandline or the like then it will be. If you use Process.Start to run the game from code, the new process will actually inherit the current directory of your application and that sort of code will fail.
The solution is to ALWAYS be explicit about the path of a file. If you want to open a file that is in your application folder then specify exactly that:
Dim logo As New Bitmap(IO.Path.Combine(Application.StartupPath, "logo.png"))
That code doesn't rely on the current directory being a specific folder so will be unaffected if it isn't.

Related

Delete relative path in Visual Basic

I'm essentially trying to figure out a simple method for deleting a relative path in vb. I want a user to be able to run the program and delete a specific folder within the AppData/Local folder on Windows. The purpose of the program is to remove Google Chrome user data when the user is finished with their session. I'm running in to trouble with:
My.Computer.FileSystem.DeleteDirectory
I'm trying to use this method to remove all folders within the \Google folder. The problem is, that since the \Google folder is relative, if anybody besides me tries to use it, it simply wont work since I would use: My.Computer.FileSystem.DeleteDirectory("C:\Users\Erik\AppData\Local\Google", FileIO.DeleteDirectoryOption.DeleteAllContents). How can I modify this program to remove the \Google folder under whichever user profile the program happens to be executed under?
You can do this with the Environent Paths:
Imports System.IO
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Directory.Delete(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\Google")
End Sub
End Class
This gets the Local Appdata Path for the current User.

My.Application.MainWindow is Nothing

After moving MainWindow.xaml in VB project using the Visual Studio into project folder Windows\MainWindow.xaml I've got some trouble (broken references etc.). I needed to re-create MainWindow.xaml to get them resolved (it was longer time ago, I don't remember exactly).
Currently, variable My.Application.MainWindow contains Nothing during runtime.
I've compared the project against blank project where My.Application.MainWindow contains correct reference during the runtime and found no place in original project where setting of My.Application.MainWindow is omitted (or something similar).
Do you have any experience on which place My.Application.MainWindow is being initialized in VisualStudio 2012 project?
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As StartupEventArgs) Handles Me.Startup
'next line throws NullReferenceException
Debug.Print("My.Application.MainWindow.Name = " & My.Application.MainWindow.Name)
'some other code here...
End Sub
OK, it seems that My.Application.MainWindow points to main window object only if main window is open. It is Nothing otherwise. So I had two issues:
In one of paths of my original code, I was accidentally closing main window, so My.Application.MainWindow became Nothing after calling Close()
In code shown in the question, it was too early to check for My.Application.MainWindow value – it was Nothing because the main window was not opened yet

Linking to internal html pages with LinkLabel

Visual Basic:
Trying to get my VB program to run an internal HTML file without it needing to navigate back the the C: drive.
Using:
Private Sub frmMalphite_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LinkLabel1.Links.Add(6, 4, "C:\Users\User\Desktop\Test\Test1\Test2.html")
End Sub
Private Sub LinkLabel1_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
System.Diagnostics.Process.Start(e.Link.LinkData.ToString())
End Sub
I can get the html page to run, however it would not work if I opened the project on another computer, because the absolute path given. Looking for a work around so I don't have to change the path on every computer I use to work on the project.
If the file exists on a drive on MachineA, then the only way you can open this from MachineB is to put the file on a shared drive and access the file via this share.
This will work from any machine that has permissions to read that share.
Something like:
LinkLabel1.Links.Add(6, 4, "\\MachineA\SharedDrive\Test2.html")
You may have access to the hidden administrative share on MachineA (\\MachineA\c$) from MachineB but you can't rely on it.

Error on Load Event when using My.Settings

I am currently having an issue with the usage of embedded settings in my application. I intend to use them with the form load/closing event, but I am recieving an error like this user:
Error when loading mySettings [Visual basics 2010]
I looked at my settings.vb file and everything appears to be in order, but I am not really sure what could have become incorrect/corrupt because it is all generated when I make changes to the project properties. In order to check if my usage of the settings was correct I created a new project with:
Private Sub Load()
Textbox1.Text = My.Settings.Test
End Sub
Private Sub Close()
My.Settings.Test = TextBox1.Text
End Sub
Everything is working perfectly in the new project, so the error is isolated to my particular project. Has anyone encountered this or have any ideas on how to remedy it?
Thanks for any help!
Exact Same Error from another user:
For those people googling this in the future here is the solution in my case:
Click View Detail and continue navigation through the error detail until you find the path to the app.config file. Once you find it move it to a backup location and run your app again. The file will be regenerated correctly.

How to embed dll from "class project" into my project in vb.net

I have a standard "class library" project with a set of classes that I use to import in almost all my new projects.
The way I work is creating a new Solution with an empty project, which is my main project, and then I add to the solution the mentioned class library project, this way I can see both projects in the Soluction Explorer and even see the library code or update it if needed. Then I write the code in my main project and I compile.
This lead me to have 2 files when I compile: file *.exe and stdlib.dll
Some cases I use the lib for very small tools that I want to redistribute in a easy and clean why, so I would like to embed the stdlib.dll generated from my class library project into my *.exe file.
I'm pretty sure there must be a why to do this in my Microsoft Visual Basic 2010 Express but I don't know how.
Any Suggestion?
Here is a more 'step-by-step' version of Alex's procedure to embedding the assembly.
Add the desired assembly (stdlib.dll) to the project's resources.
Go to the Resources tab of the Project Properties and choose Add Resource > Add Existing File...
Switch to the Application tab and click on the View Application Events button.
Add this code to the ApplicationEvents.vb code that opens.
Private Sub AppStart(ByVal sender As Object,
ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ResolveAssemblies
End Sub
Private Function ResolveAssemblies(sender As Object, e As System.ResolveEventArgs) As Reflection.Assembly
Dim desiredAssembly = New Reflection.AssemblyName(e.Name)
If desiredAssembly.Name = "the name of your assembly" Then
Return Reflection.Assembly.Load(My.Resources.STDLIB) 'replace with your assembly's resource name
Else
Return Nothing
End If
End Function
Now compile your project and you'll have the dependent assembly incorporated into the output as a single file.
Note that sometimes you may have the dependent assembly in the output folder. This is because VS is preconfigured to copy all dependent assemblies to the output path. You can override this by going to the References tab of the project's properties and then set the Copy Local property of the dependent assembly to False. This will stop the assembly from being copied to the output directory.
You can embedd your Assembly (.dll in your case) into your project by selecting "Add existing file" and then change the Build Option to "Embedded Ressource".
You then add a Handler for the AppDomain.CurrentDomain.AssemblyResolve event which gets fired as soon as you first access the library inside your code.
That handler code looks like this: (Notice the fully qualified assembly path inclusive correct namespacs. I'd wrap it in a function which gets called on startup of your application.
AddHandler AppDomain.CurrentDomain.AssemblyResolve,
Function(sender As Object, args As System.ResolveEventArgs) As System.Reflection.Assembly
Dim ressourceName = "YourNamespace.YourSubNamespace." + New AssemblyName(args.Name).Name + ".dll"
Using stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ressourceName)
Dim assemblyData(CInt(stream.Length)) As Byte
stream.Read(assemblyData, 0, assemblyData.Length)
Return Assembly.Load(assemblyData)
End Using
End Function
You can then deploy your tool without any additional files.