How can I get ISO-based language string from FileVersionInfo? - vb.net

I have a windows form in VB.net 2010 which needs to read remote .exe's language string.
Usually, this could be done via
oFileInfo = FileVersionInfo.GetVersionInfo("path to .exe here")
Dim sMyLanguage = oFileInfo.Language
Unfortunately, this will return something like "englisch", "französisch" on a German Windows which is absolutely useless for me.
The best would be an ISO-based code, like EN, DE, FR, etc. Another unique identifier like a codepage number or something similar would also be okay.
System.Globalization also doesn't seem to have kind of a mapping of language strings to something useful.
Any idea how to get such a language identification de-coupled from the language of my operating system? Currently, my idea is to use a .csv file with three gazillions of translations which doesn't sound to be appropriate.

Okay, I found a solution:
In System.Globalization, there is not quite a direct mapping, but as in https://msdn.microsoft.com/de-de/library/system.globalization.cultureinfo.lcid(v=vs.110).aspx there are just about 140 languages listed, so I made a .csv file with Culture ID and to returning string and looped thru it with a simple For loop.
For i = 1 To gsLanguages.Count - 1
Try
oLang = New System.Globalization.CultureInfo(CInt(gsLanguages(i).Split(";")(1)), True)
If oLang.DisplayName.ToLower.StartsWith(sLangString) Then
sLanguage = gsLanguages(i).Split(";")(0)
Exit For
End If
Catch ex As Exception
End Try
Next
No question, this may not be the best solution. But in my testing, it had a very high chance to hit, so this is good enough for me.

Related

Roslyn context.SemanticModel.GetDeclaredSymbol() returning NULL from InvocationExpression

Trying to develop an VS extension to help with migration from vb6 to Vb.net using Roslyn.
Unfortunately I am not having much luck with detecting the "DoEvents" expression in my source as I get NULL from my GetDeclaredSymbol during the detection.
My bad coding is......
Register the action:
context.RegisterSyntaxNodeAction(AddressOf ExpressionStatementDec, SyntaxKind.InvocationExpression)
Try and detect the "DoEvents" expression:
Private Sub ExpressionStatementDec(context As SyntaxNodeAnalysisContext)
Dim GotYou = context.SemanticModel.GetDeclaredSymbol(context.Node)
Dim WhatExpression = context.Node.ToFullString.ToString
' Find DoEvents.
If RemoveWhitespace(WhatExpression) = "DoEvents" Then
Dim diag = Diagnostic.Create(Rule, GotYou.Locations(0), GotYou.Name)
context.ReportDiagnostic(diag)
End If
End Sub
I have tried loads of options for trying to get the right type of object for "GotYou" but no luck so far.
Any pointers appreciated :)
Edit Additional info:
I have tried GetSymbolInfo but when I am detecting "DoEvents" in the context.Node.ToFullString.ToString I am still not getting anything in the context.SemanticModel.GetSymbolInfo(context.Node) as below.
Thanks,
Richard
If you want to look at what a invocation is referencing, call GetSymbolInfo not GetDeclaredSymbol.
Don’t have Visual Studio handy in order to get the code, but...
I believe what you want is something like:
Dim WhatExpression = TryCast(CType(context.Node, InvocationExpressionSyntax).Expression, IdentifierNameSyntax)?.Identifier.Text
This isn’t all of it, you could be dealing with a memberaccessexpression, in which case it’s probably not what you are looking for. The options would be a bit easier to handle with pattern matching in C#, but that’s the general idea. You don’t need the semantic tree at this point, because you first want to verify that you are dealing with the right text. Once you’ve got that, you can see where it comes from and whether it is something you need to deal with. Getting the semantic model is expensive, no reason to do so when (outside of your unit test) it is rarely going to be needed.

VB.Net: "Nice", maintainable way of matching integer error code to error strings for UI

