RFID Programming With VB.NET | Part II - vb.net

This post is related to a post before this one :
RFID Programming With VB.NET
Thanks for the answer Mark, i already change those to integer (because it doesnt match when port as long but the dc_init as Integer) i decided to change everything with Integer. And it works.
Now, i'm having another problem.
After the dc_init works (after i change those datatype to integer) i'm having a problem when calling dc_cards function.
For further information about the dc_init function i also include the manual file (from the RFID starter pack)
Here is the things that you need to see :
Download
I'm sorry i can't explain more specific about this problem, because i can't post images and only 2 link that i can include. Maybe it would help by downloading those thing above. It includes my project in VB.NET, and the VB6 example program (it works and no bug at all), the dcrf32.dll file (copy them to system32 the driver for RFID).
I'm doing this in VB.NET according to VB6 sample program (from the starter pack), but it's kind of difficult since migrating VB6 to VB.NET.
i really strange with this code, i never learn it and i don't know what to do. Maybe Mark could help me further in my situation.
Thanks a lot.

The Declaration for the dc_card Function should be:
Declare Auto Function dc_card Lib "dcrf32.dll" (ByVal icdev As Integer, ByVal mode as Short, snr As Integer) As Short
You should be passing the icdev you got from the dc_init function, and the mode of 0, your information will be in the snr variable and the status will be in st.
st = dc_card(ByVal icdev, cardmode, snr)
in your declares:
Dim snr, tagtype as Integer
Dim cardmode as Short
...

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.

Issue on single computer only - Conversion from string to type 'Date' is not valid

I regret having to write such a vague question, but I'm not really sure what to try. I have general programming experience, but no access to the source code for this and not a lot of experience with VB/.NET
We have a custom (Read: Crappy) CRM software we use at work that was written ~2008 by someone who has long since left the company. It works on both Windows 7 and Windows 10 just fine for multiple users. I am trying help a user with an "Unexpected program error":
"frmMain - FillGridTable
Conversion from string "03/31/2016 15:23:22" to type 'Date' is not valid."
when I close the dialog box it just says "LoopX = 0"
I do not have access to the source code, and regardless, it works on every other computer.
Could this be some issue with some type of library on the computer? Is there any way to check versions between computers for .NET/Microsoft libraries?
Thanks for any ideas!
Chase Rocker helped me get here in the comment he left on the question.
The windows date/time format settings were displaying a date that wasn't in the correct format. Resolved this by changing it to the MM/dd/YYYY format the error was suggesting the program expected.
I'm glad to see that you solved the issue by changing the computer's regional settings, but to be honest this is probably overkill for what you're wanting to do. Instead, you could have used the DateTime.TryParseExact function.
Here is a quick example of utilizing the built-in method:
Dim conversion As DateTime
Dim input As String = "11/30/2017"
If DateTime.TryParseExact(input, "MM/dd/yyyy", New CultureInfo("en-US"), DateTimeStyles.None, conversion) Then
'Converted successfully
Else
'A true conversion error occured
End If
Fiddle: Live Demo

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

Equivalent of "Dim As String * 1" VB6 to VB.NET

