VB.NET variable initialization problem on Publish - vb.net

Is there any way to stop Visual Studio from removing variable initializations prior to publish?
I have a variable:
Dim myString as String: myString = Nothing
When I click publish, Visual Studio removes ": myString = Nothing"
and then during build it complains "myString is used before it is initialized". If I do a build (instead of publish) this doesn't happen.

This appears to be more a warning. It's perfectly legal to initialize a string using the colon separator, but likely it's being optimized out.
Your code:
Dim myString as String: myString = Nothing
is the equivalent of:
Dim myString as String = Nothing
which is the equivalent of:
Dim myString as String
as Strings default to Nothing by default, at least in the all the more recent versions of VB/ASP I can find
And as such will trigger that warning. whether or not it affects your output? that's on you :)

Related

why is a string variable strVar not the same as cStr(strVar)?

Why does a string variable need to be enclosed in a cStr() conversion to be used as a key string for the CreateObject("WScript.Shell").SpecialFolders collection?
Demonstration of this absurdity(?):
Sub sdfgdfsg()
Const strCon_SpecialFolderName As String = "MyDocuments"
Dim strVar_SpecialFolderName As String
strVar_SpecialFolderName = "MyDocuments"
Debug.Print CreateObject("WScript.Shell").SpecialFolders(strCon_SpecialFolderName) ' CORRECT
Debug.Print CreateObject("WScript.Shell").SpecialFolders(strVar_SpecialFolderName) ' WRONG! (it returns the Desktop path instead)
Debug.Print CreateObject("WScript.Shell").SpecialFolders(CStr(strVar_SpecialFolderName)) ' CORRECT
Debug.Print CreateObject("WScript.Shell").SpecialFolders("MyDocuments") ' CORRECT
End Sub
I read the documentation about the index argument for a collection without finding an answer.
The WScript library was designed to be used from scripting languages such as VBScript which use Variants. The SpecialFolders.Item that you are calling expects a Variant containing a string, too.
The result you are seeing appears to come from the fact that the library is not able to read the Variant-wrapped string value VB passes, and does something wrong instead. You can achieve the same result with
Dim strVar_SpecialFolderName As String
strVar_SpecialFolderName = vbNullString
'Returns C:\Users\Public\Desktop
Debug.Print CreateObject("WScript.Shell").SpecialFolders(strVar_SpecialFolderName)
For reasons I don't fully understand, there sometimes is a problem with passing Variant-wrapped data from VBA to an external object. I speculate that it may have something to do with the presence or absence of the VT_BYREF flag in the Variant that VB(A) produces, and it produces it differently for constants, local variables and temporaries.
I believe this to be a problem on the receiving side, not in VBA.
Workarounds include:
Declaring the variable as Variant to begin with:
Dim strVar_SpecialFolderName As Variant
strVar_SpecialFolderName = "MyDocuments"
Debug.Print CreateObject("WScript.Shell").SpecialFolders(strVar_SpecialFolderName)
Forcing an evaluation which turns the local variable into a temporary (that is what your CStr does, too) which apparently changes how VB packs it into a Variant:
Dim strVar_SpecialFolderName As String
strVar_SpecialFolderName = "MyDocuments"
Debug.Print CreateObject("WScript.Shell").SpecialFolders((strVar_SpecialFolderName))

Simple code that reads CSV values causes an error in System.IO.Directory