I'm building a user interface (HMI, human-machine interface) for a machine that does various motion-controlled tasks. The motion controller is a bit on the primitive side in terms of programming, and so I have it sending me error and status codes in the form of integers.
As an example: I have a box that indicates what stage the machine is at during its autocycle. The machine sends a '1', and I want the box to say 'Waiting to start autocycle.' Here are a few more:
1 - Waiting to start autocycle.
2 - Returning to home.
3 - Waiting at home.
4 - Tracking encoder A.
5 - Tracking encoder B.
And so on. Is there a clean way to maintain these messages in VB.net using, say, resources, that I don't know about, or should I just make an XML file that just contains something like
<statusmessage code="1" message="Waiting to start autocycle.">
and read that in when the program starts?
My current method is a hard-coded select statement with the strings in the actual VB source so you have to recompile the program if you want to change a message (gross).
If it's relevant, this program is never going to be multi-language.
Thanks for any advice!
It's easy to do this with an .xml file. That or some similar file format would be my preference. Some people would prefer using app.config or file format. When I evaluate something like this, simplicity of maintenance is probably the highest priority, and there are several methods that would work equally well in this regard. A database table could be used, but it seems like an overcomplication.
If you don't need to worry about multiple languages, it is possible to do this...
Public Enum Foo
<Description("Waiting to start autocycle")> WaitingToStartAutoCycle = 1
<Description("Returning to home")> ReturningToHome = 2
' [ etc...]
End Enum
You can then use reflection to get the description. This is ripped out of a larger piece of code, so forgive me if I miss part of it..
Public Function GetEnumDescription(ByVal value As Object) As String
Dim type As Type = value.GetType()
' Excersize for the reader, validate that type is actually an Enum
Dim f As FieldInfo = type.GetField(value.ToString)
If f IsNot Nothing Then
Dim ca() As Object = f.GetCustomAttributes(GetType(DescriptionAttribute), False)
If ca IsNot Nothing AndAlso ca.Length > 0 Then
Return CType(ca(0), DescriptionAttribute).Description
End If
End If
Return value.ToString ' Last resort if no Description attribute
End Function

Ascw returns "Cannot convert to 'Integer'." in Watch or Immediate

I have following sample code
Dim q As Char = "a"
Dim res As String = CStr(AscW(q))
res contains correctly "97" but when I use AscW(q) in watch or immediate it returns message: Cannot convert to 'Integer'.
Is it a bug or Visual Studio or am I doing something not correctly?
How can I see a character code in Immediate.
Note
The code presented is just an example. I found the problem when trying to see Character code in the Watch Window.
For a workaround, how about the command
? System.Text.Encoding.Unicode.GetBytes(q)
I personally believe that any acceptable VB.Net code should be acceptable in the Immediate window and really don't understand why AscW is causing errors when VB.Net offers no equivalent (e.g. in C#, but not VB.Net, you can cast a Char variable to an Integer to get the character code).
You are doing everything right (and the outputs will be OK in any case), although you are using old VB code. If you need functionalities like AscW (, Asc, ChrW, etc.), you would have to rely on this "old code" to get what you want (directly or via Microsoft.VisualBasic.Strings which, btw, does not show a different behaviour). But, in any other case, you should avoid the utilisation of this old code.
Test these two lines in the Immediate Window:
Dim res As String = CStr(5)
res = 5.ToString()
As you can see, you get an "error" (VS 2010, right-click on the line and select "QuickWatch") in the first line (old version), but not in the second one (.NET version).
Thus, the behaviour you observed can be considered as an inoffensive bug (no real effects in the execution) more or less understandable if you analyse the situation (you are asking a certain language (VB.NET) to support all its own features and the ones from an old language (VB); with the old one, some secondary functionalities might not be perfect).

VB.NET "Fixing" Code Clone