I have some VB6 code that needs to be migrated to VB.NET, and I wanted to inquire about this line of code, and see if there is a way to implement it in .NET
Dim strChar1 As String * 1
Intellisense keeps telling me that an end of statement is expected.
That's known as a "fixed-length" string. There isn't an exact equivalent in VB.NET.
Edit: Well, OK, there's VBFixedStringAttribute, but I'm pretty sure that exists solely so that automated migration tools can more easily convert VB6 code to VB.NET for you, and it's not really the ".NET way" to do things. Also see the warnings in the article for details on why this still isn't exactly the same thing as a fixed-length string in VB6.
Generally, fixed-length strings are only used in VB6 if you are reading fixed-size records from a file or over the network (i.e. parsing headers in a protocol frame).
For example, you might have a file that contains a set of fixed-length records that all have the format (integer, 1-character-string, double), which you could represent in VB6 as a user-defined type:
Public Type Record
anInteger As Integer
aSingleCharacter As String * 1
aDouble As Double
End Type
This way, VB6 code that reads from the file containing records in this format can read each fixed-sized record stored in the file, and in particular, it will only read 1 byte for aSingleCharacter. Without the * 1, VB6 would have no idea how many characters to read from the file, since a String can normally have any number of characters.
In VB.NET, you can do one of the following, depending on your needs:
If the length matters (i.e. you need to read exactly one byte from some data source, for example) consider using an array instead, such as
Dim aSingleByteArray(1) As Byte
Alternatively, you could use one of the Stream classes. In particular, if you are reading data from a network socket or a file, consider using NetworkStream or FileStream, respectively. A Stream is meant for byte-for-byte access (i.e. raw binary access). StreamReader is a related class that simplifies reading data when it is text-based, so that might be good if you are reading a text file, for example. Otherwise (if dealing with binary data), stick with one of the Stream classes.
If the length doesn't matter, you could just use a "normal" String. That is to say:
Dim aNormalString As String
Which answer is "correct" really depends on why it was declared that way in the original VB6 code.
The fixed length strings has been deprecated in VB.NET because there are several better options.
Since your fixed length string is just one character long, you can use the Char type in this case, as Mark suggested.
Dim strChar1 As Char
Seeing as you're doing a VB6 migration, I'd definitely consider VBFixedStringAttribute as well as the other options listed by Mike Spross, but, in this case, because it is a single character, a Char may be an option in this case too.
As mentioned elsewhere VBFixedString is only acknowledged by the Get and Put VB I/O API. So the best solution (other than rewriting your code that references the "fixed length string") is to write your own equivalent of Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString. See this answer for more details.
VBFixedStringAttribute Class
<VBFixedString(1)> Dim strChar1 As String
ALthough this question was asked ages ago, VB.NET actually has a native fixed-length string -- <VbFixedArray(9)> Public fxdString As Char() 'declare 10-char fixed array. Doing this with scalars actually creates VB6-style Static Arrays.

Odd value returned by simple Fortran function

Just as a forward, I am a complete beginner when it comes to Fortran. I've spent quite awhile looking at the other questions on SO, but I couldn't identify a similar question to this, so please forgive me if my solution is either obvious, or already been answered :)
I'm attempting to learn how to correctly implement a self-written Fortran DLL in a VB.net application. I've been able to have VB recognize the DLL, and execute the function without any errors. The error comes rather as expected output compared to actual output.
My Fortran DLL function reads as follows:
function ex(i)
integer*4 i
ex=i+1
return
end
A very simple function that increments the passed parameter by one and returns the value. (I think). The VB Application has the following code.
<DllImport("ex.dll")> _
Public Shared Function ex(ByRef val As Integer) As Integer
End Function
Private Sub btn_Fortran_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Fortran.Click
Console.WriteLine(ex(1))
End Sub
So, I'm passing the ex function the integer value 1. So I would expect the value 2 to be written to the console. Instead, I get the value "1073741824" Not exactly equal. Any ideas where I'm obviously falling short?
Learning a language in a mixed language content is "a hard row to hoe". Note that value you obtained is 2**30.
In the fortran portion, you should also declare the return value of the function: "integer*4 function ex (i)" is the old fashioned way. You are probably getting ex as a real through implicit typing. It is a very good idea to include "implicit none" in all of your programs and procedures to prevent implicit typing. Many compilers include an option for the same purpose.
Late edit:
Here is a program that demonstrates what was happening by showing what value is obtained when the bit-pattern real value 2.0 is interpreted as an integer. First the program equates a real and an integer. In this case the compiler "knows" about the types and converts the value. In the second case the raw bit pattern is transferred without being converted.
program test_tc
real :: my_real
integer :: my_int
my_real = 2.0
my_int = my_real
write (*, *) my_int
my_int = transfer ( my_real, my_int )
write (*, *) my_int
end program test_tc
Output is:
2
1073741824
It appears that I was nearly on the right track, but the way in which I declared 'i' made some weird things happen. When using the following convention of
integer*4 :: ex, i
The function returns the correct value. So, my function looks like this
function ex(i)
integer*4 :: ex, i
ex=i+1
return
end function
Thanks both of you for the help. I upvoted both of you for simply opening my eyes to some aspect of the language I didn't fully understand beforehand.