I can't seem to figure out why I'm getting a compilation error with this code that tries to find the most recently updated file (all CSV files) in a directory, to then pull the last line of the CSV and update a device.
The exception I get is:
Line 3 Character 10 expected end of statement.
Don't worry about the hs.SetDevice, I know that part is correct.
Imports System.IO
Sub Main()
Dim path = System.IO.DirectoryInfo.GetFiles("C:\Users\Ian\Documents\Wifi Sensor Software").OrderByDescending(Function(f) f.LastWriteTime).First()
Dim line = System.IO.File.ReadLines(path).Last()
Dim fields() = line.Split(",".ToCharArray())
Dim fileTemp = fields(2)
hs.SetDeviceValueByRef(124, fileTemp, True)
End Sub
EDIT:
Changed Directory to DirectoryInfo
The original problem was that Directory.GetFiles() returns an array of strings, a string doesn't have a LastWriteTime Property.
This property belongs to the FileInfo base class, FileSystemInfo, the object type returned by DirectoryInfo.GetFiles().
Then, a FileInfo object cannot be passed to File.ReadLines(), this method expects a string, so you need to pass [FileInfo].FullName.
Hard-coding a Path in that manner is not a good thing. Use Environment.GetFolderPath() to get the Path of special folders, as the MyDocuments folder, and Path.Combine() to build a valid path.
Better use the TextFieldParser class to parse a CSV file. It's very simple to use and safe enough.
The worst problem is Option Strict set to Off.
Turn it On in the Project's Properties (Project->Properties->Compile), or in the general options of Visual Studio (Tools->Options->Projects and Solutions->VB Defaults), so it's already set for new Projects.
You can also add it on top of a file, as shown here.
With Option Strict On, you are immediately informed when a mishap of this kind is found in your code, so you can fix it immediately.
With Option Strict Off, some issues that come up at run-time can be very hard to identify and fix. Setting it On to try and fix the problem later is almost useless, since all the mishaps will come up all at once and you'll have a gazillion of error notifications that will hide the issue at hand.
Option Strict On
Imports System.IO
Imports Microsoft.VisualBasic.FileIO
Dim filesPath = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "Wifi Sensor Software")
Dim mostRecentFile = New DirectoryInfo(filesPath).
GetFiles("*.csv").OrderByDescending(Function(f) f.LastWriteTime).First()
Using tfp As New TextFieldParser(mostRecentFile.FullName)
tfp.TextFieldType = FieldType.Delimited
tfp.SetDelimiters({","})
Dim fileTemp As String = String.Empty
Try
While Not tfp.EndOfData
fileTemp = tfp.ReadFields()(2)
End While
Catch fnfEx As FileNotFoundException
MessageBox.Show($"File not found: {fnfEx.Message}")
Catch exIDX As IndexOutOfRangeException
MessageBox.Show($"Invalid Data format: {exIDX.Message}")
Catch exIO As MalformedLineException
MessageBox.Show($"Invalid Data format at line {exIO.Message}")
End Try
If Not String.IsNullOrEmpty(fileTemp) Then
hs.SetDeviceValueByRef(124, fileTemp, True)
End If
End Using

Add a path to a code VB.net / visual basic

how do I add a path to a code where "HERE_HAS_TO_BE_A_PATH" is. When I do, Im getting an error message. The goal is to be able to specific the path where is the final text file saved.
Thanks!
Here is a code:
Dim newFile As IO.StreamWriter = IO.File.CreateText("HERE_HAS_TO_BE_A_PATH")
Dim fix As String
fix = My.Computer.FileSystem.ReadAllText("C:\test.txt")
fix = Replace(fix, ",", ".")
My.Computer.FileSystem.WriteAllText("C:\test.txt", fix, False)
Dim query = From data In IO.File.ReadAllLines("C:\test.txt")
Let name As String = data.Split(" ")(0)
Let x As Decimal = data.Split(" ")(1)
Let y As Decimal = data.Split(" ")(2)
Let z As Decimal = data.Split(" ")(3)
Select name & " " & x & "," & y & "," & z
For i As Integer = 0 To query.Count - 1
newFile.WriteLine(query(i))
Next
newFile.Close()
1) Use a literal string:
The easiest way is replacing "HERE_HAS_TO_BE_A_PATH" with the literal path to desired output target, so overwriting it with "C:\output.txt":
Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")
2) Check permissions and read/write file references are correct:
There's a few reasons why you might be having difficulties, if you're trying to read and write into the root C:\ directory you might be having permissions issues.
Also, go line by line to make sure that the input and output files are correct every time you are using one or the other.
3) Make sure the implicit path is correct for non-fully qualified paths:
Next, when you test run the program, it's not actually in the same folder as the project folder, in case you're using a relative path, it's in a subfolder "\bin\debug", so for a project named [ProjectName], it compiles into this folder by default:
C:\path\to\[ProjectName]\bin\Debug\Program.exe
In other words, if you are trying to type in a path name as a string to save the file to and you don't specify the full path name starting from the C:\ drive, like "output.txt" instead of "C:\output.txt", it's saving it here:
C:\path\to\[ProjectName]\bin\Debug\output.txt
To find out exactly what paths it's defaulting to, in .Net Framework you can check against these:
Application.ExecutablePath
Application.StartupPath
4) Get user input via SaveFileDialogue
In addition to a literal string ("C:\output.txt") if you want the user to provide input, since it looks like you're using .Net Framework (as opposed to .Net Core, etc.), the easiest way to set a file name to use in your program is using the built-in SaveFileDialogue object in System.Windows.Forms (like you see whenever you try to save a file with most programs), you can do so really quickly like so:
Dim SFD As New SaveFileDialog
SFD.Filter = "Text Files|*.txt"
SFD.ShowDialog()
' For reuse, storing file path to string
Dim myFilePath As String = SFD.FileName
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
5) Get user input via console
In case you ever want to get a path in .Net Core, i.e. with a console, the Main process by default accepts a String array called args(), here's a different version that lets the user add a path as the first parameter when running the program, or if one is not provided it asks the user for input:
Console.WriteLine("Hello World!")
Dim myFilePath = ""
If args.Length > 0 Then
myFilePath = args(0)
End If
If myFilePath = "" Then
Console.WriteLine("No file name provided, please input file name:")
While (myFilePath = "")
Console.Write("File and Path: ")
myFilePath = Console.ReadLine()
End While
End If
Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' path var
' Do the rest of your code here
newFile.Close()
6) Best practices: Close & Dispose vs. Using Blocks
In order to keep the code as similar to yours as possible, I tried to change only the pieces that needed changing. Vikyath Rao and Mary respectively pointed out a simplified way to declare it as well as a common best practice.
For more information, check out these helpful explanations:
Can any one explain why StreamWriter is an Unmanaged Resource. and
Should I call Close() or Dispose() for stream objects?
In summary, although streams are managed and should garbage collect automatically, due to working with the file system unmanaged resources get involved, which is the primary reason why it's a good idea to manually dispose of the object. Your ".close()" does this. Overrides for both the StreamReader and StreamWriter classes call the ".dispose()" method, however it is still common practice to use a Using .. End Using block to avoid "running with scissors" as Enigmativity puts it in his post, in other words it makes sure that you don't go off somewhere else in the program and forget to dispose of the open filestream.
Within your program, you could simply replace the "Dim newFile As IO.StreamWriter = IO.File.CreateText("C:\output.txt")" and "newFile.close()" lines with the opening and closing statements for the Using block while using the simplified syntax, like so:
'Dim newFile As IO.StreamWriter = IO.File.CreateText(myFilePath) ' old
Using newFile As New IO.StreamWriter(myFilePath) ' new
Dim fix As String = "Text from somewhere!"
newFile.WriteLine(fix)
' other similar operations here
End Using ' new -- ensures disposal
'newFile.Close() ' old
You can write that in this way. The stream writer automatically creates the file.
Dim newFile As New StreamWriter(HERE_HAS_TO_BE_A_PATH)
PS: I cannot mention all these in the comment section as I have reputations less than 50, so I wrote my answer. Please feel free to tell me if its wrong
regards,
vikyath