I'm working on refactoring a decently large project, and I'm interested in searching out and reducing Code Clone for better standardization as well as ease of development.
I've got a code snippet that keeps coming up in "Exact Matches" (using Visual Studio 2012's
"Find Code Clones" feature).
Here it is:
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
Basically, I have a whole host of similar functions (similar in structure but not in actual function) that all open with something like this:
Const sql As String = ...
Using cn As SqlConnection...
Using cmd As SqlCommand(sql,cn)
... Maybe add some SqlParameters
cn.Open()
... Something with cmd.Execute...
Now, I recognize that the first code block is IDENTICAL across many, many methods, but I can't figure out a way to pull that code out, write it once and simply call it each time I need that functionality. It seems to me that there is too much control flow occurring.
So, I'm stumped as to how to fix this (and I'm only assuming that I can "fix" this because Microsoft has identified it as "cloned code").
I'm thinking of something along the lines of making a small number of functions that do the same type of thing (like returning a count from a table, returning a top value, etc...) and only really differ by the SQL that is executed. That could be a bit tricky, though, since sometimes the parameters (type and number) differ.
Any thoughts?
I wouldn't concern yourself with those. Your common-sense first impression is correct. While, technically speaking, the syntax is repeated multiple times, it is not really a repetition of logic or an algorithm of any kind. That's not to say there's no way to reduce that repetition, it's just that by doing so, you will likely end up with a worse design in your code.
For instance, you could create a single method that does all the setup and tear-down and then just calls a method in the middle that actually uses the connection to do the work, such as:
Public Function PerformDbTask(task As IMyDbTask)
Using cn As SqlConnection...
Using cmd As SqlCommand = cn.CreateCommand()
Try
cn.Open()
task.Perform(cmd)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Using
End Using
Return Nothing
End Function
However, what have you really gained? Probably not much at all, yet you've lost a lot of flexibility. So, unless that kind of design is actually necessary for what you are trying to do, I wouldn't waste time trying to solve a problem that doesn't exist.
You could create a class that implements a builder pattern, that winds up looking like
Dim list =
SqlBuilder.Query("SELECT ...")
.WithConnection("...connection string...")
.WithParameter(userName)
.WithParameter(lastTrackId)
.RetrieveTopRows(10)
Your problem is you are using a clone detector that matches token sequences (thus it matches the end-of-block sequences you exhibited), as opposed to clone detectors that match code structures. While the token sequence is technically a clone, it isn't an interesting clone. Token clone detectors produce many many "false positive" clones like this, which simply waste your time.
It is easier to build token sequence detectors, which is why they built that into MS Studio.
If you want better detectors, you have to step outside of Studio.
You should look into clone detectors that match on abstract syntax trees. They don't produce this kind of false positive, and they can find clones with complex parameters (as opposed to single-token parameters).
You should also understand that just because something has been identified as a clone, that it is not always easy or possible to refactor it away. The language you have may not have sufficiently strong abstraction mechanisms to handle that case.

Validating e-mail with regular expression VB.Net

I'm working on a small project in VB.Net where I get a input from a textbox, and need to verify that this is an e-email address.
I found this expression "^[_a-z0-9-]+(.[_a-z0-9-]+)#[a-z0-9-]+(.[a-z0-9-]+)(.[a-z]{2,4})$", but i cant find any way to test if it passes.
I want some code like:
if not txtEmail.text = regexString then
something happens..
else
something else happens..
end if
Use the System.Text.RegularExpressions.Regex class:
Function IsEmail(Byval email as string) as boolean
Static emailExpression As New Regex("^[_a-z0-9-]+(.[a-z0-9-]+)#[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$")
return emailExpression.IsMatch(email)
End Function
The most important thing to understand about this answer is that I didn't write the regular expression myself. There are just so many wrong ways that seem to be right, and there are several levels of detail that you could take this to. For example, do you want to restrict this to valid top level domains, and if so, how are you accounting for the fact that they are now occasionally adding new TLDs? If the regular expression the most appropriate place for that test, or should have separate code for that check? Even the expression in this answer is now very stale since it was originally authored.
I recommend finding an outside resource for the expression you know will be maintained over time.
Pick your favorite regex from my article on matching email addresses with a regex, and plug it into this Visual Basic code:
If Regex.IsMatch(SubjectString, "regex") Then
Error = False
Else
Error = True
End If
The best regex to match an email address is a controversial topic that I don't want to get into here. My article discusses the issues that you should be aware of when picking a regex. The regex in Joel Coehoorn's answer is definitely not a good one.
There is a great website for this kind of thing, http://regexlib.com/. Not only does it have a tester application where you can paste in a regular expression and test it, but there is also a library of regular expressions you can use with community feedback on their validity, etc. I'm not a regex guru, so I go here when I need a quick regular expression.
Also, if you are thinking of developing regular expressions yourself, there is an excellent tool called Regex Buddy that will allow you to create and test your regular expressions on the fly using an easy to understand English interpretation of your regex.
Possibly off-topic since it's not a regex solution, but you could just use some of the built in features of .NET 2.0:
try
{
MailAddress email = new MailAddress(txtEmail.Text);
}
catch(FormatException fe)
{
// output error
}
That regex isn't really complete... in fact... most aren't (check out this article, or this one).
Unless you really enjoy pain, regex isn't the right way to validate an email address.
Email address: RFC 2822 (simplified)
Matches a normal email address. Does not check the top-level domain.
Requires the "case insensitive" option to be ON.
Dim FoundMatch As Boolean
Try
FoundMatch = Regex.IsMatch(txtEmail.text, "\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", RegexOptions.IgnoreCase)
Catch ex As ArgumentException
'Syntax error in the regular expression
End Try
If Not FoundMatch Then
Error = True
Else
Error = False
End If