Keep My.Settings Always VB.Net

I have an application and I need to always have the my.settings saved. I notice that they get cleared whenever you change the files location, or run it on a different computer. Are there any ways to prevent this. It also happens when the application updates. Thanks.
Here is how you can retain your settings thru an upgrade:
(you also need to define a Project - Properties - Setting settings of 'ApplicationVersion' as string; you can start it off with an initial value of "not yet set")
Private Sub SetSettingsVersion()
Dim a As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
Dim appVersion As Version = a.GetName().Version
Dim appVersionString As String = appVersion.ToString
If My.Settings.ApplicationVersion <> appVersion.ToString Then
My.Settings.Upgrade()
My.Settings.ApplicationVersion = appVersionString
End If
End Sub

VB.NET: short cuts in code

Why is the following VB.NET code setting str to Nothing in my VS2005 IDE:
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
Button2.Enabled = True
TextBox1.Text = fname
End If
OpenFile is a Function that returns a FileStream
EDIT: If the above line containing Trim is not correct, is there a way to achieve the intended result in only one line?
The code is never setting str at all:
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
This line doesn’t set str, it compares it to the result of reading the file.
In VB, the = operator has two meanings, depending on context. If used in a statement, it assigns the right-hand expression to the left-hand expression. If used in any other context (i.e. in an expression), it performs an equality comparison, not an assignment.
Thus, in VB you must write the following:
str = New StreamReader(OpenFile()).ReadToEnd()
If str.Trim() <> "" Then …
Notice that I’ve replaced the free function Trim by a method call to make the code more consistent with common .NET coding practices.
The first thing to do when starting any VB.Net project is to make sure that Option Explicit and Option Strict are both set to true in the project settings. Only ever disable either of them if you have a specific reason (you need late binding or are taking over some old horrible code).
This would have stopped that code from even compiling and would have shown you the error right away.
Because you're not setting str, you're comparing it, then trimming the result of the comparison (basically trimming either "True" or "False"
If Trim(str = New StreamReader(OpenFile).ReadToEnd) <> "" Then
This doesn't actually set str, this breaks down to the following code
Dim str as string ' Defaults to nothing/""
Dim boolValue as bool = (str = New StreamReader(OpenFile).ReadToEnd)
If Trim(boolValue) <> "" Then
' This is always true, as "True" and "False" will never = ""'
...
End If